Tris MiniMax
This commit is contained in:
30
TrisMiniMax/.gitignore
vendored
Normal file
30
TrisMiniMax/.gitignore
vendored
Normal file
@@ -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
|
||||
8
TrisMiniMax/.idea/.gitignore
generated
vendored
Normal file
8
TrisMiniMax/.idea/.gitignore
generated
vendored
Normal file
@@ -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
|
||||
6
TrisMiniMax/.idea/misc.xml
generated
Normal file
6
TrisMiniMax/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
TrisMiniMax/.idea/modules.xml
generated
Normal file
8
TrisMiniMax/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/TrisMiniMax.iml" filepath="$PROJECT_DIR$/TrisMiniMax.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
TrisMiniMax/.idea/vcs.xml
generated
Normal file
6
TrisMiniMax/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
11
TrisMiniMax/TrisMiniMax.iml
Normal file
11
TrisMiniMax/TrisMiniMax.iml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
221
TrisMiniMax/src/TrisGame.java
Normal file
221
TrisMiniMax/src/TrisGame.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user