From b3e29a32620f014dfe45ca512b649c230e20e3e0 Mon Sep 17 00:00:00 2001 From: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> Date: Sun, 25 Jan 2026 12:13:21 +0100 Subject: [PATCH] Demo 7 (#314) * Changed pom to be correct. Fixed SnowflakeGenerator not making unique ids. Changed naming for event implementation. Automated id getter for events. Added Error-Prone to all modules. Added parents to all modules. Added processors module. * SoundEffectManager now generic * Removed ResourceManager from AudioManagers * Added linelistener to SoundEffectAsset * commit * commit ofzo * Tests for SoundEffectManager * getLegalMoves logic seems fixed //todo write better tests * Tests toegevoegd * punk toegevoegd * Added shuffling on user request * Reworked NetworkingClientManager into SRP model. * Forgot to remove * Improved API for dependency injection * Some better docs. * gui refactor * fixed merge conflicts * Added exceptions. Added reconnect attempts and changeable address * Fixed event bug * add: reversi game * add: server chat box * visual update * Refactor to make Events easier to work with. * Quick fix for closing connection. * Documentation * Correct client creation and user polling * begin van audio display * Polling music event, fires every 1 second * Updated test. * Updated timings * Nuke everything on close. * Basis Audio Display toegevoegd + standaard CSS toegevoegd Kan nu zien hoe lang de song duurt, hoe lang ie al bezig is met draaien en de titel (-.mp3) * Clips now also return positional information * Skip Button * Skip Button * Fixes for garbage code by Omar * Tiny fix when natural skip * Small event fix * Faster event schedule for PlayingMusic event * test fix * added method for sorting the flipped pieces by distance to Move.position * new reversi test (both players no legal moves) * connect4 with minimax AI * Toegevoegd: -Play Button + CSS + Events -Previous Button + CSS + Events -Changed interface for AudioResource to include a pause button which works really well with mediaplayer, however now SoundEffectAsset has an unnessescary pause * Made it so that it indicates with the play/pause button if its paused or played * add simple flip animations and fixed(?) server somewhat * fixed tests * can start game from playerlist screen * tourney ready * spam minder * fixed setgamelabels * spam minder v2 * canvas changes * moved score out of game * can now go to last using previous and being at the first song * mainview false for sendchallengeview * moved score out of game * kleine ui fix * updated music ma,es * started working on the widget system * iets met timing verkeerd temporary fix * Fixes for garbage code by Omar * Added replace to reduce boiler plate code * Manually fallback to the fallback locale when a ResourceBundle is missing a resource key. Fallsback to "MISSING RESOUREC" if it's not present in the fallback. * Removed unused import and unused parameter * cool onhover effect for reversi * Made the GameState enum it's own file and fixed imports * Removed unused import * Turned abstract methods into an interface * Moved the Move record into it's own file, seperated from Game * Removed unused imports * Renamed Interface Playtable to IPlayable * Turned Abstract Method for AI into interface * Refactored Game to follow encapsulation principle * Removed unused imports * Applied encapsulation principle to TurnBasedBame.java * Privated methods that didn't have to be public * Reversi: made method private * Changed checkForEarlyDraw so it doesn't need a game as input. * Fixed warning "Warning:(27, 12) Copy constructor does not copy field 'mostRecentlyFlippedPieces'", removed unused field * Made connect4 public method private * half done with the widget system * added some comments and made some methods a bit more readable * widget system almost complete * Functional code, is now object orientated * Removed no more needed comments * started a basis for the tutorials, tic tac toe is almost done with some general stuff still to do. * rest van de tutorials toegevoegd * resizable true * fixed turn skip bug fixed end score bug now only shows legal and highlight moves when human * Squashed commit of the following: commit a517f2f302baa89f8ef59946a31c7bb59c56770f Author: Stef Date: Thu Nov 27 15:43:43 2025 +0100 Make it so the game shows "Waiting on ... to make their move". Styling isn't done but it is easier to see who's turn it is. There is a lot of structuring to do in the previous code... * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Fixed compilation errors * Changed the way turns are being stored in TurnBasedGame. * Removed views * Added function input for enabling/disabling localization p/text * Fix eventbus problems (#265) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Debugs for EventBus and fixed unsubscribe all (#266) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Fix music display not working (#267) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Added LoadingWidget.java for server feedback * Replace deprecated with correct function * Removed loading widget from Server.java * Fixed old new EventFlow().listen() missing false as third param * Tutorials to Dev (#264) * Fixed garbage code * added a pop button * Tutorial images now use ImageAsset.java * Added button to continue and start game. Refactors * Refactored nextScreen runnable * Removed unused imports * Refactored switch statement * Added documentation * Removed space * Added translations * Added function input for enabling/disabling localization p/text --------- Co-authored-by: ramollia <> * Merge new framework into development (#269) * Created a somewhat generic TurnBasedGame thread. Temporary UI that only works for TicTacToe rn. Added a LocalPlayer with the intent to add more players * (RANDOM COMMIT) Hope it works * Changes by bas * Fixed dependency issues * Fixed major issue in game deepcopy * Merge conflict fix * Removed unused import * Update GTBGT branch from dev branch (#263) * started a basis for the tutorials, tic tac toe is almost done with some general stuff still to do. * rest van de tutorials toegevoegd * Removed views * Merge conflict fix * Removed unused import --------- Co-authored-by: michiel301b Co-authored-by: ramollia <> Co-authored-by: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> * Revert "Update GTBGT branch from dev branch (#263)" This reverts commit 9134d7e3432a9e35cf6ae9a49c9d7940581677cd. * Fixed frontend not using GameController because of spaghetti code. * Removed unused imports * GameCanvas not implements a DrawPlayerMove that can be overridden for specific implementations * Created an event that will request the controller to refresh the UI. * ADDED DEPENDENCY. Renamed GameControllers to GameManagers, gameThread is not game controller. * Attempt at adding an online player. I think it doesn't work because of unsubscriben after success not working * Multiplayer is functional through OnlineThreadBehaviour. Empty slots are currently represented by -1 in the GUI. * Removed sout spam, added logger than I can't get to work. * Idek what these changes are * Te lang geen commit, sorry * Multiplayer seems to work pretty well now, hopefully I can add the other games soon. * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Inbetween commit of adding Reversi. This is a lot of spaghetti. * Fixed stress tests * Fixed typo in NetworkingGameClientHandler that prevented losses from being received * Missed 2nd typo. Fixed * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Works now with updated EventFlow(). Unsubscribing works. ReversiAIR has an issue where a forced move returns -1 and local play back button doesn't work properly. To be fixed * Fixed ReversiR issue that caused skip turn desync * Fixed color mismatch with server and online main player is now correct. * Added a bunch of java doc and small changes * Small changes * Added a new Thread Behaviour to test framework. * Fixed human error I made in TicTacToeR logic... * Fixed broken event and wrong player being presented as winner. * Idk changes * Fixed PR conflicts --------- Co-authored-by: michiel301b Co-authored-by: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> * added back button sounds because SOMEONE fucked it up..... * 231 connecting to server feedback (#275) * Added unsubscribe to EventFlow. ListenerHandler now functional. GlobalEventbus now user listenerHandler * getAllListeners * Removed nulls * Fixed stress tests * Added docs, no more list creation when adding events to the bus. * Fixed unsubscribe not working. * Moved away from deprecated functions * moved from wildcard to typed * Moved away from deprecated function * Added debugging to GlobalEventBus * Fixed cleaning flow * Fixed unsubscribe all * Fixed unsubscribe all * Removed unused import * Added LoadingWidget.java for server feedback * Imports * fixed loadingwidget * Workable LoadingWidget and trying to connect to server * Removed output * Small bug temp fix --------- Co-authored-by: ramollia <> * Double loading call fix, LoadingWidget docs * Main menu loader (#277) * LoadingWidget main menu * fixed garbage code * Fixed garbage code 2 * LoadWidget fix, added loading to starting the game. Removed unnecessary console output --------- Co-authored-by: ramollia <> * Fixed systems starting, before assets being loaded (I am retarded) * Added infinite boolean, fixed loading behaviour at startup * 272 remake game framework interfaces to properly represent vmc (#278) * Cleaned up a lot of old files and renamed/remade interfaces to better suit the framework * Broken commit * Fixed online play * Better file structure and closer to MVC * Best fix for white screen at start * Making threads verbose regarding exceptions * Loading circle, better loading colors. * Event bus now testable, improved UI (#284) * turn updates * smalle fixes aan turn updates * better human/ai selector with bot selection and depth on TicTacToeAIR * depth + thinktime back to AIs, along with a a specific TicTacToeAIRSleep * fixed overlapping back and disconnect buttons * Changed to debug instead of info * changed the transitionNextCustom to be easier to use * added getAllWidgets to WidgetContainer * Correct back view * added replacePrevious in ViewWidget * added removeIndexFromPreviousChain * fixed incorrect index counting * Fixt wrong view order * Removed todo * Challenge popups "Fixed" * Popups now remove themselves * localize the ChallengePopup text * made the game text a header instead * fixed getAllWidgets * Escape popup * fixed redundant container * Escape remove popup * Working escape menu * Added find functionality * Tutorials moved to escape menu * Escape can't be opened in mainview now * Can now test the event bus, created testable interfaces * Logging errors * Made events and handlers more generic * Suppress * Managers now have changeable eventbus * Tutorials fixed * Removed import * Single threaded eventbus * Fixed wrong eventbus * Removed get * Removed old code * Renaming * Optimization * Removed useless comment * Removed unnecessary imports * Rename * Renaming, refactor and type safety * Rename * Removed import --------- Co-authored-by: michiel301b Co-authored-by: ramollia <> * initSystems now uses latch instead of timer. Moved single threads to Executor * Safety * Deleted unnecessary imports * Code cleanup * changed "fullscreen exit key combination" from esc to F11 * shitty fix for player selector spacing issue * shitty fix for player selector spacing issue v2 * fixed reversi colors being switched, causing multiple issues * Merge bitboards into development (#285) * added new classes for the games that use bitboards instead. also combined game with turnbasedgame * (DOES NOT COMPILE) In-between commit * turn updates * smalle fixes aan turn updates * Bitboard implemented with scuffed TicTacToe translation done by game. This should be done by the view. * Almost done with implementing bitboards. Reversi is broken and artifical players don't work yet. * better human/ai selector with bot selection and depth on TicTacToeAIR * fixed getLegalMoves * depth + thinktime back to AIs, along with a a specific TicTacToeAIRSleep * fixed overlapping back and disconnect buttons * Changed to debug instead of info * changed the transitionNextCustom to be easier to use * added getAllWidgets to WidgetContainer * Correct back view * added replacePrevious in ViewWidget * added removeIndexFromPreviousChain * fixed incorrect index counting * Fixt wrong view order * fixed? getLegalMoves * Everything is broken * Removed todo * fixed getLegalMoves & getFlips * Challenge popups "Fixed" * Fixed local and online play for both games * Popups now remove themselves * Removed souts for debugging * localize the ChallengePopup text * made the game text a header instead * made more classes deepClonable. * fixed getAllWidgets * Added comment * Escape popup * fixed redundant container * Made all network events async again * Escape remove popup * Working escape menu * Removed old AI and old files. Added a new generic random AI. game no longer deals with translation. * Drawing of board on canvas is now done from bitboards rather than translating. * Added a method getWinner() to game interface.Controller now tells gameThreads how to deal with drawing UI and sending a move to server. * Added find functionality * Added a ChatGPT generated MiniMaxAI based on the old MiniMaxAI but with alpha-beta pruning and heuristics for Reversi * Removed System-Outs to clean up console * Update BitGameCanvas.java * Merge fixes * Removed unused imports --------- Co-authored-by: ramollia <> Co-authored-by: michiel301b Co-authored-by: lieght <49651652+BAFGdeJong@users.noreply.github.com> * Better limits to generic acceptance * Will fix tests etc later * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * Init server code * Moves * Testing code * Removed Generics, pray nothing breaks. * Code cleanup * Tests and better instantiation * Init challenges * Working challenges * Fixed bugs, easy to use host button * Fixed tic tac toe naming * Fixes * Removed Generics, pray nothing breaks. * Added ability to take ServerPlayer from user * Added pairs * Using pairs now in server.java * Removed space in naming * Werkt nog niet * Fixed hasArgs * Closable server * Making moves works. Game notifies when game has ended. * Partial server refactor * Refactor done, added ability to subscribe * Working subscription, button only subs to reversi right now * Small improvements to usability, auto disconnect when server closes connection * Missed a boolean * Quick fix so more than one game can be played in succession * Removed user from subscription if in a game * UI fixes after game end * TableWidget * mcts v1 * Moved subscriptions to store * bitboard optimization * Collapsed interfaces from model portion * Fixed runtime error I forgot to fix. * Collapsed interfaces in Controller section * Collapsed interfaces in View section * Code readability * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * 289 server demo ready (#306) * Server update with new dev changes (#305) * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * mcts v1 * bitboard optimization * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * Hotfix for stuff * Logging and fixed user input getting stuck * Fixed merge mistakes * Revert "Merge remote-tracking branch 'refs/remotes/origin/main' into Development" This reverts commit e2132b549d92c6d7cf98720660d88db8210cc408, reversing changes made to 9aefcb9b7bdf599735d5bbe5a4ffb8da07fd0e58. * Turn information * legal move highlight and onhover effect added back * 289 server (#308) Incremental server update, with working tournament and player input timeout * Server update with new dev changes (#305) * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * mcts v1 * bitboard optimization * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main --------- Co-authored-by: ramollia <> Co-authored-by: Stef Co-authored-by: Stef <48526421+StefBuwalda@users.noreply.github.com> * Hotfix for stuff * Logging and fixed user input getting stuck * Fixed merge mistakes * Working tournament * GlobalEventBus is now async instead * Shuffle now changeable, host can now switch tournament gametype * Tournament results are now send back to the clients connected to the server * Tournament now returns result to clients * Refactored tournament to use interfaces and builders * Removed unnecessary imports * Tournament refactor for better naming and easier to understand code * Starting a tournament now requires to be admin * Request admin list * Added admins to games * Tournament is now without admins * Added result comeback with a draw * Async tournament runner * Added back ability to shuffle matchmaker * Moved scoring calculation into scoring system * Tournament now uses propper builder pattern * Null handling * Removed input mistake, removed print * Refactored Tournament to use matchExecutor and ResultBroadcaster. Added turnTime and players are now added through Tournament creation instead of on MatchMaker/ScoreSystem creation * Added shuffle to builder * Removed unnecessary throw * More adaptable scoring system * Moved async runner to virtual thread * Timeout added * AI player given time change --------- Co-authored-by: Stef Co-authored-by: Stef <48526421+StefBuwalda@users.noreply.github.com> * update mcts, incremental merge (#311) * mcts v1, v2, v3, v4 done. v5 wip * update mcts * mcts v1, v2, v3, v4 done. v5 wip * update mcts * Merge changes on dev * update mcts --------- Co-authored-by: ramollia <> * Research Experiment Data generator * added visual score to reversi * New CSV structure thats cleaner, the code in AITest is also cleaner * implement solved * fixed things * saving games data to games.csv * readded the exploration constant * changed the way multithreading worked * Better data collection for overnight run * Infinite game collection * Correct time data visualization effect on timetable lookup for data collection purposes * Back to 10ms * m4 nu 8 threads * AI data now correct * Data collection fixes * name fixes * AI wait fixes * Added thread test * Small thread count fix * Fixes * name fixes * fixed extra wait time for threads * readded threads argument * Parameters added to tests * Moved back in threads * AI Thread fixes --------- Co-authored-by: Ticho Hidding Co-authored-by: Stef Co-authored-by: michiel Co-authored-by: ramollia <@> Co-authored-by: ramollia <> Co-authored-by: tichohidding <58555714+tichohidding@users.noreply.github.com> Co-authored-by: Stef <48526421+StefBuwalda@users.noreply.github.com> --- .idea/inspectionProfiles/Project_Default.xml | 2 +- app/src/main/java/org/toop/Main.java | 46 +- app/src/main/java/org/toop/app/Server.java | 23 +- .../org/toop/app/canvas/ReversiBitCanvas.java | 29 + .../GenericGameController.java | 16 +- .../gameControllers/ReversiBitController.java | 8 +- .../toop/app/widget/popup/GameOverPopup.java | 2 +- .../org/toop/app/widget/view/GameView.java | 32 +- .../app/widget/view/LocalMultiplayerView.java | 16 +- .../org/toop/app/widget/view/ServerView.java | 76 ++- .../toop/framework/eventbus/EventFlow.java | 4 +- .../framework/eventbus/GlobalEventBus.java | 17 +- .../framework/eventbus/bus/AsyncEventBus.java | 7 + .../eventbus/bus/DefaultEventBus.java | 14 +- .../org/toop/framework/game/BitboardGame.java | 6 +- .../gameThreads/OnlineThreadBehaviour.java | 10 +- .../gameThreads/ServerThreadBehaviour.java | 67 +- .../game/games/reversi/BitboardReversi.java | 53 +- .../games/tictactoe/BitboardTicTacToe.java | 15 + .../game/players/ArtificialPlayer.java | 8 +- .../framework/game/players/ServerPlayer.java | 11 +- .../model/game/TurnBasedGame.java | 5 + .../connection/events/NetworkEvents.java | 4 + .../handlers/NetworkingGameClientHandler.java | 66 ++ .../networking/server/GameResultFuture.java | 7 + .../networking/server/GameServer.java | 6 +- .../networking/server/MatchExecutor.java | 10 + .../server/OnlineTurnBasedGame.java | 47 +- .../framework/networking/server/Server.java | 109 +++- .../networking/server/client/NettyClient.java | 1 - .../server/handlers/MessageHandler.java | 39 +- .../tournaments/AsyncTournamentRunner.java | 86 +++ .../tournaments/BasicTournamentRunner.java | 40 ++ .../server/tournaments/ResultBroadcaster.java | 10 + .../server/tournaments/Tournament.java | 121 ++++ .../server/tournaments/TournamentMatch.java | 18 + .../server/tournaments/TournamentRunner.java | 13 + .../DoubleRoundRobinMatchMaker.java | 81 +++ .../tournaments/matchmakers/MatchMaker.java | 13 + .../matchmakers/RoundRobinMatchMaker.java | 67 ++ .../scoresystems/DrawCountScoreSystem.java | 43 ++ .../scoresystems/IntegerScoreSystem.java | 6 + .../scoresystems/LoseCountScoreSystem.java | 41 ++ .../scoresystems/MatchCountScoreSystem.java | 37 ++ .../tournaments/scoresystems/ScoreSystem.java | 10 + .../scoresystems/WinCountScoreSystem.java | 41 ++ .../tournaments/shufflers/RandomShuffle.java | 20 + .../tournaments/shufflers/Shuffler.java | 7 + .../java/org/toop/game/players/ai/MCTSAI.java | 337 ++++++---- .../toop/game/players/ai/mcts/MCTSAI1.java | 38 ++ .../toop/game/players/ai/mcts/MCTSAI2.java | 48 ++ .../toop/game/players/ai/mcts/MCTSAI3.java | 76 +++ .../toop/game/players/ai/mcts/MCTSAI4.java | 82 +++ game/src/test/java/research/AIData.java | 77 +++ game/src/test/java/research/AITest.java | 612 ++++++++++++++++++ game/src/test/java/research/GameData.java | 32 + game/src/test/java/research/Matchup.java | 30 + 57 files changed, 2450 insertions(+), 292 deletions(-) create mode 100644 framework/src/main/java/org/toop/framework/eventbus/bus/AsyncEventBus.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameResultFuture.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/MatchExecutor.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/AsyncTournamentRunner.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournamentRunner.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/ResultBroadcaster.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentMatch.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentRunner.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/DoubleRoundRobinMatchMaker.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/MatchMaker.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/RoundRobinMatchMaker.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/DrawCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/IntegerScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/LoseCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/MatchCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/WinCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/RandomShuffle.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/Shuffler.java create mode 100644 game/src/main/java/org/toop/game/players/ai/mcts/MCTSAI1.java create mode 100644 game/src/main/java/org/toop/game/players/ai/mcts/MCTSAI2.java create mode 100644 game/src/main/java/org/toop/game/players/ai/mcts/MCTSAI3.java create mode 100644 game/src/main/java/org/toop/game/players/ai/mcts/MCTSAI4.java create mode 100644 game/src/test/java/research/AIData.java create mode 100644 game/src/test/java/research/AITest.java create mode 100644 game/src/test/java/research/GameData.java create mode 100644 game/src/test/java/research/Matchup.java diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 655cfae..e0e273b 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,7 +2,7 @@ diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index bd330d2..3b4fef3 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -4,50 +4,6 @@ import org.toop.app.App; public final class Main { static void main(String[] args) { - App.run(args); - // testMCTS(10); + App.run(args); } - - // Voor onderzoek - // private static void testMCTS(int games) { - // var random = new ArtificialPlayer<>(new RandomAI(), "Random AI"); - // var v1 = new ArtificialPlayer<>(new MCTSAI(10), "MCTS V1 AI"); - // var v2 = new ArtificialPlayer<>(new MCTSAI2(10), "MCTS V2 AI"); - // var v2_2 = new ArtificialPlayer<>(new MCTSAI2(100), "MCTS V2_2 AI"); - // var v3 = new ArtificialPlayer<>(new MCTSAI3(10), "MCTS V3 AI"); - - // testAI(games, new Player[]{ v1, v2 }); - // // testAI(games, new Player[]{ v1, v3 }); - - // // testAI(games, new Player[]{ random, v3 }); - // // testAI(games, new Player[]{ v2, v3 }); - // testAI(games, new Player[]{ v2, v3 }); - // // testAI(games, new Player[]{ v3, v2 }); - // } - - // private static void testAI(int games, Player[] ais) { - // int wins = 0; - // int ties = 0; - - // for (int i = 0; i < games; i++) { - // final BitboardReversi match = new BitboardReversi(ais); - - // while (!match.isTerminal()) { - // final int currentAI = match.getCurrentTurn(); - // final long move = ais[currentAI].getMove(match); - - // match.play(move); - // } - - // if (match.getWinner() < 0) { - // ties++; - // continue; - // } - - // wins += match.getWinner() == 0? 1 : 0; - // } - - // System.out.printf("Out of %d games, %s won %d -- tied %d -- lost %d, games against %s\n", games, ais[0].getName(), wins, ties, games - wins - ties, ais[1].getName()); - // System.out.printf("Average win rate was: %.2f\n\n", wins / (float)games); - // } } diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index f6bcdec..d8c4acf 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -11,6 +11,7 @@ import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.view.ServerView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.game.players.ArtificialPlayer; import org.toop.framework.game.players.OnlinePlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.eventbus.GlobalEventBus; @@ -19,9 +20,10 @@ import org.toop.framework.networking.connection.clients.TournamentNetworkingClie import org.toop.framework.networking.connection.events.NetworkEvents; import org.toop.framework.networking.connection.types.NetworkingConnector; import org.toop.framework.networking.server.gateway.NettyGatewayServer; -import org.toop.framework.game.players.LocalPlayer; +import org.toop.game.players.ai.mcts.MCTSAI3; import org.toop.local.AppContext; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; @@ -117,7 +119,8 @@ public final class Server { return; } - primary = new ServerView(user, this::sendChallenge, clientId); + primary = new ServerView(user, this::sendChallenge, user, clientId); + WidgetContainer.getCurrentView().transitionNextCustom(primary, "disconnect", this::disconnect); a.unsubscribe("connecting"); @@ -159,7 +162,8 @@ public final class Server { .listen(NetworkEvents.GameResultResponse.class, this::handleGameResult, false, "game-result") .listen(NetworkEvents.GameMoveResponse.class, this::handleReceivedMove, false, "game-move") .listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn") - .listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection"); + .listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection") + .listen(NetworkEvents.TournamentResultResponse.class, this::handleTournamentResult, false, "tournament-result"); connectFlow = a; } @@ -205,7 +209,8 @@ public final class Server { information.players[opponentStartingTurn].name = response.opponent(); Player[] players = new Player[2]; - players[userStartingTurn] = new LocalPlayer(user); + + players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(1000, 8), user); players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { @@ -238,6 +243,13 @@ public final class Server { gameController.gameFinished(response); } + private void handleTournamentResult(NetworkEvents.TournamentResultResponse response) { + IO.println(response.gameType()); + IO.println(Arrays.toString(response.names())); + IO.println(Arrays.toString(response.scoreTypes())); + IO.println(Arrays.toString(response.scores().toArray())); + } + private void handleReceivedMove(NetworkEvents.GameMoveResponse response) { if (gameController == null) { return; @@ -337,7 +349,8 @@ public final class Server { private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) { gameList.clear(); - var gl = List.of(event.gamelist()); + var gl = new java.util.ArrayList<>(List.of(event.gamelist())); + gl.sort(String::compareTo); gameList.addAll(gl); primary.updateGameList(gl); } diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java index 685a985..d210b16 100644 --- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java @@ -2,9 +2,13 @@ package org.toop.app.canvas; import javafx.scene.paint.Color; import org.toop.app.App; +import org.toop.framework.game.games.reversi.BitboardReversi; +import org.toop.framework.game.players.LocalPlayer; import org.toop.framework.gameFramework.model.game.TurnBasedGame; public class ReversiBitCanvas extends BitGameCanvas { + private TurnBasedGame gameCopy; + private int previousCell; public ReversiBitCanvas() { super(Color.GRAY, new Color(0f, 0.4f, 0.2f, 1f), (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, 8, 8, 5, true); canvas.setOnMouseMoved(event -> { @@ -20,6 +24,9 @@ public class ReversiBitCanvas extends BitGameCanvas { break; } } + if (hovered != null) { + checkHoverDots(hovered, cellId); + } }); } @@ -31,9 +38,31 @@ public class ReversiBitCanvas extends BitGameCanvas { @Override public void redraw(TurnBasedGame gameCopy) { + this.gameCopy = gameCopy; clearAll(); long[] board = gameCopy.getBoard(); loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, i)); loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, i)); } + + public void drawLegalDots(TurnBasedGame gameCopy){ + long legal = gameCopy.getLegalMoves(); + loopOverBoard(legal, (i) -> drawInnerDot(gameCopy.getCurrentTurn()==0?new Color(1f,1f,1f,0.65f) :new Color(0f,0f,0f,0.65f), i,false)); + } + + private void checkHoverDots(BitGameCanvas.Cell hovered, int cellId){ + if (previousCell == cellId){ + return; + } + long backflips = ((BitboardReversi)gameCopy).getFlips(1L << previousCell); + loopOverBoard(backflips, (i) -> drawInnerDot(gameCopy.getCurrentTurn()==1?Color.WHITE:Color.BLACK, i,true)); + previousCell = cellId; + if (gameCopy.getPlayer(gameCopy.getCurrentTurn()) instanceof LocalPlayer) { + long legal = gameCopy.getLegalMoves(); + if ((legal & (1L << cellId)) != 0) { + long flips = ((BitboardReversi) gameCopy).getFlips(1L << cellId); + loopOverBoard(flips, (i) -> drawInnerDot(gameCopy.getCurrentTurn() == 0 ? Color.WHITE : Color.BLACK, i, false)); + } + } + } } diff --git a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java index 0c68a74..d31c60d 100644 --- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java +++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java @@ -5,10 +5,12 @@ import javafx.geometry.Pos; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.toop.app.canvas.GameCanvas; +import org.toop.app.canvas.ReversiBitCanvas; import org.toop.app.widget.WidgetContainer; import org.toop.app.widget.view.GameView; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.GlobalEventBus; +import org.toop.framework.game.games.reversi.BitboardReversi; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.model.game.threadBehaviour.SupportsOnlinePlay; import org.toop.framework.gameFramework.model.game.TurnBasedGame; @@ -153,6 +155,18 @@ public class GenericGameController implements GameController { @Override public void updateUI() { - canvas.redraw(game.deepCopy()); + TurnBasedGame gameCopy = game.deepCopy(); + canvas.redraw(gameCopy); + String gameType = game.getClass().getSimpleName().replace("Bitboard",""); + gameView.nextPlayer(true, getCurrentPlayer().getName(), game.getPlayer(1-getCurrentPlayerIndex()).getName(),gameType); + if (gameType.equals("Reversi")) { + BitboardReversi reversiGame = (BitboardReversi) game; + BitboardReversi.Score reversiScore = reversiGame.getScore(); + gameView.setPlayer1Score(reversiScore.black()); + gameView.setPlayer2Score(reversiScore.white()); + if (getCurrentPlayer() instanceof LocalPlayer) { + ((ReversiBitCanvas)canvas).drawLegalDots(gameCopy); + } + } } } diff --git a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java index 1ea8109..8954a62 100644 --- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java +++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java @@ -11,13 +11,19 @@ import org.toop.framework.game.players.OnlinePlayer; import java.util.Arrays; public class ReversiBitController extends GenericGameController { + + private BitboardReversi game; + public ReversiBitController(Player[] players) { BitboardReversi game = new BitboardReversi(); game.init(players); - ThreadBehaviour thread = Arrays.stream(players).anyMatch(e -> e instanceof OnlinePlayer) ? new OnlineThreadBehaviour(game) : new LocalThreadBehaviour(game); super(new ReversiBitCanvas(), game, thread, "Reversi"); } + + public BitboardReversi.Score getScore() { + return game.getScore(); + } } diff --git a/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java b/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java index ab1ef3d..9c9f961 100644 --- a/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java +++ b/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java @@ -4,6 +4,7 @@ import org.toop.app.widget.complex.ConfirmWidget; import org.toop.app.widget.complex.PopupWidget; import javafx.geometry.Pos; +import org.toop.framework.game.games.reversi.BitboardReversi; public final class GameOverPopup extends PopupWidget { public GameOverPopup(boolean winOrTie, String winner) { @@ -15,7 +16,6 @@ public final class GameOverPopup extends PopupWidget { else{ confirmWidget.setMessage("It was a tie!"); } - confirmWidget.addButton("ok", this::hide); add(Pos.CENTER, confirmWidget); diff --git a/app/src/main/java/org/toop/app/widget/view/GameView.java b/app/src/main/java/org/toop/app/widget/view/GameView.java index 441cc0e..38fcd6c 100644 --- a/app/src/main/java/org/toop/app/widget/view/GameView.java +++ b/app/src/main/java/org/toop/app/widget/view/GameView.java @@ -6,6 +6,8 @@ import javafx.scene.text.Font; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.GameOverPopup; + +import java.util.Objects; import java.util.function.Consumer; import javafx.application.Platform; import javafx.geometry.Pos; @@ -24,6 +26,8 @@ public final class GameView extends ViewWidget { private final Text player2Header; private Circle player1Icon; private Circle player2Icon; + private final Text player1Score; + private final Text player2Score; private final Button forfeitButton; private final Button exitButton; private final TextField chatInput; @@ -38,6 +42,8 @@ public final class GameView extends ViewWidget { player2Header = Primitive.header(""); player1Icon = new Circle(); player2Icon = new Circle(); + player1Score = Primitive.header(""); + player2Score = Primitive.header(""); if (onForfeit != null) { forfeitButton = Primitive.button("forfeit", () -> onForfeit.run(), false); @@ -94,7 +100,7 @@ public final class GameView extends ViewWidget { } } - public void nextPlayer(boolean isMe, String currentPlayer, String currentMove, String nextPlayer, char GameType) { + public void nextPlayer(boolean isMe, String currentPlayer, String nextPlayer, String GameType) { Platform.runLater(() -> { if (!(hasSet)) { playerHeader.setText(currentPlayer + " vs. " + nextPlayer); @@ -112,8 +118,8 @@ public final class GameView extends ViewWidget { new GameOverPopup(iWon, winner).show(Pos.CENTER); } - private void setPlayerHeaders(boolean isMe, String currentPlayer, String nextPlayer, char GameType) { - if (GameType == 'T') { + private void setPlayerHeaders(boolean isMe, String currentPlayer, String nextPlayer, String GameType) { + if (Objects.equals(GameType, "TicTacToe")) { if (isMe) { player1Header.setText("X: " + currentPlayer); player2Header.setText("O: " + nextPlayer); @@ -124,7 +130,7 @@ public final class GameView extends ViewWidget { } setPlayerInfoTTT(); } - else if (GameType == 'R') { + else if (Objects.equals(GameType, "Reversi")) { if (isMe) { player1Header.setText(currentPlayer); player2Header.setText(nextPlayer); @@ -151,14 +157,16 @@ public final class GameView extends ViewWidget { private void setPlayerInfoReversi() { var player1box = Primitive.hbox( player1Icon, - player1Header + player1Header, + player1Score ); player1box.getStyleClass().add("hboxspacing"); var player2box = Primitive.hbox( player2Icon, - player2Header + player2Header, + player2Score ); player2box.getStyleClass().add("hboxspacing"); @@ -172,8 +180,16 @@ public final class GameView extends ViewWidget { player1Icon.setRadius(player1Header.fontProperty().map(Font::getSize).getValue()); player2Icon.setRadius(player2Header.fontProperty().map(Font::getSize).getValue()); - player1Icon.setFill(Color.BLACK); - player2Icon.setFill(Color.WHITE); + player1Icon.setFill(Color.WHITE); + player2Icon.setFill(Color.BLACK); add(Pos.TOP_RIGHT, playerInfo); } + + public void setPlayer1Score(int score) { + player1Score.setText("(" + Integer.toString(score) + ")"); + } + + public void setPlayer2Score(int score) { + player2Score.setText("(" + Integer.toString(score) + ")"); + } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java index 9139720..2db2419 100644 --- a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java +++ b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java @@ -4,6 +4,7 @@ import javafx.application.Platform; import org.toop.app.GameInformation; import org.toop.app.gameControllers.ReversiBitController; import org.toop.app.gameControllers.TicTacToeBitController; +import org.toop.framework.game.players.LocalPlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.model.player.Player; import org.toop.framework.game.players.ArtificialPlayer; @@ -12,11 +13,10 @@ import org.toop.app.widget.complex.PlayerInfoWidget; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.tutorial.*; -import org.toop.framework.game.players.LocalPlayer; -import org.toop.game.players.ai.MCTSAI; -import org.toop.game.players.ai.MCTSAI2; -import org.toop.game.players.ai.MCTSAI3; import org.toop.game.players.ai.MiniMaxAI; +import org.toop.game.players.ai.mcts.MCTSAI1; +import org.toop.game.players.ai.mcts.MCTSAI3; +import org.toop.game.players.ai.mcts.MCTSAI4; import org.toop.local.AppContext; import javafx.geometry.Pos; @@ -54,7 +54,7 @@ public class LocalMultiplayerView extends ViewWidget { if (information.players[0].isHuman) { players[0] = new LocalPlayer(information.players[0].name); } else { - players[0] = new ArtificialPlayer(new MCTSAI(100), "MCTS AI"); + players[0] = new ArtificialPlayer(new MCTSAI1(100), "MCTS AI"); } if (information.players[1].isHuman) { players[1] = new LocalPlayer(information.players[1].name); @@ -82,13 +82,13 @@ public class LocalMultiplayerView extends ViewWidget { if (information.players[0].isHuman) { players[0] = new LocalPlayer(information.players[0].name); } else { - // players[0] = new ArtificialPlayer(new RandomAI(), "Random AI"); - players[0] = new ArtificialPlayer(new MCTSAI3(50), "MCTS V3 AI"); + // players[0] = new ArtificialPlayer(new RandomAI(), "Random AI"); + players[0] = new ArtificialPlayer(new MCTSAI1(100), "MCTS V1 AI"); } if (information.players[1].isHuman) { players[1] = new LocalPlayer(information.players[1].name); } else { - players[1] = new ArtificialPlayer(new MCTSAI2(50), "MCTS V2 AI"); + players[1] = new ArtificialPlayer(new MCTSAI4(100, 8), "MCTS V4 AI"); } if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstReversi()) { new ShowEnableTutorialWidget( diff --git a/app/src/main/java/org/toop/app/widget/view/ServerView.java b/app/src/main/java/org/toop/app/widget/view/ServerView.java index 92c8101..9408b27 100644 --- a/app/src/main/java/org/toop/app/widget/view/ServerView.java +++ b/app/src/main/java/org/toop/app/widget/view/ServerView.java @@ -6,6 +6,8 @@ import javafx.scene.control.ComboBox; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.ViewWidget; +import java.io.Reader; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Consumer; @@ -15,6 +17,7 @@ import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.ListView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.eventbus.GlobalEventBus; import org.toop.framework.networking.connection.events.NetworkEvents; public final class ServerView extends ViewWidget { @@ -22,46 +25,65 @@ public final class ServerView extends ViewWidget { private final Consumer onPlayerClicked; private final long clientId; - private final ComboBox gameList; + private final ComboBox gameListSub; + private final ComboBox gameListTour; private final ListView