]> vgcfreebox.myrthtech.pt Git - ue-aai-hiddenarkgame.git/commitdiff
final project of Applied Artificial Inteligence Course main
authorVGoncalo <vitor.goncalo.costa@gmail.com>
Sun, 15 Mar 2026 22:18:31 +0000 (22:18 +0000)
committerVGoncalo <vitor.goncalo.costa@gmail.com>
Sun, 15 Mar 2026 22:18:31 +0000 (22:18 +0000)
HiddenArkGame.py [new file with mode: 0644]
RelatórioAAI-57098&70323.pdf [new file with mode: 0644]
readme.txt [new file with mode: 0644]

diff --git a/HiddenArkGame.py b/HiddenArkGame.py
new file mode 100644 (file)
index 0000000..bf7e711
--- /dev/null
@@ -0,0 +1,276 @@
+import tkinter as tk\r
+import sys\r
+from tkinter import ttk, messagebox\r
+import random\r
+import numpy as np\r
+from scipy.spatial.distance import cityblock\r
+\r
+# Configurações do tabuleiro (tamanho (X,Y), orçamento inicial, Custo dos sensores)\r
+if len(sys.argv) > 1:\r
+    ROWS = int(sys.argv[1])\r
+    COLS = int(sys.argv[2])\r
+else:\r
+    ROWS,COLS = 5,5\r
+\r
+\r
+class TreasureGame:\r
+    def __init__(self, root):\r
+        self.root = root\r
+        self.root.title("Caçadores da Arca Perdida")\r
+\r
+        # Inicialização de variáveis de estado\r
+        self.perfect_mode = False\r
+        self.INITIAL_BUDGET = 100\r
+        self.SENSOR_COSTS = {"GPR": 5, "MAG": 3, "VIS": 1, "DIG": 0}\r
+\r
+        self.budget = self.INITIAL_BUDGET\r
+        self.ark_loc = (random.randint(0, ROWS - 1), random.randint(0, COLS - 1))\r
+        #self.ark_loc = (1,1)\r
+        self.probs = np.full((ROWS, COLS), 1.0 / (ROWS * COLS))\r
+        self.used_sensors = set()\r
+        self.cell_history = {}\r
+        self.show_treasure_debug = False\r
+        # Tabelas de Probabilidade Normais\r
+        self.SENSOR_TABLES = {\r
+            "GPR": {\r
+                "STRONG": [0.75, 0.10, 0.05, 0.02],\r
+                "MODERATE": [0.15, 0.70, 0.15, 0.08],\r
+                "WEAK": [0.07, 0.15, 0.65, 0.15],\r
+                "NONE": [0.03, 0.05, 0.15, 0.75]\r
+            },\r
+            "MAG": {\r
+                "HIGH": [0.70, 0.15, 0.10],\r
+                "MEDIUM": [0.20, 0.65, 0.25],\r
+                "LOW": [0.10, 0.20, 0.65]\r
+            },\r
+            "VIS": {\r
+                "SUSPICIOUS": [0.60, 0.20],\r
+                "NORMAL": [0.40, 0.80]\r
+            }\r
+        }\r
+        # Tabelas de Probabilidade Perfeitas\r
+        self.SENSOR_TABLES_PERFECT = {\r
+            "GPR": {\r
+                "STRONG": [1, 0, 0, 0],\r
+                "MODERATE": [0, 1, 0, 0],\r
+                "WEAK": [0, 0, 1, 0],\r
+                "NONE": [0, 0, 0, 1],\r
+            },\r
+            "MAG": {\r
+                "HIGH": [1, 0, 0],\r
+                "MEDIUM": [0, 1, 0],\r
+                "LOW": [0, 0, 1]\r
+            },\r
+            "VIS": {\r
+                "SUSPICIOUS": [1, 0],\r
+                "NORMAL": [0, 1]\r
+            }\r
+        }\r
+\r
+\r
+        # Estilos dos botões\r
+        self.style = ttk.Style()\r
+        self.style.configure("Perfect.TButton", foreground="green", font=("Arial", 9, "bold"))\r
+        self.style.configure("Normal.TButton", foreground="black")\r
+\r
+        self.setup_ui()\r
+\r
+    # Define os sensores utilizados\r
+    @property\r
+    def current_sensor_table(self):\r
+        return self.SENSOR_TABLES_PERFECT if self.perfect_mode else self.SENSOR_TABLES\r
+\r
+    def setup_ui(self):\r
+        # Tabuleiro INICIO\r
+        self.main_frame = ttk.Frame(self.root, padding="10")\r
+        self.main_frame.grid(row=0, column=0, sticky="nsew")\r
+\r
+        self.buttons = {}\r
+        for r in range(ROWS):\r
+            for c in range(COLS):\r
+                btn = tk.Button(self.main_frame, text="", width=15, height=5,\r
+                                font=("Arial", 8), relief="groove",\r
+                                command=lambda row=r, col=c: self.cell_click(row, col))\r
+                btn.grid(row=r, column=c, padx=2, pady=2, sticky="nsew")\r
+                self.buttons[(r, c)] = btn\r
+        # Tabuleiro FIM\r
+        # Menu Lateral INICIO\r
+        control_panel = ttk.Frame(self.root, padding="10")\r
+        control_panel.grid(row=0, column=1, sticky="ns")\r
+\r
+        # Texto Orçamento\r
+        self.budget_var = tk.StringVar(value=f"Orçamento: {self.budget}")\r
+        ttk.Label(control_panel, textvariable=self.budget_var, font=("Arial", 12, "bold")).pack(pady=5)\r
+\r
+        # RadioButton Sensores\r
+        self.sensor_var = tk.StringVar(value="GPR")\r
+        sf = ttk.LabelFrame(control_panel, text=" Selecione o Sensor ", padding="5")\r
+        sf.pack(fill='x', pady=5)\r
+        for s, cost in self.SENSOR_COSTS.items():\r
+            ttk.Radiobutton(sf, text=f"{s} ({cost})", variable=self.sensor_var, value=s).pack(anchor='w')\r
+\r
+        # Botão Revelar tesouro\r
+        self.reveal_btn = ttk.Button(control_panel, text="Revelar Tesouro: OFF", command=self.toggle_treasure,\r
+                                     style="Normal.TButton")\r
+        self.reveal_btn.pack(fill='x', pady=10)\r
+\r
+        # Botão Sensores Perfeitos\r
+        self.perfect_btn = ttk.Button(control_panel, text="Sensores Perfeitos: OFF", command=self.toggle_perfect_mode,\r
+                                      style="Normal.TButton")\r
+        self.perfect_btn.pack(fill='x', pady=5)\r
+\r
+        # Painel Histórico\r
+        ttk.Label(control_panel, text="Histórico:").pack(anchor='w', pady=(10, 0))\r
+        self.history_log = tk.Text(control_panel, width=30, height=12, state='disabled', font=("Consolas", 9))\r
+        self.history_log.pack(pady=5)\r
+\r
+        # Botão Reiniciar\r
+        ttk.Button(control_panel, text="Reiniciar Jogo", command=self.reset_game).pack(fill='x', pady=2)\r
+\r
+        # Botão Sair\r
+        ttk.Button(control_panel, text="Sair", command=self.root.destroy).pack(fill='x', pady=5)\r
+\r
+        # Menu lateral FIM\r
+        self.update_grid_display()\r
+\r
+    # Activa/Desactiva sensores perfeitos\r
+    def toggle_perfect_mode(self):\r
+        self.perfect_mode = not self.perfect_mode\r
+        if self.perfect_mode:\r
+            self.perfect_btn.config(text="Sensores Perfeitos: ON", style="Perfect.TButton")\r
+        else:\r
+            self.perfect_btn.config(text="Sensores Perfeitos: OFF", style="Normal.TButton")\r
+\r
+        self.history_log.config(state='normal')\r
+        self.history_log.insert(tk.END, f"> Modo Sensores Perfeitos: {'ON' if self.perfect_mode else 'OFF'}\n")\r
+        self.history_log.see(tk.END)\r
+        self.history_log.config(state='disabled')\r
+\r
+    # Activa/Desactiva localização do tesouro\r
+    def toggle_treasure(self):\r
+\r
+        self.show_treasure_debug = not self.show_treasure_debug\r
+        if self.show_treasure_debug:\r
+            self.reveal_btn.config(text="Revelar Tesouro: ON", style="Perfect.TButton")\r
+        else:\r
+            self.reveal_btn.config(text="Revelar Tesouro: OFF", style="Normal.TButton")\r
+\r
+        self.history_log.config(state='normal')\r
+        self.history_log.insert(tk.END, f"> Modo Tesouro Visivel: {'ON' if self.show_treasure_debug else 'OFF'}\n")\r
+        self.history_log.see(tk.END)\r
+        self.history_log.config(state='disabled')\r
+\r
+        self.update_grid_display()\r
+\r
+    # Actualiza o tabuleiro\r
+    def update_grid_display(self):\r
+        for (r, c), btn in self.buttons.items():\r
+            treasure_header = "!!! TESOURO !!!\n" if (self.show_treasure_debug and (r, c) == self.ark_loc) else ""\r
+            p_text = f"{self.probs[r, c]:.1%}"\r
+            history_text = self.cell_history.get((r, c), "")\r
+            if history_text:\r
+                history_text = "\n" + history_text\r
+\r
+            btn.config(text=f"{treasure_header}{p_text}{history_text}")\r
+\r
+            # Cor de fundo baseada na probabilidade\r
+            intensity = int(255 - (self.probs[r, c] * 350))\r
+            intensity = max(min(intensity, 255), 180)\r
+            color = f"#{255:02x}{intensity:02x}{intensity:02x}"\r
+\r
+            if self.show_treasure_debug and (r, c) == self.ark_loc:\r
+                color = "#FFD700"  # Dourado\r
+\r
+            btn.config(bg=color)\r
+\r
+    # Click das localizações do mapa\r
+    def cell_click(self, r, c):\r
+        sensor = self.sensor_var.get()\r
+        cost = self.SENSOR_COSTS[sensor]\r
+\r
+        # Verifica o se sensor já foi usado na localização\r
+        if sensor != "DIG" and (r, c, sensor) in self.used_sensors:\r
+            messagebox.showwarning("Aviso", "Este sensor já foi usado aqui!")\r
+            return\r
+\r
+        # Verifica se há orçamento\r
+        if self.budget < cost:\r
+            messagebox.showwarning("Aviso", "Orçamento insuficiente!")\r
+            return\r
+\r
+        # Se o jogador utilizou "DIG" verifica se ganhou ou perdeu\r
+        if sensor == "DIG":\r
+            if (r, c) == self.ark_loc:\r
+                messagebox.showinfo("Vitória", f"Encontrou o tesouro!\nPontuação final: {self.budget}")\r
+            else:\r
+                messagebox.showerror("Derrota", f"O tesouro não está nesta localização.\nPerdeu o jogo!")\r
+            self.root.destroy()\r
+            return\r
+\r
+        # Executa o sensor, com base na tabela utilizada\r
+        dist = cityblock((r, c), self.ark_loc)\r
+        active_table = self.current_sensor_table[sensor]\r
+\r
+        # Determinar leitura baseada nas probabilidades\r
+        outcomes = list(active_table.keys())\r
+        max_idx = len(next(iter(active_table.values()))) - 1\r
+        idx = min(dist, max_idx)\r
+        weights = [active_table[out][idx] for out in outcomes]\r
+        print(weights)\r
+        reading = random.choices(outcomes, weights=weights, k=1)[0]\r
+\r
+\r
+        # Actualiza orçamento\r
+        self.used_sensors.add((r, c, sensor))\r
+        self.budget -= cost\r
+        self.budget_var.set(f"Orçamento: {self.budget}")\r
+\r
+        # Atualiza o resultado na localização\r
+        entry = f"{sensor}:{reading}"\r
+\r
+        # Actualiza o histórico\r
+        self.cell_history[(r, c)] = f"{self.cell_history.get((r, c), '')}\n{entry}".strip()\r
+        self.history_log.config(state='normal')\r
+        self.history_log.insert(tk.END, f"{sensor} em ({r},{c}): {reading}\n")\r
+        self.history_log.see(tk.END)\r
+        self.history_log.config(state='disabled')\r
+\r
+        self.update_probabilities(sensor, reading, (r, c))\r
+        self.update_grid_display()\r
+\r
+    # actualiza as probabilidades no tabuleiro\r
+    def update_probabilities(self, sensor, reading, click_loc):\r
+        new_probs = np.zeros((ROWS, COLS))\r
+        table_row = self.current_sensor_table[sensor][reading]\r
+        max_idx = len(table_row) - 1\r
+\r
+        for r in range(ROWS):\r
+            for c in range(COLS):\r
+                d = cityblock((r, c), click_loc)\r
+                prob_evidence = table_row[min(d, max_idx)]\r
+                new_probs[r, c] = self.probs[r, c] * prob_evidence\r
+\r
+        total = np.sum(new_probs)\r
+        if total > 0:\r
+            self.probs = new_probs / total\r
+\r
+    # Reinicia o jogo\r
+    def reset_game(self):\r
+        self.budget = self.INITIAL_BUDGET\r
+        self.budget_var.set(f"Orçamento: {self.budget}")\r
+        self.ark_loc = (random.randint(0, ROWS - 1), random.randint(0, COLS - 1))\r
+        self.probs = np.full((ROWS, COLS), 1.0 / (ROWS * COLS))\r
+        self.used_sensors = set()\r
+        self.cell_history = {}\r
+\r
+        self.history_log.config(state='normal')\r
+        self.history_log.delete('1.0', tk.END)\r
+        self.history_log.config(state='disabled')\r
+\r
+        self.update_grid_display()\r
+\r
+\r
+if __name__ == "__main__":\r
+    root = tk.Tk()\r
+    game = TreasureGame(root)\r
+    root.mainloop()\r
diff --git a/RelatórioAAI-57098&70323.pdf b/RelatórioAAI-57098&70323.pdf
new file mode 100644 (file)
index 0000000..a48a137
Binary files /dev/null and "b/Relat\303\263rioAAI-57098&70323.pdf" differ
diff --git a/readme.txt b/readme.txt
new file mode 100644 (file)
index 0000000..f1d4f59
--- /dev/null
@@ -0,0 +1,8 @@
+Hidden Ark Game\r
+\r
+This application is a videogame that expects inputs from the user's mouse. The user can selects different inference instruments to improve it's chance to find an hidden treasure ark.
+\r
+In order to properly execute the application the following libraries must be available in the system \r
+or virtual environment: tkinter, numpy, scikit. The default game uses a 5x5 grid of areas to infer, but this can be changed by passing the arguments on start like: .\HiddenArkGame.py 9 9\r
+\r
+The class TreasureGame is responsible to define the game variables and functions available in the UI, the method cell_click is executed on each user click on a tkinter.button, triggering other actions like update_probabilities which calculates the probabilities for each area and refreshes the ui, with the method update_grid_display, which is also responsible for colloring the buttons and provide an heat-map to the user.
\ No newline at end of file