Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
315fceb
Lay groundwork for simultaneous move support
ibrahim-mLq Apr 14, 2026
dcd87c9
one action - refactored for multiple players, but keeping the single …
ibrahim-mLq May 15, 2026
112d589
AbstractForwardModel next method, oneAction updated, getSimultaneousP…
ibrahim-mLq May 17, 2026
839402a
redundant functions removed -> refactored oneAction
ibrahim-mLq May 26, 2026
9bc0973
finally fixed the game loop and implemented simultaneous sushigo actions
ibrahim-mLq May 30, 2026
8de6b12
finally fixed the game loop and implemented simultaneous sushigo actions
ibrahim-mLq Jun 1, 2026
0e4d70a
Merge branch 'master' of https://github.com/GAIGResearch/TabletopGames
ibrahim-mLq Jun 1, 2026
17afa10
made pull request feedback changes
ibrahim-mLq Jun 4, 2026
b182f27
GameID now updated correctly when rerunning games from same state
hopshackle Jun 5, 2026
b2e2536
GameID now updated correctly when rerunning games from same state
hopshackle Jun 5, 2026
782d36b
GameID now updated correctly when rerunning games from same state
hopshackle Jun 5, 2026
b42932e
Corrected ACTION_TAKEN event publication in Game
hopshackle Jun 5, 2026
baaf557
Removed some excessive blank spaces
hopshackle Jun 5, 2026
176c4a7
TODO: Allow IExtendedSequence to be simultaneous
hopshackle Jun 5, 2026
593a3c0
llow IExtendedSequence to be simultaneous
hopshackle Jun 7, 2026
7cf0df6
Fixes for Simultaneous moves to pass unit tests
hopshackle Jun 8, 2026
5c8e611
Reversed out incorrect 'fix' for TunableParameters (caused unit test …
hopshackle Jun 8, 2026
fc4f6b0
Refactor to split out redeterminisation from copy
hopshackle Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ src/main/java/META-INF/MANIFEST.MF

src/pytag/env/
metrics/out/*
outputdir/*
treeRecorder*
.vscode/*
4 changes: 2 additions & 2 deletions json/config/RunGames/CantStopExample.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"game" : "CantStop",
"game" : "SushiGo",
"nPlayers" : 3,
"playerDirectory" : "CantStop_Agents/3P",
"mode" : "random",
"matchups" : 1000,
"matchups" : 100,
"verbose" : false,
"listener" : "GameResultsListener.json",
"destDir" : "SkillGrid_CantStop_3P",
Expand Down
10 changes: 10 additions & 0 deletions json/config/RunGames/backwards_comp_test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"game" : "SushiGo",
"nPlayers" : 2,
"mode" : "random",
"matchups" : 1000,
"verbose" : true,
"seed" : 740234,
"listener" : "json/listeners/basiclistener.json",
"destDir" : "outputdir"
}
38 changes: 32 additions & 6 deletions src/main/java/core/AbstractForwardModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import core.actions.AbstractAction;
import core.actions.ActionSpace;
import core.actions.DoNothing;
import core.actions.SimultaneousAction;
import core.interfaces.IPlayerDecorator;
import utilities.ActionTreeNode;
import utilities.ElapsedCpuChessTimer;
Expand All @@ -22,7 +23,7 @@ public AbstractForwardModel() {
}

/**
* Combines both super class and sub class setup methods. Called from the game loop.
* Combines both super class and subclass setup methods. Called from the game loop.
*
* @param firstState - initial state.
*/
Expand Down Expand Up @@ -73,12 +74,20 @@ protected void abstractSetup(AbstractGameState firstState) {
*
* @return - List of AbstractAction objects.
*/
protected List<AbstractAction> _computeAvailableActions(AbstractGameState gameState, int activePlayer) {
return _computeAvailableActions(gameState);
}

protected abstract List<AbstractAction> _computeAvailableActions(AbstractGameState gameState);

protected List<AbstractAction> _computeAvailableActions(AbstractGameState gameState, ActionSpace actionSpace) {
return _computeAvailableActions(gameState);
}

protected List<AbstractAction> _computeAvailableActions(AbstractGameState gameState, ActionSpace actionSpace, int activePlayer) {
return _computeAvailableActions(gameState, activePlayer);
}

protected abstract void endPlayerTurn(AbstractGameState state);

/**
Expand Down Expand Up @@ -131,9 +140,17 @@ public final void setup(AbstractGameState gameState) {
*/
public final void next(AbstractGameState currentState, AbstractAction action) {
if (action != null) {
int player = currentState.getCurrentPlayer();
currentState.recordAction(action, player);
if (action instanceof SimultaneousAction sa) {
for (Map.Entry<Integer, AbstractAction> entry : sa.getPlayerActions().entrySet()) {
currentState.recordAction(entry.getValue(), entry.getKey());
}
} else {
int player = currentState.getCurrentPlayer();
currentState.recordAction(action, player);
}

_next(currentState, action);

} else {
if (currentState.coreGameParameters.verbose) {
System.out.println("Invalid action.");
Expand All @@ -154,14 +171,23 @@ public final List<AbstractAction> computeAvailableActions(AbstractGameState game
}

public final List<AbstractAction> computeAvailableActions(AbstractGameState gameState, ActionSpace actionSpace) {
return computeAvailableActions(gameState, actionSpace, gameState.getCurrentPlayer());
}

public final List<AbstractAction> computeAvailableActions(AbstractGameState gameState, ActionSpace actionSpace, int activePlayer) {
// If there is an action in progress (see IExtendedSequence), then delegate to that
List<AbstractAction> retValue;
if (gameState.isActionInProgress()) {
retValue = gameState.actionsInProgress.peek()._computeAvailableActions(gameState, actionSpace);
// we call appropriate method depending on the actionSpace and move simultaneity
if (actionSpace != null && !actionSpace.isDefault()) {
retValue = gameState.actionsInProgress.peek()._computeAvailableActions(gameState, actionSpace, activePlayer);
} else {
retValue = gameState.getActionsInProgress().peek()._computeAvailableActions(gameState, activePlayer);
}
} else if (actionSpace != null && !actionSpace.isDefault()) {
retValue = _computeAvailableActions(gameState, actionSpace);
retValue = _computeAvailableActions(gameState, actionSpace, activePlayer);
} else {
retValue = _computeAvailableActions(gameState);
retValue = _computeAvailableActions(gameState, activePlayer);
}
return retValue;
}
Expand Down
25 changes: 21 additions & 4 deletions src/main/java/core/AbstractGameState.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,20 @@ public final AbstractParameters getGameParameters() {
* in child classes if relevant to the game
*/
public int getTeam(int player) { return player;}

public int getCurrentPlayer() {
return isActionInProgress() ? actionsInProgress.peek().getCurrentPlayer(this) : turnOwner;
}

/**
* This method returns a list of the players in a game state that has simultaneous moves
*/
public List<Integer> getCurrentSimultaneousPlayers(){
return isActionInProgress() ?
actionsInProgress.peek().getCurrentSimultaneousPlayers(this) :
Collections.singletonList(getCurrentPlayer());
}

public final CoreConstants.GameResult[] getPlayerResults() {return playerResults;}
public final Set<Integer> getWinners() {
Set<Integer> winners = new HashSet<>();
Expand All @@ -160,10 +171,6 @@ public final GameType getGameType() {
return gameType;
}


protected void setHistoryAt(int index, Pair<Integer, AbstractAction> action) {
history.set(index, action);
}
/**
* @return All actions that have been executed on this state since reset()/initialisation
*/
Expand Down Expand Up @@ -334,6 +341,9 @@ public final AbstractGameState copy(int playerId) {
s.playerTimer[i] = playerTimer[i].copy();
}

if (playerId != -1 && coreGameParameters.partialObservable) {
s.redeterminise(playerId);
}
// Update the list of components for ID matching in actions.
s.addAllComponents();
return s;
Expand All @@ -349,6 +359,13 @@ protected final void recordAction(AbstractAction action, int player) {
historyText.add("Player " + player + " : " + action.getString(this));
}

/**
* Override with logic to redeterminise the game state from the perspective of the specified player
* @param playerId
*/
public void redeterminise(int playerId) {
// do nothing as the default
}

// helper function to avoid time-consuming string manipulations if the message is not actually
// going to be logged anywhere
Expand Down
Loading