from browser import document, html, alert, window from typing import Any from lib_language import interpreter from lib_robo import Robo, ProgramEnded from lib_field import HTMLField import lib log = lib.Log('info') class DrawCells: """Рисует ячейки выбранного типа на поле.""" cell_type: str field: HTMLField def __init__(self, field_obj: HTMLField) -> None: """ :param field_obj: Объект -- поле. """ self.field = field_obj self.select('wall') def select(self, cell_type: str) -> None: """ Запоминает выбранный для рисования тип ячейки. :param cell_type: тип ячейки (empty, wall, red, green). """ self.cell_type = cell_type for cell_type in ['empty', 'wall', 'red', 'green']: document[f'draw_{cell_type}'].text = '' document[f'draw_{self.cell_type}'].text = '✓' def draw(self, cell_id: str) -> None: """ Рисует ячейку выбранным типом. :param cell_id: ID ячейки. """ col, row = self.field.to_coords(cell_id) { 'empty': self.field.remove_wall_or_tile, 'wall': self.field.build_wall, 'red': self.field.put_red_tile, 'green': self.field.put_green_tile, }[self.cell_type](col, row) class State: """Переключает состояние страницы.""" name: str _timer: Any def __init__(self) -> None: self._timer = None self.edit() def edit(self) -> None: """Включает состояние редактирования.""" document['reset_exec'].disabled = True document['stop_exec'].disabled = True document['exec_cmd'].disabled = False document['run_prg'].disabled = False document['add_col'].disabled = False document['add_row'].disabled = False document['rm_col'].disabled = False document['rm_row'].disabled = False document['source_code'].disabled = False self.name = 'edit' def pause(self) -> None: """Включает состояние паузы выполнения.""" if self.name == 'edit': try: robo.load_program( interpreter(document['source_code'].value) ) except Exception as err: alert(str(err)) return if self.name != 'pause': document['reset_exec'].disabled = False document['stop_exec'].disabled = True document['exec_cmd'].disabled = False document['run_prg'].disabled = False document['add_col'].disabled = True document['add_row'].disabled = True document['rm_col'].disabled = True document['rm_row'].disabled = True document['source_code'].disabled = True if self._timer: window.clearTimeout(self._timer) self.name = 'pause' def run(self) -> None: """Включает состояние выполнения программы.""" if self.name == 'edit': try: robo.load_program( interpreter(document['source_code'].value) ) except Exception as err: alert(str(err)) return if self.name != 'run': document['reset_exec'].disabled = True document['stop_exec'].disabled = False document['exec_cmd'].disabled = True document['run_prg'].disabled = True document['add_col'].disabled = True document['add_row'].disabled = True document['rm_col'].disabled = True document['rm_row'].disabled = True document['source_code'].disabled = True self.name = 'run' self._timer = window.setInterval(program_step, 100) def program_step(): try: robo.cpu_tact() except ProgramEnded: if state.name == 'pause': alert('Программа закончена.') else: state.pause() except Exception as err: alert(str(err)) state.pause() # ########################################################################### # # ## Функции обработки кликов. ## # # ########################################################################### # def open_doc_window(_) -> None: """Открывает/закрывает окно с документацией.""" document['doc_window'].hidden = not document['doc_window'].hidden def close_doc_window(_) -> None: """Закрывает окно с документацией.""" document['doc_window'].hidden = True def resize_field(event) -> None: """Клик по кнопкам изменения размера поля.""" { 'rm_col': field.rm_col, 'add_col': field.add_col, 'rm_row': field.rm_row, 'add_row': field.add_row, }[event.target.id]() document['rows'].text = field.rows document['cols'].text = field.cols field.save_state() def select_to_draw(event) -> None: """Клик на выборе вида ячейки для рисования.""" draw_cells.select(event.target.id[len('draw_'):]) def click_field_cell(event) -> None: """Клик по ячейке поля.""" draw_cells.draw(event.target.id) if state.name == 'edit': field.save_state() def reset_execution(_): """Клик по кнопке сброса выполнения программы.""" state.edit() field.draw() robo.cpu_reset() def stop_execution(_): """Клик по кнопке остановки исполнения программы (паузы).""" state.pause() def execute_cmd(_): """Клик по кнопке исполнения следующей команды.""" state.pause() program_step() def run_program(_): """Клик по кнопке запуска программы.""" state.run() # ########################################################################### # # ## Хуки на клики. ## # # ########################################################################### # # Кнопки документации. document['open_doc'].bind('click', open_doc_window) document['close_doc'].bind('click', close_doc_window) # Кнопки изменения размера поля. document['rm_col'].bind('click', resize_field) document['add_col'].bind('click', resize_field) document['rm_row'].bind('click', resize_field) document['add_row'].bind('click', resize_field) # Кнопки выбора рисуемых ячеек. document['draw_empty'].bind('click', select_to_draw) document['draw_wall'].bind('click', select_to_draw) document['draw_red'].bind('click', select_to_draw) document['draw_green'].bind('click', select_to_draw) # Кнопки управления выполнением программы. document['reset_exec'].bind('click', reset_execution) document['stop_exec'].bind('click', stop_execution) document['exec_cmd'].bind('click', execute_cmd) document['run_prg'].bind('click', run_program) # ########################################################################### # # ## Основной код. ## # # ########################################################################### # field = HTMLField(container=document['field_container']) field.use_click_handler(click_field_cell) draw_cells = DrawCells(field) state = State() robo = Robo(field) field.draw()