diff --git "a/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Readme.md" "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Readme.md" new file mode 100644 index 0000000..fadedbd --- /dev/null +++ "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Readme.md" @@ -0,0 +1,25 @@ +# Робот-Программист + +## Описание: +Робот-Программист выполняет задачи в контексте 'Серверов'. +Координатная система: ось Y направлена вверх (на север), ось X направлена вправо (на восток). Начало координат — в нижней левой ячейке. + +--- + +### Методы специализации и их действие: +- Код: заменяет Код -> Развернуто +- Терминал: заменяет Терминал -> Код + +--- + +### Цель: +- После завершения работы не должно остаться ячеек следующих типов: + - Код + - Терминал +- Программа должна завершиться на ячейке типа Финиш + +--- + +### Ограничения перемещения: +- нельзя заходить на ячейки типа Сервер +- нельзя заходить на ячейки типа Баг diff --git "a/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Video.mp4" "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Video.mp4" new file mode 100644 index 0000000..e6685df Binary files /dev/null and "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/Video.mp4" differ diff --git "a/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main1.py" "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main1.py" new file mode 100644 index 0000000..3b9549c --- /dev/null +++ "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main1.py" @@ -0,0 +1,560 @@ +import enum +import tkinter as tk +from tkinter import messagebox, scrolledtext +from typing import Iterator, Optional, List +import time + + +class ТипНаправленийDevOpsНапр(enum.Enum): + ДеплойВперёд = "ДеплойВперёд" + ОткатНазад = "ОткатНазад" + ВлевоСеть = "ВлевоСеть" + ВправоСеть = "ВправоСеть" + ДиагDevСЗ = "ДиагDevСЗ" + ДиагDevЮВ = "ДиагDevЮВ" + + +class ТипЯчеекСерверов(enum.IntEnum): + Сервер = 0 + Терминал = 1 + Развернуто = 2 + Код = 3 + Баг = 4 + Финиш = 5 + Сеть = 6 + + +class ЯчейкаРоботПрограммист: + def копия(self): + return ЯчейкаРоботПрограммист( + self.ячейка_робота, + self.тип_ячейки + ) + def __init__(self, ячейка_робота: bool, тип_ячейки: ТипЯчеекСерверов): + self.ячейка_робота = ячейка_робота + self.тип_ячейки = тип_ячейки + + def получить_значение(self) -> int: + значение = int(self.тип_ячейки) + if self.ячейка_робота: + значение |= 0x8 + return значение + + def __repr__(self) -> str: + return f"Ячейка(робот={self.ячейка_робота}, тип=0x{self.получить_значение():X})" + + def __eq__(self, other): + if not isinstance(other, ЯчейкаРоботПрограммист): + return False + return (self.ячейка_робота == other.ячейка_робота and + self.тип_ячейки == other.тип_ячейки) + + +class ЛабиринтРоботПрограммист: + def __init__(self, ширина: int, длина: int): + self.ширина = ширина + self.длина = длина + self.ячейки: List[List[ЯчейкаРоботПрограммист]] = [] + + def ИнициализироватьЛабиринт(self, тип_ячейки: ТипЯчеекСерверов): + self.ячейки = [] + for y in range(self.длина): + row = [] + for x in range(self.ширина): + row.append(ЯчейкаРоботПрограммист(False, тип_ячейки)) + self.ячейки.append(row) + + def ПолучитьСоседнююЯчейку(self, текущая_ячейка: ЯчейкаРоботПрограммист, + направление_поиска: ТипНаправленийDevOpsНапр) -> Optional[ЯчейкаРоботПрограммист]: + current_x = current_y = -1 + for y in range(self.длина): + for x in range(self.ширина): + if self.ячейки[y][x] is текущая_ячейка: + current_x, current_y = x, y + break + if current_x != -1: + break + + if current_x == -1 or current_y == -1: + return None + + if направление_поиска == ТипНаправленийDevOpsНапр.ДеплойВперёд: + dx, dy = (0, 1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ОткатНазад: + dx, dy = (0, -1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ВлевоСеть: + dx, dy = (-1, 0) + elif направление_поиска == ТипНаправленийDevOpsНапр.ВправоСеть: + dx, dy = (1, 0) + elif направление_поиска == ТипНаправленийDevOpsНапр.ДиагDevСЗ: + dx, dy = (-1, 1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ДиагDevЮВ: + dx, dy = (1, -1) + else: + return None + + new_x, new_y = current_x + dx, current_y + dy + + if not (0 <= new_x < self.ширина and 0 <= new_y < self.длина): + return None + + новая_ячейка = self.ячейки[new_y][new_x] + + if новая_ячейка.тип_ячейки in (ТипЯчеекСерверов.Сервер, ТипЯчеекСерверов.Баг): + return None + + return новая_ячейка + + def ПолучитьИтератор(self) -> Iterator[ЯчейкаРоботПрограммист]: + if not self.ячейки or self.длина == 0 or self.ширина == 0: + return + + x, y = 0, self.длина - 1 + direction = 1 + + while y >= 0: + yield self.ячейки[y][x] + + if direction == 1: + if x + 1 < self.ширина: + x += 1 + else: + y -= 1 + if y >= 0: + direction = -1 + else: + if x - 1 >= 0: + x -= 1 + else: + y -= 1 + if y >= 0: + direction = 1 + + +class РоботПрограммист: + def __init__(self, лабиринт: ЛабиринтРоботПрограммист): + self.лабиринт = лабиринт + self.деплоэнергия: Optional[ЯчейкаРоботПрограммист] = None + self.откатный: Optional[ЯчейкаРоботПрограммист] = None + + # Находим ячейку с роботом + self.текущая_ячейка = None + for y in range(self.лабиринт.длина): + for x in range(self.лабиринт.ширина): + if self.лабиринт.ячейки[y][x].ячейка_робота: + self.текущая_ячейка = self.лабиринт.ячейки[y][x] + return + + def Деплойнуть(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ДеплойВперёд) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def Откатнуть(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ОткатНазад) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def СдвинутьВлево(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ВлевоСеть) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def СдвинутьВправо(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ВправоСеть) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def ПоднятьКонтейнер(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ДиагDevСЗ) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def ОпуститьКонтейнер(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + старая_ячейка = self.текущая_ячейка + новая_ячейка = self.лабиринт.ПолучитьСоседнююЯчейку( + старая_ячейка, ТипНаправленийDevOpsНапр.ДиагDevЮВ) + + старая_ячейка_до = старая_ячейка.копия() + + if новая_ячейка: + старая_ячейка.ячейка_робота = False + новая_ячейка.ячейка_робота = True + self.текущая_ячейка = новая_ячейка + + return старая_ячейка_до + + def Код(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + до = self.текущая_ячейка.копия() + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Код: + self.текущая_ячейка.тип_ячейки = ТипЯчеекСерверов.Развернуто + + return до + + def Терминал(self) -> Optional[ЯчейкаРоботПрограммист]: + if self.текущая_ячейка is None: + return None + + до = self.текущая_ячейка.копия() + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Терминал: + self.текущая_ячейка.тип_ячейки = ТипЯчеекСерверов.Код + + return до + + +class DevOpsApp: + def __init__(self, root, width=5, height=6): + self.root = root + self.root.title("Робот-Программист") + + self.lab = ЛабиринтРоботПрограммист(width, height) + self.lab.ИнициализироватьЛабиринт(ТипЯчеекСерверов.Сервер) + + self._setup_demo_map() + self.robot = РоботПрограммист(self.lab) + + self.cell_size = 60 + self.canvas = tk.Canvas( + root, + width=width * self.cell_size, + height=height * self.cell_size, + bg="white" + ) + self.canvas.pack(side=tk.LEFT, padx=10, pady=10) + + panel = tk.Frame(root) + panel.pack(side=tk.RIGHT, fill=tk.Y) + + self.log = scrolledtext.ScrolledText( + panel, + width=30, + height=12, + state="disabled" + ) + self.log.pack(fill=tk.BOTH, pady=(0, 10)) + + self.auto_running = False + + style = {'bg': '#F0F0F0', 'activebackground': '#E0E0E0', 'relief': 'flat'} + + tk.Button( + panel, + text="Авто", + bg="#C9E2CD", + command=self.toggle_auto + ).pack(fill=tk.X, pady=10) + + tk.Button(panel, text="Деплой", + command=lambda: self.step(self.robot.Деплойнуть)).pack(fill=tk.X) + + tk.Button(panel, text="Откат", + command=lambda: self.step(self.robot.Откатнуть)).pack(fill=tk.X) + + tk.Button(panel, text="Влево", + command=lambda: self.step(self.robot.СдвинутьВлево)).pack(fill=tk.X) + + tk.Button(panel, text="Вправо", + command=lambda: self.step(self.robot.СдвинутьВправо)).pack(fill=tk.X) + + tk.Button(panel, text="Поднять", + command=lambda: self.step(self.robot.ПоднятьКонтейнер)).pack(fill=tk.X) + + tk.Button(panel, text="Опустить", + command=lambda: self.step(self.robot.ОпуститьКонтейнер)).pack(fill=tk.X) + + tk.Button(panel, text="Код", bg="#F6D6A1", + command=lambda: self.step(self.robot.Код)).pack(fill=tk.X, pady=(10, 0)) + + tk.Button(panel, text="Терминал", bg="#D4DDF1", + command=lambda: self.step(self.robot.Терминал)).pack(fill=tk.X) + + + self.iterator = self.lab.ПолучитьИтератор() + self.draw() + + def toggle_auto(self): + self.auto_running = not self.auto_running + if self.auto_running: + self.write_log("Авто-режим запущен") + self.auto_step_loop() + else: + self.write_log("Авто-режим остановлен") + + def auto_step_loop(self): + if not self.auto_running: + return + + cur = self.robot.текущая_ячейка + + if self.handle_cell_action(): + self.draw() + self.root.after(300, self.auto_step_loop) + return + + try: + target = self.auto_target + except AttributeError: + try: + self.auto_target = next(self.iterator) + target = self.auto_target + except StopIteration: + self.finish_check() + self.auto_running = False + return + + cx = cy = tx = ty = None + + for y in range(self.lab.длина): + for x in range(self.lab.ширина): + if self.lab.ячейки[y][x] is cur: + cx, cy = x, y + if self.lab.ячейки[y][x] is target: + tx, ty = x, y + + prev_cell = self.robot.текущая_ячейка + + moved = False + + if cx != tx: + prev = self.robot.текущая_ячейка + if cx < tx: + self.robot.СдвинутьВправо() + else: + self.robot.СдвинутьВлево() + moved = self.robot.текущая_ячейка is not prev + + if not moved and cy != ty: + prev = self.robot.текущая_ячейка + if cy < ty: + self.robot.Деплойнуть() + else: + self.robot.Откатнуть() + moved = self.robot.текущая_ячейка is not prev + + if not moved: + self.write_log("Авто: путь заблокирован, цель пропущена") + try: + del self.auto_target + self.auto_target = next(self.iterator) + except StopIteration: + ... + self.root.after(50, self.auto_step_loop) + return + + if self.robot.текущая_ячейка is prev_cell: + self.write_log("Авто: цель недостижима, пропуск") + try: + self.auto_target = next(self.iterator) + except StopIteration: + if self.robot.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Финиш: + self.finish_check() + else: + self.write_log("Авто: обход завершен, финиш не достигнут") + self.auto_running = False + return self.root.after(50, self.auto_step_loop) + return + + if self.robot.текущая_ячейка is target: + del self.auto_target + + self.draw() + self.root.after(300, self.auto_step_loop) + + + def handle_cell_action(self): + cell = self.robot.текущая_ячейка + + if cell.тип_ячейки == ТипЯчеекСерверов.Терминал: + self.robot.Терминал() + self.write_log("Авто: Терминал -> Код") + return True + + if cell.тип_ячейки == ТипЯчеекСерверов.Код: + self.robot.Код() + self.write_log("Авто: Код -> Развернуто") + return True + + return False + + def finish_check(self): + if self.robot.текущая_ячейка.тип_ячейки != ТипЯчеекСерверов.Финиш: + self.show_fail() + return + + for row in self.lab.ячейки: + for cell in row: + if cell.тип_ячейки in ( + ТипЯчеекСерверов.Код, + ТипЯчеекСерверов.Терминал, + ): + self.show_fail() + return + + self.show_success() + + def show_success(self): + messagebox.showinfo( + "Результат", + "успешный успех" + ) + self.root.destroy() + + def show_fail(self): + messagebox.showwarning( + "Результат", + "робот еще не доделал все" + ) + + def write_log(self, text): + self.log.config(state="normal") + self.log.insert(tk.END, text + "\n") + self.log.see(tk.END) + self.log.config(state="disabled") + + def step(self, action): + before = self.robot.текущая_ячейка + result = action() + after = self.robot.текущая_ячейка + + if result is None: + self.write_log("Действие невозможно") + else: + self.write_log(f"{action.__name__}: {before} -> {after}") + + if self.robot.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Финиш: + self.finish_check() + + self.draw() + + def _setup_demo_map(self): + data = [ + [14, 6, 3, 4, 1], + [3, 0, 6, 4, 6], + [6, 0, 6, 6, 3], + [1, 0, 4, 4, 1], + [4, 6, 3, 4, 1], + [5, 0, 1, 3, 6], + ] + + for y in range(self.lab.длина): + for x in range(self.lab.ширина): + v = data[y][x] + has_robot = v == 14 + cell_type = ТипЯчеекСерверов(v if v != 14 else 6) + cell = self.lab.ячейки[y][x] + cell.тип_ячейки = cell_type + cell.ячейка_робота = has_robot + + def draw(self): + self.canvas.delete("all") + h = self.lab.длина + w = self.lab.ширина + + colors = { + ТипЯчеекСерверов.Сервер: "#B3B3B3", + ТипЯчеекСерверов.Терминал: "#D4DDF1", + ТипЯчеекСерверов.Развернуто: "#C9E2CD", + ТипЯчеекСерверов.Код: "#F6D6A1", + ТипЯчеекСерверов.Баг: "#EBACAB", + ТипЯчеекСерверов.Финиш: "#896487", + ТипЯчеекСерверов.Сеть: "#F9F0EE", + } + + for y in range(h): + for x in range(w): + cell = self.lab.ячейки[y][x] + gui_y = (h - 1 - y) * self.cell_size + gui_x = x * self.cell_size + + color = colors[cell.тип_ячейки] + self.canvas.create_rectangle( + gui_x, + gui_y, + gui_x + self.cell_size, + gui_y + self.cell_size, + fill=color, + outline="white", + ) + + if cell.ячейка_робота: + self.canvas.create_text( + gui_x + 30, + gui_y + 30, + font= ("Arial", 40), + text="🤖", + ) + + + +if __name__ == "__main__": + root = tk.Tk() + DevOpsApp(root) + root.mainloop() \ No newline at end of file diff --git "a/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main2.py" "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main2.py" new file mode 100644 index 0000000..dfe3bf2 --- /dev/null +++ "b/5030102_30202/\320\235\320\260\320\267\320\260\321\200\320\276\320\262\320\260 \320\220\320\275\320\260\321\201\321\202\320\260\321\201\320\270\321\217 \320\224\320\265\320\275\320\270\321\201\320\276\320\262\320\275\320\260/main2.py" @@ -0,0 +1,723 @@ +import streamlit as st +import yaml +from enum import Enum + + +class ТипНаправленийDevOpsНапр(Enum): + ДеплойВперёд = "ДеплойВперёд" + ОткатНазад = "ОткатНазад" + ВлевоСеть = "ВлевоСеть" + ВправоСеть = "ВправоСеть" + ДиагDevСЗ = "ДиагDevСЗ" + ДиагDevЮВ = "ДиагDevЮВ" + + +class ТипЯчеекСерверов(Enum): + Сервер = "Сервер" + Терминал = "Терминал" + Развернуто = "Развернуто" + Код = "Код" + Баг = "Баг" + Финиш = "Финиш" + Сеть = "Сеть" + + +class ЯчейкаРоботПрограммист: + def __init__(self, тип_ячейки=None, ячейка_робота=False, x=0, y=0): + self.ячейка_робота = ячейка_робота + self.тип_ячейки = тип_ячейки + self.x = x + self.y = y + + +class ЛабиринтРоботПрограммист: + def __init__(self, ширина=5, длина=6): + self.ширина = ширина + self.длина = длина + self.ячейки = [] + self.создать_демо_лабиринт() + + def ПолучитьСоседнююЯчейку(self, текущая_ячейка, направление_поиска): + if текущая_ячейка is None or not self.ячейки: + return None + + x, y = текущая_ячейка.x, текущая_ячейка.y + + if направление_поиска == ТипНаправленийDevOpsНапр.ДеплойВперёд: + dx, dy = (0, 1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ОткатНазад: + dx, dy = (0, -1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ВлевоСеть: + dx, dy = (-1, 0) + elif направление_поиска == ТипНаправленийDevOpsНапр.ВправоСеть: + dx, dy = (1, 0) + elif направление_поиска == ТипНаправленийDevOpsНапр.ДиагDevСЗ: + dx, dy = (-1, 1) + elif направление_поиска == ТипНаправленийDevOpsНапр.ДиагDevЮВ: + dx, dy = (1, -1) + else: + return None + + nx, ny = x + dx, y + dy + + if not (0 <= nx < self.ширина and 0 <= ny < self.длина): + return None + + соседняя = self.ячейки[ny][nx] + + if соседняя.тип_ячейки in (ТипЯчеекСерверов.Сервер, ТипЯчеекСерверов.Баг): + return None + + return соседняя + + def ПолучитьИтератор(self): + if not self.ячейки: + return iter(()) + + x = 0 + y = self.длина - 1 + direction = 1 + + while True: + yield self.ячейки[y][x] + + if direction == 1: + if x < self.ширина - 1: + x += 1 + else: + if y == 0: + break + y -= 1 + direction = -1 + else: + if x > 0: + x -= 1 + else: + if y == 0: + break + y -= 1 + direction = 1 + + def создать_демо_лабиринт(self): + data = [ + [14, 6, 3, 4, 1], + [3, 0, 6, 4, 6], + [6, 0, 6, 6, 2], + [1, 0, 4, 4, 1], + [4, 6, 3, 4, 2], + [5, 0, 1, 3, 6], + ] + + self.ячейки = [] + + for y in range(self.длина): + row = [] + for x in range(self.ширина): + cell_type_val = data[y][x] + has_robot = cell_type_val == 14 + if has_robot: + cell_type_val = 6 + + cell_type_map = { + 0: ТипЯчеекСерверов.Сервер, + 1: ТипЯчеекСерверов.Терминал, + 2: ТипЯчеекСерверов.Развернуто, + 3: ТипЯчеекСерверов.Код, + 4: ТипЯчеекСерверов.Баг, + 5: ТипЯчеекСерверов.Финиш, + 6: ТипЯчеекСерверов.Сеть + } + + cell_type = cell_type_map.get(cell_type_val, ТипЯчеекСерверов.Сеть) + row.append(ЯчейкаРоботПрограммист(тип_ячейки=cell_type, ячейка_робота=has_robot, x=x, y=y)) + self.ячейки.append(row) + + +class РоботПрограммист: + def __init__(self, лабиринт): + self.лабиринт = лабиринт + self.деплоэнергия = None + self.откатный = None + self.шаги = 0 + + for row in self.лабиринт.ячейки: + for cell in row: + if cell.ячейка_робота: + self.текущая_ячейка = cell + return + + def _переместить_робота(self, направление): + if self.текущая_ячейка is None: + return None + + цель = self.лабиринт.ПолучитьСоседнююЯчейку(self.текущая_ячейка, направление) + + if цель is None: + return None + + self.текущая_ячейка.ячейка_робота = False + цель.ячейка_робота = True + self.текущая_ячейка = цель + self.шаги += 1 + + return цель + + def Деплойнуть(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ДеплойВперёд) + + def Откатнуть(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ОткатНазад) + + def СдвинутьВлево(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ВлевоСеть) + + def СдвинутьВправо(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ВправоСеть) + + def ПоднятьКонтейнер(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ДиагDevСЗ) + + def ОпуститьКонтейнер(self): + return self._переместить_робота(ТипНаправленийDevOpsНапр.ДиагDevЮВ) + + def Код(self): + if self.текущая_ячейка is None: + return None + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Код: + self.текущая_ячейка.тип_ячейки = ТипЯчеекСерверов.Развернуто + return True + return False + + def Терминал(self): + if self.текущая_ячейка is None: + return None + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Терминал: + self.текущая_ячейка.тип_ячейки = ТипЯчеекСерверов.Код + return True + return False + + def обработать_текущую_ячейку(self): + if self.текущая_ячейка is None: + return False + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Терминал: + self.Терминал() + self.Код() + return True + + if self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Код: + self.Код() + return True + + return False + + def проверить_цель(self): + if self.текущая_ячейка is None: + return False + + for row in self.лабиринт.ячейки: + for cell in row: + if cell.тип_ячейки in [ТипЯчеекСерверов.Код, ТипЯчеекСерверов.Терминал]: + return False + + return self.текущая_ячейка.тип_ячейки == ТипЯчеекСерверов.Финиш + + +def init_session_state(): + if 'robot' not in st.session_state: + maze = ЛабиринтРоботПрограммист(ширина=5, длина=6) + st.session_state.robot = РоботПрограммист(maze) + st.session_state.iterator = None + st.session_state.auto_mode = False + st.session_state.auto_targets = [] + st.session_state.current_target_index = 0 + st.session_state.logs = ["робот готов к работе"] + st.session_state.show_success = False + st.session_state.show_fail = False + + +def get_cell_color(cell_type): + colors = { + "Сервер": "#B3B3B3", + "Терминал": "#D4DDF1", + "Развернуто": "#C9E2CD", + "Код": "#F6D6A1", + "Баг": "#EBACAB", + "Финиш": "#896487", + "Сеть": "#F9F0EE", + } + return colors.get(cell_type, "#FFFFFF") + + +def render_grid(): + robot = st.session_state.robot + maze = robot.лабиринт + + for y in range(maze.длина - 1, -1, -1): + cols = st.columns(maze.ширина + 1) + + for x in range(maze.ширина): + cell = maze.ячейки[y][x] + cell_type = cell.тип_ячейки.value if cell.тип_ячейки else "Сеть" + color = get_cell_color(cell_type) + + with cols[x + 1]: + border_color = "#85A1D2" if cell.ячейка_робота else "#848484" + border_width = "3px" if cell.ячейка_робота else "1px" + + st.markdown(f""" +
+
+ {x},{y} +
+
+ {cell_type[:4]} +
+ """, unsafe_allow_html=True) + + if cell.ячейка_робота: + st.markdown( + '
🤖
', + unsafe_allow_html=True) + + st.markdown('
', unsafe_allow_html=True) + + cols_bottom = st.columns(maze.ширина + 1) + + +def move_robot(action_name): + robot = st.session_state.robot + result = None + + if action_name == "Деплойнуть": + result = robot.Деплойнуть() + elif action_name == "Откатнуть": + result = robot.Откатнуть() + elif action_name == "СдвинутьВлево": + result = robot.СдвинутьВлево() + elif action_name == "СдвинутьВправо": + result = robot.СдвинутьВправо() + elif action_name == "ПоднятьКонтейнер": + result = robot.ПоднятьКонтейнер() + elif action_name == "ОпуститьКонтейнер": + result = robot.ОпуститьКонтейнер() + + if result: + st.session_state.logs.append(f"{action_name} -> ({result.x},{result.y})") + else: + st.session_state.logs.append(f"{action_name} невозможно!") + + return result + + +def start_auto_mode(): + robot = st.session_state.robot + st.session_state.auto_targets = list(robot.лабиринт.ПолучитьИтератор()) + st.session_state.current_target_index = 0 + st.session_state.auto_mode = True + st.session_state.logs.append("Авто-режим запущен") + + +def auto_step(): + if not st.session_state.auto_mode: + return False + + robot = st.session_state.robot + + if st.session_state.current_target_index >= len(st.session_state.auto_targets): + st.session_state.auto_mode = False + st.session_state.logs.append("Авто-режим завершен: пройдены все ячейки") + check_goal_auto() + return False + + target_cell = st.session_state.auto_targets[st.session_state.current_target_index] + + if robot.текущая_ячейка is target_cell: + processed = robot.обработать_текущую_ячейку() + if processed: + st.session_state.logs.append(f"Авто: обработана ячейка ({target_cell.x},{target_cell.y})") + st.session_state.current_target_index += 1 + return True + else: + start_x, start_y = robot.текущая_ячейка.x, robot.текущая_ячейка.y + target_x, target_y = target_cell.x, target_cell.y + + moved = False + + if start_x < target_x: + result = robot.СдвинутьВправо() + if result: + moved = True + st.session_state.logs.append(f"Авто: Вправо -> ({result.x},{result.y})") + else: + st.session_state.logs.append("Авто: Путь заблокирован, пропуск ячейки") + st.session_state.current_target_index += 1 + elif start_x > target_x: + result = robot.СдвинутьВлево() + if result: + moved = True + st.session_state.logs.append(f"Авто: Влево -> ({result.x},{result.y})") + else: + st.session_state.logs.append("Авто: Путь заблокирован, пропуск ячейки") + st.session_state.current_target_index += 1 + elif start_y < target_y: + result = robot.Деплойнуть() + if result: + moved = True + st.session_state.logs.append(f"Авто: Деплой -> ({result.x},{result.y})") + else: + st.session_state.logs.append("Авто: Путь заблокирован, пропуск ячейки") + st.session_state.current_target_index += 1 + elif start_y > target_y: + result = robot.Откатнуть() + if result: + moved = True + st.session_state.logs.append(f"Авто: Откат -> ({result.x},{result.y})") + else: + st.session_state.logs.append("Авто: Путь заблокирован, пропуск ячейки") + st.session_state.current_target_index += 1 + + if not moved and robot.текущая_ячейка is not target_cell: + st.session_state.logs.append("Авто: Невозможно добраться, пропуск ячейки") + st.session_state.current_target_index += 1 + + return moved + + +def check_goal(): + robot = st.session_state.robot + if robot.проверить_цель(): + st.session_state.show_success = True + st.session_state.logs.append("Цель достигнута!") + else: + st.session_state.show_fail = True + remaining = [] + for row in robot.лабиринт.ячейки: + for cell in row: + if cell.тип_ячейки == ТипЯчеекСерверов.Код: + remaining.append(f"Код в ({cell.x},{cell.y})") + elif cell.тип_ячейки == ТипЯчеекСерверов.Терминал: + remaining.append(f"Терминал в ({cell.x},{cell.y})") + + if remaining: + st.session_state.logs.append(f"Цель не достигнута, не обработано {len(remaining)} ячеек") + elif robot.текущая_ячейка.тип_ячейки != ТипЯчеекСерверов.Финиш: + st.session_state.logs.append( + f"Робот не на финише! Позиция: ({robot.текущая_ячейка.x},{robot.текущая_ячейка.y})") + else: + st.session_state.logs.append("Все условия выполнены, кроме нахождения на финише") + + +def check_goal_auto(): + robot = st.session_state.robot + if robot.проверить_цель(): + st.session_state.show_success = True + else: + st.session_state.show_fail = True + + +def restart_game(): + st.session_state.auto_mode = False + st.session_state.iterator = None + st.session_state.auto_targets = [] + st.session_state.current_target_index = 0 + st.session_state.logs = [] + maze = ЛабиринтРоботПрограммист(ширина=5, длина=6) + st.session_state.robot = РоботПрограммист(maze) + st.session_state.show_success = False + st.session_state.show_fail = False + st.session_state.logs.append("Новая игра") + st.session_state.logs.append("Робот начинает в позиции (0,0)") + + +def render_controls(): + st.markdown("### Управление движением") + + col1, col2, col3 = st.columns(3) + + with col2: + if st.button("Деплой", key="up", use_container_width=True, help="Вперед"): + move_robot("Деплойнуть") + st.rerun() + + with col1: + if st.button("Влево", key="left", use_container_width=True, help="Влево"): + move_robot("СдвинутьВлево") + st.rerun() + + with col3: + if st.button("Вправо", key="right", use_container_width=True, help="Вправо"): + move_robot("СдвинутьВправо") + st.rerun() + + with col2: + if st.button("Откат", key="down", use_container_width=True, help="Назад"): + move_robot("Откатнуть") + st.rerun() + + st.markdown("") + col1, col2 = st.columns(2) + + with col1: + if st.button("Поднять", key="up_left", use_container_width=True, help="Северо-запад"): + move_robot("ПоднятьКонтейнер") + st.rerun() + + with col2: + if st.button("Опустить", key="down_right", use_container_width=True, help="Юго-восток"): + move_robot("ОпуститьКонтейнер") + st.rerun() + + st.markdown("### Действия") + col1, col2 = st.columns(2) + + with col1: + if st.button("Код", key="code", use_container_width=True, help="Код -> Развернуто"): + robot = st.session_state.robot + if robot.Код(): + st.session_state.logs.append(f"Код -> Развернуто в ({robot.текущая_ячейка.x},{robot.текущая_ячейка.y})") + else: + st.session_state.logs.append("Нет Кода для обработки") + st.rerun() + + with col2: + if st.button("Терминал", key="terminal", use_container_width=True, help="Терминал -> Код"): + robot = st.session_state.robot + if robot.Терминал(): + st.session_state.logs.append(f"Терминал -> Код в ({robot.текущая_ячейка.x},{robot.текущая_ячейка.y})") + else: + st.session_state.logs.append("Нет Терминала для обработки") + st.rerun() + + st.markdown("### Авто-режим") + col1, col2, col3 = st.columns(3) + + with col1: + if st.button("Запуск", key="start_auto", use_container_width=True, help="Запустить змейку"): + start_auto_mode() + st.rerun() + + with col2: + if st.button("Шаг", key="next_auto", use_container_width=True, + disabled=not st.session_state.auto_mode, help="Следующий шаг авто-режима"): + auto_step() + st.rerun() + + with col3: + if st.button("Стоп", key="stop_auto", use_container_width=True, + disabled=not st.session_state.auto_mode, help="Остановить авто-режим"): + st.session_state.auto_mode = False + st.session_state.logs.append("Авто-режим остановлен") + st.rerun() + + st.markdown("") + col1, col2 = st.columns(2) + + with col1: + if st.button("Проверить цель", key="check", use_container_width=True, help="Проверить выполнение задачи"): + check_goal() + st.rerun() + + with col2: + if st.button("Новая игра", key="restart", use_container_width=True): + restart_game() + st.rerun() + + +def render_stats(): + robot = st.session_state.robot + current_x = robot.текущая_ячейка.x if robot.текущая_ячейка else 0 + current_y = robot.текущая_ячейка.y if robot.текущая_ячейка else 0 + cell_type = robot.текущая_ячейка.тип_ячейки.value if robot.текущая_ячейка else "Неизвестно" + + st.markdown("### Информация") + + st.text(f"Шагов: {robot.шаги}") + st.text(f"Позиция: {current_x},{current_y}") + st.text(f"Тип ячейки: {cell_type}") + st.text(f"Авто-режим: {'Активен' if st.session_state.auto_mode else 'Выключен'}") + + +def render_logs(): + st.markdown("### Лог действий") + + if st.session_state.logs: + for log in reversed(st.session_state.logs[-15:]): + st.text(log) + else: + st.text("Лог пуст") + + +def render_legend(): + with st.expander("Легенда цветов"): + legend_items = [ + ("Сервер", "#B3B3B3", "Запрещенная зона"), + ("Терминал", "#D4DDF1", "Заменяется на Код"), + ("Развернуто", "#C9E2CD", "Обработанный Код"), + ("Код", "#F6D6A1", "Заменяется на Развернуто"), + ("Баг", "#EBACAB", "Запрещенная зона"), + ("Финиш", "#896487", "Целевая ячейка"), + ("Сеть", "#F9F0EE", "Пустая ячейка"), + ] + + for label, color, desc in legend_items: + col1, col2 = st.columns([1, 4]) + with col1: + st.markdown( + f'
', + unsafe_allow_html=True) + with col2: + st.markdown(f"**{label}**
{desc}", unsafe_allow_html=True) + + +def create_mapping_yaml(): + mapping = { + 'классы': [ + { + 'Класс диаграммы': 'РоботПрограммист', + 'свойства': [ + {'лабиринт': 'лабиринт'}, + {'деплоэнергия': 'деплоэнергия'}, + {'откатный': 'откатный'} + ], + 'методы': [ + {'Деплойнуть': 'Деплойнуть'}, + {'Откатнуть': 'Откатнуть'}, + {'СдвинутьВлево': 'СдвинутьВлево'}, + {'СдвинутьПраво': 'СдвинутьВправо'}, + {'ПоднятьКонтейнер': 'ПоднятьКонтейнер'}, + {'ОпуститьКонтейнер': 'ОпуститьКонтейнер'}, + {'Код': 'Код'}, + {'Терминал': 'Терминал'} + ] + }, + { + 'Класс диаграммы': 'ЛабиринтРоботПрограммист', + 'свойства': [ + {'ширина': 'ширина'}, + {'длина': 'длина'}, + {'ячейки': 'ячейки'} + ], + 'методы': [ + {'ПолучитьСоседнююЯчейку': 'ПолучитьСоседнююЯчейку'}, + {'ПолучитьИтератор': 'ПолучитьИтератор'}, + {'ИнициализироватьЛабиринт': 'ИнициализироватьЛабиринт'} + ] + }, + { + 'Класс диаграммы': 'ЯчейкаРоботПрограммист', + 'свойства': [ + {'ячейка_робота': 'ячейка_робота'}, + {'тип_ячейки': 'тип_ячейки'} + ], + 'методы': [] + } + ], + 'перечисления': [ + { + 'ПеречислениеНаДиаграмме': 'ТипНаправленийDevOpsНапр', + 'опции': [ + {'ДеплойВперёд': 'ДеплойВперёд'}, + {'ОткатНазад': 'ОткатНазад'}, + {'ВлевоСеть': 'ВлевоСеть'}, + {'ВправоСеть': 'ВправоСеть'}, + {'ДиагDevC3': 'ДиагDevСЗ'}, + {'ДиагDevIOB': 'ДиагDevЮВ'} + ] + }, + { + 'ПеречислениеНаДиаграмме': 'ТипЯчеекСерверов', + 'опции': [ + {'Сервер': 'Сервер'}, + {'Терминал': 'Терминал'}, + {'Развернуто': 'Развернуто'}, + {'Код': 'Код'}, + {'Баг': 'Баг'}, + {'Финиш': 'Финиш'}, + {'Сеть': 'Сеть'} + ] + } + ] + } + + with open('mapping.yaml', 'w', encoding='utf-8') as f: + yaml.dump(mapping, f, allow_unicode=True, default_flow_style=False) + + +def main(): + st.set_page_config( + page_title="Робот-Программист", + layout="wide" + ) + + init_session_state() + + st.title("⠀⠀⠀⠀⠀⠀⠀Робот-Программист") + + if st.session_state.auto_mode: + st.info("Автоматический режим активен") + + if st.session_state.show_success: + st.success("успешный успех хихихи") + st.session_state.show_success = False + + if st.session_state.show_fail: + st.warning("Робот еще не доделал все") + st.session_state.show_fail = False + + col1, col2 = st.columns([2, 1]) + + with col1: + render_grid() + + with col2: + render_stats() + render_controls() + render_logs() + render_legend() + + with st.expander("Условие задачи"): + st.markdown(""" + **Цель задачи:** + 1. Обработать все ячейки типа **Код** и **Терминал** + 2. Завершить программу на ячейке типа **Финиш** + + **Преобразования:** + - **Код** -> заменяет Код -> Развернуто + - **Терминал** -> заменяет Терминал -> Код + + **Ограничения перемещения:** + - Нельзя заходить на ячейки типа: **Сервер** + - Нельзя заходить на ячейки типа: **Баг** + + **Координатная система:** + - Ось Y направлена вверх + - Ось X направлена вправо + - Начало координат — в нижней левой ячейке (0,0) + + **Авто-режим:** + - Движется змейкой по итератору + - Автоматически обрабатывает ячейки + - При затыкании пропускает ячейку и продолжает + """) + + create_mapping_yaml() + + +if __name__ == "__main__": + main()