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()