Skip to content

Commit 5c32417

Browse files
Merge pull request #24 from briancorbinxyz/jdk24
JDK24
2 parents 896cda4 + bdce1cd commit 5c32417

File tree

64 files changed

+1760
-278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1760
-278
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ Cargo.lock
3434
# and can be added to the global gitignore or merged into this file. For a more nuclear
3535
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
3636
#.idea/
37-
bin/
37+
*/bin/
3838
native/src/main/resources/native/
39+
buildSrc/.kotlin

.idea/.gitignore

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/compiler.xml

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/kotlinc.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/material_theme_project_new.xml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules/api/overengineering-tictactoe.api.test.iml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vscode/launch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
"name": "App",
9898
"request": "launch",
9999
"mainClass": "org.xxdc.oss.example.App",
100+
"vmArgs": "-XX:+UseZGC --enable-preview",
100101
"projectName": "app",
101102
},
102103
{

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"workingDirectory": "${workspaceFolder}",
77
"vmArgs": [
88
"--enable-native-access=ALL-UNNAMED",
9-
"-Djava.library.path=${env:LIB_PATH}",
9+
"-Djava.library.path=${env:LIB_PATH}"
1010
],
1111
"env": {
1212
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ Over-Engineering Tic-Tac-Toe
55

66
Tic-Tac-Toe in Java deliberately over-engineered to apply features of Java introduced over time.
77

8-
Developed to pair with the ongoing blog post: [Road to JDK 25 - Over-Engineering Tic-Tac-Toe](https://thelifeof.briancorbin.xyz/Library/03-Resources/Road-to-JDK-25---Over-Engineering-Tic-Tac-Toe!) also serialized to Medium @ [Road to JDK 25 - Over-Engineering Tic-Tac-Toe On Medium](https://briancorbinxyz.medium.com/list/road-to-jdk-25-d0f656f66a8f)
8+
Developed to pair with the ongoing blog post: [Road to JDK 25 - Over-Engineering Tic-Tac-Toe](https://sympatheticengineering.com/Library/03-Resources/Road-to-JDK-25---Over-Engineering-Tic-Tac-Toe!) also serialized to Medium @ [Road to JDK 25 - Over-Engineering Tic-Tac-Toe On Medium](https://briancorbinxyz.medium.com/list/road-to-jdk-25-d0f656f66a8f)
99

1010
---
1111

1212
### Features
1313

14+
https://openjdk.org/projects/jdk/24/
15+
- **JEP496**: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
16+
- **JEP485**: Stream Gatherers
17+
- **JEP483**: Ahead-of-Time Class Loading & Linking
18+
- **JEP484**: Class-File API
19+
1420
https://openjdk.org/projects/jdk/23/
1521

1622
- **JEP467**: Markdown Documentation Comments
@@ -73,7 +79,7 @@ The following algorithms are used by the AI BOT in this project - for a detailed
7379

7480
- To run the single game application, use the following command: `./gradlew run`
7581

76-
- If you don't have Java 23 installed on your system you can install it first with [SDKMAN](https://sdkman.io/):
82+
- If you don't have Java installed on your system you can install it first with [SDKMAN](https://sdkman.io/) to build with a JDK 24 toolchain:
7783

7884
```bash
7985
curl -s "https://get.sdkman.io" | bash

api/build.gradle.kts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ dependencies {
2424
testRuntimeOnly("org.slf4j:slf4j-api:2.0.13")
2525
testRuntimeOnly("org.slf4j:slf4j-jdk-platform-logging:2.0.13")
2626

27-
2827
// JDK23: JMH (Third-Party) Not required, added for benchmarking
2928
// https://github.com/openjdk/jmh
3029
testImplementation("org.openjdk.jmh:jmh-core:1.37")
@@ -90,12 +89,37 @@ publishing {
9089
}
9190
}
9291

93-
tasks.withType<Test>().all {
94-
// JDK22: Foreign Function Interface (FFI)
95-
// Resolves Warning:
96-
// WARNING: A restricted method in java.lang.foreign.SymbolLookup has been called
97-
// WARNING: java.lang.foreign.SymbolLookup::libraryLookup has been called by org.xxdc.oss.example.GameBoardNativeImpl in an unnamed module
98-
// WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
99-
// WARNING: Restricted methods will be blocked in a future release unless native access is enabled
100-
jvmArgs = listOf("--enable-native-access=ALL-UNNAMED", "-XX:+UseZGC")
92+
// TODO: Disable preview features on the branch when the next JDK is released
93+
val enablePreviewFeatures = true
94+
95+
val collectorArgs = listOf(
96+
"-XX:+UseZGC"
97+
)
98+
val standardArgs = listOf(
99+
"--enable-native-access=ALL-UNNAMED",
100+
) + collectorArgs
101+
102+
tasks.named<Test>("test") {
103+
jvmArgs = if (enablePreviewFeatures) {
104+
listOf("--enable-preview") + standardArgs
105+
} else {
106+
standardArgs
107+
}
108+
}
109+
110+
if (enablePreviewFeatures) {
111+
tasks.withType<JavaCompile>().configureEach {
112+
options.compilerArgs.addAll(listOf("--enable-preview"))
113+
}
114+
115+
tasks.withType<JavaExec>().configureEach {
116+
jvmArgs("--enable-preview")
117+
}
118+
119+
tasks.withType<Javadoc>() {
120+
(options as StandardJavadocDocletOptions).apply {
121+
addBooleanOption("-enable-preview", true)
122+
source = "24"
123+
}
124+
}
101125
}

api/src/main/java/org/xxdc/oss/example/Game.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import java.util.ArrayDeque;
1010
import java.util.Deque;
1111
import java.util.Optional;
12+
import java.util.SequencedCollection;
1213
import java.util.UUID;
14+
import java.util.function.Consumer;
1315

1416
/**
1517
* Represents a game of Tic-Tac-Toe, including the game board, players, and game state. The game can
@@ -76,12 +78,35 @@ public static Game from(File gameFile) throws IOException, ClassNotFoundExceptio
7678
return persistence.loadFrom(gameFile);
7779
}
7880

81+
/**
82+
* Constructs a new {@link Game} instance with a 3x3 game board, persistence disabled, and a bot
83+
* player as player 'X' and a bot player as player 'O'.
84+
*/
85+
public static Game ofBots() {
86+
return new Game(
87+
3,
88+
false,
89+
new PlayerNode.Local<>("X", new BotPlayer()),
90+
new PlayerNode.Local<>("O", new BotPlayer()));
91+
}
92+
7993
/**
8094
* Plays the game, rendering the board, applying player moves, and persisting the game state if
8195
* enabled. The game continues until a winning player is found or there are no more moves
8296
* available, at which point the winner or tie is logged.
8397
*/
8498
public void play() {
99+
playWithAction(null);
100+
}
101+
102+
/**
103+
* Plays the game, rendering the board, applying player moves, and persisting the game state if
104+
* enabled. The game continues until a winning player is found or there are no more moves
105+
* available, at which point the winner or tie is logged.
106+
*
107+
* @param postMoveAction The action to perform after a move is made (if any)
108+
*/
109+
public void playWithAction(Consumer<Game> postMoveAction) {
85110
try {
86111
GamePersistence persistence = new GamePersistence();
87112
File persistenceDir = gameFileDirectory();
@@ -104,6 +129,9 @@ public void play() {
104129
winningPlayer = checkWon(state);
105130
movesAvailable = state.hasMovesAvailable();
106131
currentPlayer = playerNodes.byIndex(state.currentPlayerIndex());
132+
if (postMoveAction != null) {
133+
postMoveAction.accept(this);
134+
}
107135
}
108136

109137
winningPlayer.ifPresentOrElse(
@@ -116,6 +144,49 @@ public void play() {
116144
}
117145
}
118146

147+
/**
148+
* Returns the unique identifier for this game instance (Deprecated).
149+
*
150+
* @return the game ID
151+
* @deprecated use {@link #id()} instead
152+
*/
153+
@Deprecated(since = "1.5.0", forRemoval = true)
154+
public UUID getGameId() {
155+
return gameId;
156+
}
157+
158+
/**
159+
* Returns the unique identifier for this game instance.
160+
*
161+
* @return the game ID
162+
*/
163+
public UUID id() {
164+
return gameId;
165+
}
166+
167+
@Override
168+
public void close() throws Exception {
169+
playerNodes.close();
170+
}
171+
172+
/**
173+
* Returns the number of players in the game.
174+
*
175+
* @return the number of players
176+
*/
177+
public int numberOfPlayers() {
178+
return playerNodes.playerMarkerList().size();
179+
}
180+
181+
/** Returns the history of the game, including all moves made. */
182+
public SequencedCollection<GameState> history() {
183+
return gameState;
184+
}
185+
186+
public int moveNumber() {
187+
return moveNumber;
188+
}
189+
119190
private Optional<String> checkWon(GameState state) {
120191
return state.lastMove() > -1 && state.lastPlayerHasChain()
121192
? Optional.of(state.playerMarkers().get(state.lastPlayerIndex()))
@@ -135,20 +206,6 @@ private GameState pushGameState(GameState state) {
135206
return state;
136207
}
137208

138-
/**
139-
* Returns the unique identifier for this game instance.
140-
*
141-
* @return the game ID
142-
*/
143-
public UUID getGameId() {
144-
return gameId;
145-
}
146-
147-
@Override
148-
public void close() throws Exception {
149-
playerNodes.close();
150-
}
151-
152209
private void renderBoard() {
153210
log.log(Level.INFO, "\n" + currentGameState().board());
154211
}

api/src/main/java/org/xxdc/oss/example/GameBoard.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ default boolean isEmpty() {
5252
return true;
5353
}
5454

55+
/**
56+
* Checks if the given player is present at the given location on the game board.
57+
*
58+
* @param playerMarker the marker representing the player to check
59+
* @param location the location on the game board to check
60+
* @return true if the player is present at the given location, false otherwise
61+
*/
62+
boolean hasPlayer(String playerMarker, int location);
63+
5564
/**
5665
* Checks if the given player has a winning chain of connected game pieces on the game board.
5766
*

api/src/main/java/org/xxdc/oss/example/GameBoardLocalImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ public GameBoard clone() {
144144
return new GameBoardLocalImpl(dimension, getBoardCopy());
145145
}
146146

147+
@Override
148+
public boolean hasPlayer(String playerMarker, int location) {
149+
return location >= 0
150+
&& location < content.length
151+
&& content[location] != null
152+
&& content[location].equals(playerMarker);
153+
}
154+
147155
private String[] getBoardCopy() {
148156
String[] boardCopy = new String[dimension * dimension];
149157
System.arraycopy(content, 0, boardCopy, 0, boardCopy.length);

api/src/main/java/org/xxdc/oss/example/GameState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public boolean lastPlayerHasChain() {
149149
* @return the last player's marker
150150
* @throws GameServiceException if there is no last move or the board is empty
151151
*/
152-
private String lastPlayer() {
152+
public String lastPlayer() {
153153
if (lastMove < 0 || board.isEmpty()) {
154154
throw new GameServiceException("null last player");
155155
}

0 commit comments

Comments
 (0)