better human/ai selector with bot selection and depth on TicTacToeAIR

This commit is contained in:
michiel
2025-12-04 14:31:04 +01:00
parent a00d25f24a
commit 134c9a2fd8
18 changed files with 113 additions and 50 deletions

View File

@@ -199,7 +199,7 @@ public final class Server {
switch (type){ switch (type){
case TICTACTOE ->{ case TICTACTOE ->{
players[myTurn] = new ArtificialPlayer<>(new TicTacToeAIR(), user); players[myTurn] = new ArtificialPlayer<>(new TicTacToeAIR(9), user);
} }
case REVERSI ->{ case REVERSI ->{
players[myTurn] = new ArtificialPlayer<>(new ReversiAIR(), user); players[myTurn] = new ArtificialPlayer<>(new ReversiAIR(), user);

View File

@@ -5,10 +5,13 @@ import org.toop.app.widget.Primitive;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
public class PlayerInfoWidget { public class PlayerInfoWidget {
private final GameInformation.Player information; private final GameInformation.Player information;
private final VBox container; private final VBox container;
private Text playerName;
private boolean hasSet;
public PlayerInfoWidget(GameInformation.Player information) { public PlayerInfoWidget(GameInformation.Player information) {
this.information = information; this.information = information;
@@ -16,6 +19,7 @@ public class PlayerInfoWidget {
buildToggle().getNode(), buildToggle().getNode(),
buildContent() buildContent()
); );
this.playerName = null;
} }
private ToggleWidget buildToggle() { private ToggleWidget buildToggle() {
@@ -43,11 +47,13 @@ public class PlayerInfoWidget {
return nameInput.getNode(); return nameInput.getNode();
} else { } else {
if (information.name == null || information.name.isEmpty()) { var AIBox = Primitive.vbox(
information.name = "Pism Bot"; makeAIButton(0, 1, "zwartepiet"),
} makeAIButton(2, 1, "sinterklaas"),
makeAIButton(9, 1, "santa")
);
var playerName = Primitive.text(""); this.playerName = Primitive.text("");
playerName.setText(information.name); playerName.setText(information.name);
var nameDisplay = Primitive.vbox( var nameDisplay = Primitive.vbox(
@@ -55,29 +61,45 @@ public class PlayerInfoWidget {
playerName playerName
); );
var difficultySlider = new LabeledSliderWidget( if (!hasSet) {
"computer-difficulty", doDefault();
0, 5, hasSet = true;
information.computerDifficulty, }
newVal -> information.computerDifficulty = newVal
);
var thinkTimeSlider = new LabeledSliderWidget(
"computer-think-time",
0, 5,
information.computerThinkTime,
newVal -> information.computerThinkTime = newVal
);
return Primitive.vbox( return Primitive.vbox(
nameDisplay, AIBox,
difficultySlider.getNode(), nameDisplay
thinkTimeSlider.getNode()
); );
} }
} }
public Node getNode() { public Node getNode() {
return container; return container;
} }
private Node makeAIButton(int depth, int thinktime, String name) {
return Primitive.button(name, () -> {
information.name = getName(name);
information.computerDifficulty = depth;
information.computerThinkTime = thinktime;
this.playerName.setText(getName(name));
});
}
private String getName(String name) {
return switch (name) {
case "sinterklaas" -> "Sint. R. Klaas";
case "zwartepiet" -> "Zwarte Piet";
case "santa" -> "Santa";
default -> "Default";
};
}
private void doDefault() {
information.name = getName("zwartepiet");
information.computerDifficulty = 0;
information.computerThinkTime = 1;
this.playerName.setText(getName("zwartepiet"));
}
} }

View File

@@ -52,12 +52,12 @@ public class LocalMultiplayerView extends ViewWidget {
if (information.players[0].isHuman) { if (information.players[0].isHuman) {
players[0] = new LocalPlayer<>(information.players[0].name); players[0] = new LocalPlayer<>(information.players[0].name);
} else { } else {
players[0] = new ArtificialPlayer<>(new TicTacToeAIR(), information.players[0].name); players[0] = new ArtificialPlayer<>(new TicTacToeAIR(information.players[0].computerDifficulty), information.players[0].name);
} }
if (information.players[1].isHuman) { if (information.players[1].isHuman) {
players[1] = new LocalPlayer<>(information.players[1].name); players[1] = new LocalPlayer<>(information.players[1].name);
} else { } else {
players[1] = new ArtificialPlayer<>(new TicTacToeAIR(), information.players[1].name); players[1] = new ArtificialPlayer<>(new TicTacToeAIR(information.players[1].computerDifficulty), information.players[1].name);
} }
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstTTT()) { if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstTTT()) {
new ShowEnableTutorialWidget( new ShowEnableTutorialWidget(

View File

@@ -86,6 +86,9 @@ tutorialstring=\u0627\u0644\u062f\u0631\u0633 \u0627\u0644\u062a\u0648\u0636\u06
startgame=\u0627\u0628\u062f\u0623 \u0627\u0644\u0644\u0639\u0628\u0629! startgame=\u0627\u0628\u062f\u0623 \u0627\u0644\u0644\u0639\u0628\u0629!
goback=\u0627\u0631\u062c\u0639 goback=\u0627\u0631\u062c\u0639
turnof=\u062F\u0648\u0631\u0647 turnof=\u062F\u0648\u0631\u0647
zwartepiet=\u0633\u0647\u0644: Zwarte Piet
sinterklaas=\u0645\u062a\u0648\u0633\u0637: Sint R. Klaas
santa=\u0635\u0639\u0628: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629

View File

@@ -88,6 +88,9 @@ tutorialstring=Tutorial
startgame=Spiel starten! startgame=Spiel starten!
goback=Zur<EFBFBD>ck goback=Zur<EFBFBD>ck
turnof=ist dran turnof=ist dran
zwartepiet=Leicht: Zwarte Piet
sinterklaas=Mittel: Sint R. Klaas
santa=Schwer: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
chinese=\u4e2d\u6587 (Chinesisch) chinese=\u4e2d\u6587 (Chinesisch)

View File

@@ -89,6 +89,9 @@ tutorialstring=Tutorial
startgame=Start game! startgame=Start game!
goback=Go back goback=Go back
turnof='s turn turnof='s turn
zwartepiet=Easy: Zwarte Piet
sinterklaas=Medium: Sint R. Klaas
santa=Hard:Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabic) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabic)
chinese=\u4e2d\u6587 (Chinese) chinese=\u4e2d\u6587 (Chinese)

View File

@@ -87,7 +87,9 @@ tutorialstring=Tutorial
startgame=\u00a1Iniciar juego! startgame=\u00a1Iniciar juego!
goback=Volver goback=Volver
turnof=le toca turnof=le toca
zwartepiet=F\u00e1cil: Zwarte Piet
sinterklaas=Medio: Sint R. Klaas
santa=Dif\u00edcil: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Ar\u00e1bigo) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Ar\u00e1bigo)
chinese=\u4e2d\u6587 (Chino) chinese=\u4e2d\u6587 (Chino)

View File

@@ -87,6 +87,9 @@ tutorialstring=Tutoriel
startgame=D\u00e9marrer le jeu! startgame=D\u00e9marrer le jeu!
goback=Retour goback=Retour
turnof=\u00E0 son tour turnof=\u00E0 son tour
zwartepiet=Facile: Zwarte Piet
sinterklaas=Moyen : Sint R. Klaas
santa=Difficile: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabe) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabe)
chinese=\u4e2d\u6587 (Chinois) chinese=\u4e2d\u6587 (Chinois)

View File

@@ -87,6 +87,9 @@ tutorialstring=\u0924\u0942\u091f\u0949\u0930\u093f\u092f\u0932
startgame=\u0916\u0947\u0932 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902! startgame=\u0916\u0947\u0932 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902!
goback=\u0935\u093e\u092a\u0938 \u091c\u093e\u090f\u0901 goback=\u0935\u093e\u092a\u0938 \u091c\u093e\u090f\u0901
turnof=\u0915\u0940 \u092C\u093E\u0930\u0940 turnof=\u0915\u0940 \u092C\u093E\u0930\u0940
zwartepiet=\u0905\u0938\u093e\u0928: Zwarte Piet
sinterklaas=\u092e\u0927\u094d\u092f\u092e: Sint R. Klaas
santa=\u0915\u0924\u093f\u0928: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0905\u0930\u092c\u0940) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0905\u0930\u092c\u0940)
chinese=\u4e2d\u6587 (\u091a\u0940\u0928\u0940) chinese=\u4e2d\u6587 (\u091a\u0940\u0928\u0940)

View File

@@ -86,6 +86,9 @@ tutorialstring=Tutorial
startgame=Avvia il gioco! startgame=Avvia il gioco!
goback=Indietro goback=Indietro
turnof=\u00E8 il suo turno turnof=\u00E8 il suo turno
zwartepiet=Facile: Zwarte Piet
sinterklaas=Medio: Sint R. Klaas
santa=Difficile: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabo) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabo)
chinese=\u4e2d\u6587 (Cinese) chinese=\u4e2d\u6587 (Cinese)

View File

@@ -86,6 +86,9 @@ tutorialstring=\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb
startgame=\u30b2\u30fc\u30e0\u3092\u958b\u59cb\uff01 startgame=\u30b2\u30fc\u30e0\u3092\u958b\u59cb\uff01
goback=\u623b\u308b goback=\u623b\u308b
turnof=\u306E\u756A turnof=\u306E\u756A
zwartepiet=\u7c21\u5358: Zwarte Piet
sinterklaas=\u4e2d\u7d1a: Sint R. Klaas
santa=\u96e3\u3057\u3044: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u30a2\u30e9\u30d3\u30a2\u8a9e) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u30a2\u30e9\u30d3\u30a2\u8a9e)
chinese=\u4e2d\u6587 (\u4e2d\u6587) chinese=\u4e2d\u6587 (\u4e2d\u6587)

View File

@@ -86,6 +86,9 @@ tutorialstring=\ud14c\ud2b8\ub9ad
startgame=\uac8c\uc784 \uc2dc\uc791! startgame=\uac8c\uc784 \uc2dc\uc791!
goback=\ub4a4\ub85c \uac00\uae30 goback=\ub4a4\ub85c \uac00\uae30
turnof=\uC758 \uCC28\uB840 turnof=\uC758 \uCC28\uB840
zwartepiet=\uc218\uc601: Zwarte Piet
sinterklaas=\ubcf4\ud1b5: Sint R. Klaas
santa=\uc5d0\uc18c: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0639\u0631\u0628\u064a\u0629) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0639\u0631\u0628\u064a\u0629)
chinese=\u4e2d\u6587 (\u4e2d\u6587) chinese=\u4e2d\u6587 (\u4e2d\u6587)

View File

@@ -86,6 +86,9 @@ tutorialstring=Tutorial
startgame=Spel starten! startgame=Spel starten!
goback=Ga terug goback=Ga terug
turnof=is aan de beurt turnof=is aan de beurt
zwartepiet=Makkelijk: Zwarte Piet
sinterklaas=Gemiddeld: Sint R. Klaas
santa=Moeilijk: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
chinese=\u4e2d\u6587 (Chinees) chinese=\u4e2d\u6587 (Chinees)

View File

@@ -86,6 +86,9 @@ tutorialstring=\u0423\u0447\u0435\u0431\u043d\u0438\u043a
startgame=\u041d\u0430\u0447\u0430\u0442\u044c \u0438\u0433\u0440\u0443! startgame=\u041d\u0430\u0447\u0430\u0442\u044c \u0438\u0433\u0440\u0443!
goback=\u041d\u0430\u0437\u0430\u0434 goback=\u041d\u0430\u0437\u0430\u0434
turnof=\u0445\u043E\u0434\u0438\u0442 turnof=\u0445\u043E\u0434\u0438\u0442
zwartepiet=\u041b\u0435\u0433\u043a\u043e: Zwarte Piet
sinterklaas=\u0421\u0440\u0435\u0434\u043d\u0438\u0439: Sint R. Klaas
santa=\u0421\u043b\u043e\u0436\u043d\u043e: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0410\u0440\u0430\u0431\u0441\u043a\u0438\u0439) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0410\u0440\u0430\u0431\u0441\u043a\u0438\u0439)
chinese=\u4e2d\u6587 (\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439) chinese=\u4e2d\u6587 (\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439)

View File

@@ -86,6 +86,9 @@ tutorialstring=\u6559\u7a0b
startgame=\u5f00\u59cb\u6e38\u620f\uff01 startgame=\u5f00\u59cb\u6e38\u620f\uff01
goback=\u8fd4\u56de goback=\u8fd4\u56de
turnof=\u7684\u56DE\u5408 turnof=\u7684\u56DE\u5408
zwartepiet=\u7b80\u5355: Zwarte Piet
sinterklaas=\u4e2d\u7b49: Sint R. Klaas
santa=\u56f0\u96be: Santa
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u963f\u62c9\u4f2f\u8bed) arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u963f\u62c9\u4f2f\u8bed)
chinese=\u4e2d\u6587 chinese=\u4e2d\u6587

View File

@@ -26,9 +26,15 @@ public final class TicTacToeAIR extends AbstractAI<TicTacToeR> {
* @param game the current Tic-Tac-Toe game state * @param game the current Tic-Tac-Toe game state
* @param depth the depth of lookahead for evaluating moves (non-negative) * @param depth the depth of lookahead for evaluating moves (non-negative)
* @return the index of the best move, or -1 if no moves are available * @return the index of the best move, or -1 if no moves are available
*
*/ */
private int depth;
public TicTacToeAIR(int depth) {
this.depth = depth;
}
public int getMove(TicTacToeR game) { public int getMove(TicTacToeR game) {
int depth = 9;
assert game != null; assert game != null;
final int[] legalMoves = game.getLegalMoves(); final int[] legalMoves = game.getLegalMoves();

View File

@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.*;
final class TicTacToeAIRTest { final class TicTacToeAIRTest {
private final TicTacToeAIR ai = new TicTacToeAIR(); private final TicTacToeAIR ai = new TicTacToeAIR(9);
// Helper: play multiple moves in sequence on a fresh board // Helper: play multiple moves in sequence on a fresh board
private TicTacToeR playSequence(int... moves) { private TicTacToeR playSequence(int... moves) {