From 33bc3d76c649da1088bb0e57e5a03634beb411ab Mon Sep 17 00:00:00 2001 From: Vichingo455 Date: Thu, 4 Dec 2025 09:36:41 +0100 Subject: [PATCH] Tris MiniMax --- TrisMiniMax/.gitignore | 30 +++++ TrisMiniMax/.idea/.gitignore | 8 ++ TrisMiniMax/.idea/misc.xml | 6 + TrisMiniMax/.idea/modules.xml | 8 ++ TrisMiniMax/.idea/vcs.xml | 6 + TrisMiniMax/TrisMiniMax.iml | 11 ++ TrisMiniMax/src/TrisGame.java | 221 ++++++++++++++++++++++++++++++++++ 7 files changed, 290 insertions(+) create mode 100644 TrisMiniMax/.gitignore create mode 100644 TrisMiniMax/.idea/.gitignore create mode 100644 TrisMiniMax/.idea/misc.xml create mode 100644 TrisMiniMax/.idea/modules.xml create mode 100644 TrisMiniMax/.idea/vcs.xml create mode 100644 TrisMiniMax/TrisMiniMax.iml create mode 100644 TrisMiniMax/src/TrisGame.java diff --git a/TrisMiniMax/.gitignore b/TrisMiniMax/.gitignore new file mode 100644 index 0000000..13275f1 --- /dev/null +++ b/TrisMiniMax/.gitignore @@ -0,0 +1,30 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ +.kotlin + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/TrisMiniMax/.idea/.gitignore b/TrisMiniMax/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/TrisMiniMax/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/TrisMiniMax/.idea/misc.xml b/TrisMiniMax/.idea/misc.xml new file mode 100644 index 0000000..07115cd --- /dev/null +++ b/TrisMiniMax/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TrisMiniMax/.idea/modules.xml b/TrisMiniMax/.idea/modules.xml new file mode 100644 index 0000000..5d7e12e --- /dev/null +++ b/TrisMiniMax/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/TrisMiniMax/.idea/vcs.xml b/TrisMiniMax/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/TrisMiniMax/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TrisMiniMax/TrisMiniMax.iml b/TrisMiniMax/TrisMiniMax.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/TrisMiniMax/TrisMiniMax.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/TrisMiniMax/src/TrisGame.java b/TrisMiniMax/src/TrisGame.java new file mode 100644 index 0000000..bf26f46 --- /dev/null +++ b/TrisMiniMax/src/TrisGame.java @@ -0,0 +1,221 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class TrisGame extends JFrame { + private final JButton[][] buttons = new JButton[3][3]; + private final char[][] board = new char[3][3]; + private final char humanPlayer = 'X'; + private final char aiPlayer = 'O'; + private final JLabel statusLabel; + private boolean gameOver = false; + + public TrisGame() { + setTitle("Tris - Minimax AI"); + setSize(400, 450); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setLayout(new BorderLayout()); + + // Pannello di gioco + JPanel gamePanel = new JPanel(new GridLayout(3, 3, 5, 5)); + gamePanel.setBackground(Color.BLACK); + + // Inizializza la board e i bottoni + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + board[i][j] = ' '; + buttons[i][j] = new JButton(""); + buttons[i][j].setFont(new Font("Arial", Font.BOLD, 60)); + buttons[i][j].setFocusPainted(false); + buttons[i][j].setBackground(Color.WHITE); + + final int row = i; + final int col = j; + + buttons[i][j].addActionListener(e -> playerMove(row, col)); + gamePanel.add(buttons[i][j]); + } + } + + // Pannello di stato + JPanel statusPanel = new JPanel(); + statusLabel = new JLabel("Il tuo turno! (X)"); + statusLabel.setFont(new Font("Arial", Font.BOLD, 16)); + statusPanel.add(statusLabel); + + // Bottone reset + JButton resetButton = new JButton("Nuova Partita"); + resetButton.addActionListener(e -> resetGame()); + statusPanel.add(resetButton); + + add(gamePanel, BorderLayout.CENTER); + add(statusPanel, BorderLayout.SOUTH); + + setLocationRelativeTo(null); + setVisible(true); + } + + private void playerMove(int row, int col) { + if (gameOver || board[row][col] != ' ') return; + + // Mossa del giocatore + board[row][col] = humanPlayer; + buttons[row][col].setText("X"); + buttons[row][col].setForeground(Color.BLUE); + + if (checkWinner(humanPlayer)) { + statusLabel.setText("Hai vinto! 🎉"); + gameOver = true; + highlightWinner(humanPlayer); + return; + } + + if (isBoardFull()) { + statusLabel.setText("Pareggio!"); + gameOver = true; + return; + } + + // Mossa dell'AI + statusLabel.setText("L'AI sta pensando..."); + Timer timer = new Timer(500, e -> { + aiMove(); + + if (checkWinner(aiPlayer)) { + statusLabel.setText("L'AI ha vinto!"); + gameOver = true; + highlightWinner(aiPlayer); + } else if (isBoardFull()) { + statusLabel.setText("Pareggio!"); + gameOver = true; + } else { + statusLabel.setText("Il tuo turno! (X)"); + } + }); + timer.setRepeats(false); + timer.start(); + } + + private void aiMove() { + int[] bestMove = findBestMove(); + board[bestMove[0]][bestMove[1]] = aiPlayer; + buttons[bestMove[0]][bestMove[1]].setText("O"); + buttons[bestMove[0]][bestMove[1]].setForeground(Color.RED); + } + + private int[] findBestMove() { + int bestScore = Integer.MIN_VALUE; + int[] bestMove = new int[2]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i][j] == ' ') { + board[i][j] = aiPlayer; + int score = minimax(0, false); + board[i][j] = ' '; + + if (score > bestScore) { + bestScore = score; + bestMove[0] = i; + bestMove[1] = j; + } + } + } + } + return bestMove; + } + + private int minimax(int depth, boolean isMaximizing) { + if (checkWinner(aiPlayer)) return 10 - depth; + if (checkWinner(humanPlayer)) return depth - 10; + if (isBoardFull()) return 0; + + int bestScore; + if (isMaximizing) { + bestScore = Integer.MIN_VALUE; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i][j] == ' ') { + board[i][j] = aiPlayer; + int score = minimax(depth + 1, false); + board[i][j] = ' '; + bestScore = Math.max(score, bestScore); + } + } + } + } else { + bestScore = Integer.MAX_VALUE; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i][j] == ' ') { + board[i][j] = humanPlayer; + int score = minimax(depth + 1, true); + board[i][j] = ' '; + bestScore = Math.min(score, bestScore); + } + } + } + } + return bestScore; + } + + private boolean checkWinner(char player) { + // Righe e colonne + for (int i = 0; i < 3; i++) { + if (board[i][0] == player && board[i][1] == player && board[i][2] == player) return true; + if (board[0][i] == player && board[1][i] == player && board[2][i] == player) return true; + } + // Diagonali + if (board[0][0] == player && board[1][1] == player && board[2][2] == player) return true; + return board[0][2] == player && board[1][1] == player && board[2][0] == player; + } + + private void highlightWinner(char player) { + Color winColor = new Color(144, 238, 144); + + // Righe + for (int i = 0; i < 3; i++) { + if (board[i][0] == player && board[i][1] == player && board[i][2] == player) { + for (int j = 0; j < 3; j++) buttons[i][j].setBackground(winColor); + } + } + // Colonne + for (int i = 0; i < 3; i++) { + if (board[0][i] == player && board[1][i] == player && board[2][i] == player) { + for (int j = 0; j < 3; j++) buttons[j][i].setBackground(winColor); + } + } + // Diagonali + if (board[0][0] == player && board[1][1] == player && board[2][2] == player) { + for (int i = 0; i < 3; i++) buttons[i][i].setBackground(winColor); + } + if (board[0][2] == player && board[1][1] == player && board[2][0] == player) { + for (int i = 0; i < 3; i++) buttons[i][2-i].setBackground(winColor); + } + } + + private boolean isBoardFull() { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i][j] == ' ') return false; + } + } + return true; + } + + private void resetGame() { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + board[i][j] = ' '; + buttons[i][j].setText(""); + buttons[i][j].setBackground(Color.WHITE); + } + } + gameOver = false; + statusLabel.setText("Il tuo turno! (X)"); + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(TrisGame::new); + } +} \ No newline at end of file