162 Commits

Author SHA1 Message Date
48cd4d3956 Add migration state XML files and update build configuration 2025-10-09 10:52:04 +02:00
d54f814192 Merge pull request 'Implemented Docker' (#43) from dockertest into master
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Reviewed-on: #43
2025-01-23 18:09:24 +01:00
05b6ebb2a8 DOCKER WORKS
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-23 17:46:18 +01:00
079e66a5cf Docker File update
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-23 17:00:18 +01:00
220c3d04ea Hotfix for Presentation
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-23 16:04:39 +01:00
a6e514880c Docker File implementation
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-23 13:05:10 +01:00
ec329df768 Hotfix for Presentation
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-23 09:38:18 +01:00
a856843fc3 Fixed Tests v2
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-20 14:08:19 +01:00
LQ63
f57537b3eb updated WinnerScreen
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-20 13:34:07 +01:00
6c825845ea Merge branch 'master' into FileIO
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-20 13:32:43 +01:00
5b37ebb01d Fixed Tests 2025-01-20 13:31:54 +01:00
2b63fbe88d Merge pull request 'FileIO' (#42) from FileIO into master
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Reviewed-on: #42
2025-01-20 13:04:14 +01:00
LQ63
0e31134dfb better winning screen
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-18 19:54:26 +01:00
LQ63
d0ab531e16 Finished Basic functionality for Gui. Includes working cut, (very) basic winning screen 2025-01-18 17:16:18 +01:00
b6812d1223 Fixed Dog Play + Savegames 2025-01-18 15:17:06 +01:00
LQ63
169537c479 Added new Stuff for the gui, added support for gamesaving and loading. 2025-01-17 09:18:10 +01:00
aad61fd10a Load File improvements 2025-01-17 09:09:53 +01:00
d9b1bb2186 Tie fixes 2025-01-17 09:00:10 +01:00
d48e3b1daa File ending support 2025-01-17 08:55:45 +01:00
fa8cab1d6f FileIO 2025-01-16 21:53:31 +01:00
a53f4dda46 Tried fixing CT 2025-01-16 21:09:21 +01:00
483991bdbb Reduced Critical Section 2025-01-16 21:06:58 +01:00
bd73997959 XML FileIO Done 2025-01-16 20:24:40 +01:00
3a41a4bb4d Current FileIO State 2025-01-16 18:59:04 +01:00
474de82cde Fixed GUI 2025-01-16 18:47:59 +01:00
d39e92cfa8 Fixed PersistenceManager 2025-01-16 18:04:13 +01:00
e1d7405f51 FileIO Impl 2025-01-16 17:49:41 +01:00
a33e404378 Start of fileio 2025-01-15 20:24:25 +01:00
LQ63
2e0d24adbd changed tests
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2025-01-14 21:13:57 +01:00
13199ddd74 Dependency Injection 2025-01-09 14:35:45 +01:00
3396355193 Config Version yay
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:54:29 +01:00
LQ63
111242a6aa removed comments
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:52:37 +01:00
LQ63
681fdd4253 Merge remote-tracking branch 'origin/Components' into Components
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:51:26 +01:00
LQ63
3fe3abe7fc removed comments 2024-12-20 10:51:09 +01:00
e0b7a68207 Components yayyy
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:48:46 +01:00
LQ63
67a590e544 Configuration
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:38:19 +01:00
LQ63
8742c5dc7a Mock PlayerQueue + startet config
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 10:33:20 +01:00
LQ63
7a46bed011 Mock PlayerQueue
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 09:30:34 +01:00
LQ63
9ecf91282e Merge remote-tracking branch 'origin/Components' into Components 2024-12-20 09:29:55 +01:00
LQ63
0526f99464 Mock PlayerQueue 2024-12-20 09:29:32 +01:00
95228cbd51 Current Component State
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-20 09:24:20 +01:00
LQ63
49e378b51a Merge remote-tracking branch 'origin/Components' into Components
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 21:44:10 +01:00
LQ63
3b6ec1cd1b interfaces finished 2024-12-19 21:43:44 +01:00
d21540bbe7 Componentiesierung round 2
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 21:26:11 +01:00
LQ63
05afe8b392 interfaces almost finished(comments missing)
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 21:24:49 +01:00
92e9149d55 Componentiesierung
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 21:03:43 +01:00
LQ63
5324a16cbe Started components
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 20:38:00 +01:00
LQ63
ecff0a318d Started components 2024-12-19 20:37:52 +01:00
LQ63
b8c5b7a389 Started components
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 20:37:23 +01:00
3c83fec6b5 Added Background
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-19 11:29:59 +01:00
a5f7f14d06 GUI changes
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 12:28:27 +01:00
4aafd01f92 GUI changes 2024-12-13 12:23:57 +01:00
LQ63
2fe0ddcf45 Merge remote-tracking branch 'origin/GUI' into GUI
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 12:18:25 +01:00
LQ63
e1c2d660f1 added RoundEnd and TrickEnd animations 2024-12-13 12:18:00 +01:00
648a1b2ce7 Main Menu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 11:54:33 +01:00
56cc2f1182 Changed Delays added FirstCard
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 11:31:03 +01:00
LQ63
f7b09a0bd9 fixed TrumpsuitMenu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 11:18:20 +01:00
LQ63
ed8356577c added PickTrumpsuit Menu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 11:07:53 +01:00
085002a35a Made cards playable
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 09:40:59 +01:00
c3dcca6bde PlayedCards implemented
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 09:33:59 +01:00
4e43e25437 Main updated
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 09:30:55 +01:00
9d5194bf1d Game updated 2024-12-13 09:30:41 +01:00
LQ63
f5250f401f rendered cards for gui
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 01:23:06 +01:00
30e395d649 Game GUI WIP
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 00:58:59 +01:00
597c0f196a Starting GUI integration
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 00:24:31 +01:00
33c14d3731 Fixed Main Menu spawning twice
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-13 00:16:19 +01:00
961f91eef8 Custom Input... 2024-12-13 00:14:57 +01:00
LQ63
bb51dcb69b gui update
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 23:40:18 +01:00
82c6398dab Added State handling
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 23:31:50 +01:00
LQ63
b0e44b6690 started GUI
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 23:21:25 +01:00
0aae73f530 Fixed GUI Thread problems
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 23:02:18 +01:00
de63e94342 Changed Logic:
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Made UndoLogic Thread safe.
CustomThread optimized
2024-12-12 22:47:21 +01:00
b45efc91cb Merge branch 'WIPGUI' into GUI
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
# Conflicts:
#	src/main/scala/de/knockoutwhist/ui/gui/MainMenu.scala
2024-12-12 21:06:02 +01:00
fbd2f7a4dd Changed Logic:
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
UIs must now directly call the logic.
Removed Returnable Events
2024-12-12 21:00:13 +01:00
7f4a08c673 Custom Thread Support
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 15:50:12 +01:00
LQ63
34d9986979 added Return and checkmark button
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-12 01:35:17 +01:00
21e810b0da Agony and Pain
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 19:18:01 +01:00
LQ63
452810f9fa updated MainMenu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 19:17:49 +01:00
LQ63
bfcd207c38 updated MainMenu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 18:31:26 +01:00
3f958cf20a Added some animations added change child
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 18:08:54 +01:00
faecdf00be Added Main Menu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 17:31:53 +01:00
de9aa383ea Started Main Menu
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 17:04:33 +01:00
2fad96bb2c GUI start
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 15:46:20 +01:00
LQ63
aec723d243 updated sbt
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-11 15:27:44 +01:00
28c8f5850e Logic fixes (Tie a bit unstable)
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-06 11:23:16 +01:00
5e065c04c7 Fixed Undo - cause didn't work before
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-06 10:42:01 +01:00
4ef7333ef5 Fixed AI Logic - Fixed dog life (thx Leon)
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-06 10:18:01 +01:00
dddbd97362 Made everything immutable -> Tests severely broken, AI broken, Coverage very low (But it works)
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-05 23:19:06 +01:00
LQ63
46075fa356 changed RoundControl
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-05 19:36:16 +01:00
8553bf7941 Merge remote-tracking branch 'origin/commandPattern' into commandPattern
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-05 19:27:14 +01:00
1311cb20b8 Match immutable 2024-12-05 19:26:56 +01:00
LQ63
87e9d66f46 Player immutable
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-05 19:23:16 +01:00
9edea7082d CustomPlayerQueue clone 2024-12-05 18:20:44 +01:00
0a4d725669 Immutable + Command Pattern
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-12-05 18:15:41 +01:00
9e9941cd70 Merge pull request 'Hotfix Code Coverage' (#41) from development into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #41
2024-11-29 12:31:41 +01:00
0ce277fe33 Merge branch 'master' into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-29 12:29:05 +01:00
LQ63
4573f4c2a6 Coverage 100%
Some checks reported errors
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-29 12:28:23 +01:00
LQ63
9c5947a18f Merge pull request 'Patterns implemented' (#40) from development into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #40
2024-11-29 12:20:06 +01:00
337d27abbf Added second Iterator
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-29 12:16:02 +01:00
4e8a8a958d Merge remote-tracking branch 'origin/development' into playerpattern
Some checks reported errors
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-29 12:05:37 +01:00
a9871e6038 Removed Code Smell 2024-11-29 12:05:06 +01:00
0a37a583f7 Merge pull request 'Patterns implemented' (#39) from playerpattern into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #39
2024-11-29 12:01:55 +01:00
9da9477763 Merge branch 'master' into playerpattern 2024-11-29 12:01:37 +01:00
36286be458 100% coverage
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-29 11:58:37 +01:00
ca3ffa4ba7 Builder Pattern finished
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-29 11:55:09 +01:00
LQ63
82d7ab94b4 Started Builder
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-29 11:44:39 +01:00
7487a0edf6 Merge remote-tracking branch 'origin/playerpattern' into playerpattern
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
# Conflicts:
#	src/test/scala/de/knockoutwhist/player/AITests.scala
2024-11-29 11:19:30 +01:00
6b3b702ffe Added Code Coverage 2024-11-29 11:18:26 +01:00
LQ63
1cc776bfaa optimized imports
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-29 10:40:20 +01:00
LQ63
1e50a40868 startet tests for ai
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 22:55:38 +01:00
LQ63
fe4f6a7f46 fixed current test to match the new patterns
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 22:23:52 +01:00
LQ63
7f69e6f444 optimized imports
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 20:51:57 +01:00
LQ63
e589f36c22 changed constructor access
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 20:38:06 +01:00
LQ63
33e15bca27 finished AILogic implementation, added Factory Pattern and Template Pattern
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 20:31:08 +01:00
8d7420358d Added AI Logic
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 19:11:51 +01:00
LQ63
522a1cfa23 started pattern creation
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-28 18:06:22 +01:00
LQ63
39336120e1 Merge pull request 'Full functional Code' (#37) from development into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #37
Reviewed-by: Janis <janis-e@gmx.de>
2024-11-21 22:27:12 +01:00
LQ63
777e4c2d6b Merge pull request 'reduced smelly code' (#36) from lastsmellfix into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #36
2024-11-21 22:10:44 +01:00
LQ63
d75c2cf62a merged two if's to reduce smelly code
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 22:08:23 +01:00
LQ63
9191012aaf Merge pull request 'FixedIssues' (#35) from fixissues into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #35
2024-11-21 22:01:04 +01:00
LQ63
1a7e48864b Fixed TuiMain
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 21:54:16 +01:00
LQ63
6ef9e95cb8 Changed TuiMain so that it isn't smelly anymore
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 21:50:26 +01:00
c94e37f63e Reduced complexity
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 21:29:16 +01:00
LQ63
be4e00af44 Reduced smelly code
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 21:17:53 +01:00
LQ63
ebea37aece Merge remote-tracking branch 'refs/remotes/origin/development' into fixissues
# Conflicts:
#	src/main/scala/de/knockoutwhist/control/PlayerControl.scala
#	src/main/scala/de/knockoutwhist/control/RoundControl.scala
#	src/main/scala/de/knockoutwhist/control/TrickControl.scala
2024-11-21 21:16:04 +01:00
b9e896fc0b Merge pull request 'Reduced Test Time by a lot' (#34) from test-improvements into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #34
2024-11-21 20:57:49 +01:00
a0e2eadc93 Reduced Test Time by a lot
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 19:42:14 +01:00
LQ63
47169bdb8b changed a name to match the given regex by sonarqube
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-21 12:25:22 +01:00
3a6473379d Merge pull request 'README.md aktualisiert' (#33) from janis-patch-1 into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #33
2024-11-19 20:24:21 +01:00
11dab537ba README.md aktualisiert 2024-11-19 20:24:14 +01:00
3a246b4419 Merge pull request 'README.md aktualisiert' (#32) from janis-patch-1 into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #32
2024-11-19 15:18:43 +01:00
d940620049 README.md aktualisiert 2024-11-19 15:18:33 +01:00
4d86baa6d9 Merge pull request 'README.md aktualisiert' (#31) from janis-patch-1 into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #31
2024-11-19 15:16:34 +01:00
14ef284229 README.md aktualisiert
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-19 15:16:23 +01:00
d73c4c0577 Merge pull request 'development' (#30) from development into master
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #30
2024-11-18 10:50:36 +01:00
0b5bfc69e5 Merge pull request 'Coveralls' (#29) from coverall into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #29
2024-11-18 10:45:23 +01:00
ad0494f0ba Merge remote-tracking branch 'origin/development' into coverall
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
# Conflicts:
#	project/plugins.sbt
2024-11-18 10:42:48 +01:00
355addf8a5 Merge pull request 'eventsystem' (#28) from eventsystem into development
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
Reviewed-on: #28
2024-11-18 10:38:50 +01:00
efd5e0fae6 Coveralls
All checks were successful
Build and Test (KnockOutWhist) TeamCity build finished
2024-11-18 10:37:44 +01:00
8cb5012c8f Remove unnecessary method
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 12:35:55 +01:00
LQ63
6304ce44b9 Changed GameplayTests
Some checks reported errors
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 12:35:39 +01:00
ee44f6940b Added more tests
Some checks reported errors
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 12:33:26 +01:00
LQ63
0c6de4b86f Added Tests for Events
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 12:00:48 +01:00
094afc5631 Added DelayHandlerTests
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 11:55:16 +01:00
fabb2f3580 Merge pull request 'Implemented Assembly Pipeline' (#27) from development into master
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Reviewed-on: #27
2024-11-15 11:38:39 +01:00
bb0ad578be Merge pull request 'Pipeline Test' (#26) from pipelineWorks into development
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Reviewed-on: #26
2024-11-15 11:38:13 +01:00
ce5efd7a05 Pipeline Test
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 11:35:26 +01:00
174fe3c993 Fixed Tests
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 11:17:34 +01:00
03ab3f3650 Improved Code Coverage
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-15 11:13:00 +01:00
LQ63
a7f839d01c Changed Tests according to the new structure.
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 20:35:12 +01:00
a7e84b9815 Fixed DelayHandler
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 20:14:22 +01:00
4c7fb1c8bc Fixed EventHandler
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 20:09:11 +01:00
ef1eb29fe3 Merge remote-tracking branch 'origin/eventsystem' into eventsystem
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 18:06:51 +01:00
LQ63
619cbcfaac Changed structure of Control
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 18:06:33 +01:00
fe46690fb4 Added a clear console for the main menu 2024-11-14 17:31:32 +01:00
24bfd7925c Splitted Logic between UI and Logic
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 17:28:39 +01:00
11c0b61933 Rearranged everything Data Structure got no more logic
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-14 16:47:38 +01:00
0cc7756556 Switcher Handlers over to one
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Added UI Trait
Renamed Controls
Deleted old Logic
2024-11-14 12:31:17 +01:00
153d028959 Added a delay handler
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-13 22:04:41 +01:00
LQ63
177ec3772e Added more Events, finished GenericPlayerControl. Startet with GenericMatchControl
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-13 18:07:28 +01:00
c397d079bf Reworked Events
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
Created Events
2024-11-13 13:45:19 +01:00
a99182beaf WIP - Event System
Some checks failed
Build and Test (KnockOutWhist) TeamCity build failed
2024-11-11 23:14:56 +01:00
186 changed files with 6417 additions and 1516 deletions

6
.idea/copilot.data.migration.agent.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.ask.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AskMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Ask2AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.edit.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

1
DOCKER-COMMANDS Normal file
View File

@@ -0,0 +1 @@
docker run -it --rm -e DISPLAY=host.docker.internal:0 -v /tmp/.X11-unix:/tmp/.X11-unix knockout:v1

35
Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
FROM sbtscala/scala-sbt:eclipse-temurin-jammy-22_36_1.10.0_3.4.2
WORKDIR /knockout
ENV DEBIAN_FRONTEND=noninterface
RUN apt-get update && apt-get install -y curl gnupg2 x11-apps
RUN apt-get update && apt-get install -y \
libxext6 \
libxrender1 \
libxtst6 \
libxi6 \
libxrandr2 \
libgtk-3-0 \
xorg
RUN curl -sL https://dlcdn.apache.org/sbt/debian/sbt-1.9.4.deb -o sbt.deb
RUN dpkg -i sbt.deb || apt-get install -f -y
ENV DEBIAN_FRONTEND=dialog
RUN sbt update
ENV DISPLAY=:99
ENV SBT_OPTS="-Xms512M -Xmx1536M -Xss2M -XX:MaxMetaspaceSize=512M"
ENV _JAVA_OPTIONS="-Djava.security.policy=applet.policy -Dprism.order=sw"
VOLUME /tmp/.X11-unix
COPY . /knockout
RUN sbt compile
CMD ["sh", "-c", "sbt run"]

View File

@@ -1,4 +1,4 @@
# Knock-out Whist
# Knock-out Whist [![Coverage Status](https://coveralls.io/repos/github/16Janis12/KnockOutWhist/badge.svg?branch=master)](https://coveralls.io/github/16Janis12/KnockOutWhist?branch=master) [![Build-Status-Master](https://teamcity.janis-eccarius.de/guestAuth/app/rest/builds/buildType:(id:KnockOutWhist_BuildAndTest),branch:master/statusIcon.png)](https://teamcity.janis-eccarius.de/viewType.html?buildTypeId=KnockOutWhist_BuildAndTest&branch=master) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=16Janis12_KnockOutWhist&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=16Janis12_KnockOutWhist)
## About the Game
Knock-out Whist is a trick-taking card game designed for 2 to 7 players. It uses a standard 52-card deck.
The objective is to win tricks. Players who fail to win at least one trick in a round are eliminated.
@@ -29,14 +29,17 @@ If they win a trick, they re-enter the game in the following round. When this ha
## About the project
This project is a Scala implementation of the Knock-out Whist card game. It is maintained by 2 students of the HTWG Konstanz.
Last stable build: [![Build-Status-Master](https://teamcity.janis-eccarius.de/guestAuth/app/rest/builds/buildType:(id:KnockOutWhist_BuildAndTest),branch:master/statusIcon.png)](https://teamcity.janis-eccarius.de/viewType.html?buildTypeId=KnockOutWhist_BuildAndTest&branch=master)
Last stable build: [![Build-Status-Master](https://teamcity.janis-eccarius.de/app/rest/builds/buildType:id:KnockOutWhist_BuildAndTest/statusIcon.svg)](https://teamcity.janis-eccarius.de/viewType.html?buildTypeId=KnockOutWhist_BuildAndTest&branch=master)
Last development build: [![Build-Status-Dev](https://teamcity.janis-eccarius.de/guestAuth/app/rest/builds/buildType:(id:KnockOutWhist_BuildAndTest),branch:development/statusIcon.png)](https://teamcity.janis-eccarius.de/viewType.html?buildTypeId=KnockOutWhist_BuildAndTest&branch=development)
Last development build: [![Build-Status-Dev](https://teamcity.janis-eccarius.de/app/rest/builds/buildType:id:KnockOutWhist_BuildAndTest,branch:name:development/statusIcon.svg)](https://teamcity.janis-eccarius.de/viewType.html?buildTypeId=KnockOutWhist_BuildAndTest&branch=development)
Gitea: [https://git.janis-eccarius.de/KnockOutWhist/KnockOutWhist](https://git.janis-eccarius.de/KnockOutWhist/KnockOutWhist)
GitHub (Mirror): [https://github.com/16Janis12/KnockOutWhist](https://github.com/16Janis12/KnockOutWhist)
SonarQube: [https://sonarcloud.io/project/overview?id=16Janis12_KnockOutWhist](https://sonarcloud.io/project/overview?id=16Janis12_KnockOutWhist)
Coveralls: [https://coveralls.io/github/16Janis12/KnockOutWhist](https://coveralls.io/github/16Janis12/KnockOutWhist)
## Licence
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

View File

@@ -1,5 +1,5 @@
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "3.5.1"
Compile/mainClass := Some("de.knockoutwhist.KnockOutWhist")
@@ -10,17 +10,43 @@ version := {
val buildNR = sys.env.getOrElse("BUI_COUNTER", "1")
s"$major.$minor.$buildNR"
}
organization := "de.knockoutwhist"
ThisBuild / organization := "de.knockoutwhist"
ThisBuild / version := version.value
ThisBuild / scalaVersion := "3.5.1"
lazy val root = (project in file("."))
.settings(
name := "Projekt-zu-SE"
name := "Projekt-zu-SE",
fork in run := true,
javaOptions in run += "-Xmx2G",
assembly / mainClass := Some("de.knockoutwhist.KnockOutWhist"),
assembly / assemblyJarName := s"KnockOutWhist-${version.value}.jar",
)
libraryDependencies += "org.scalactic" %% "scalactic" % "3.2.18"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.18" % "test"
libraryDependencies +="io.github.mkpaz" % "atlantafx-base" % "2.0.1"
libraryDependencies += "org.scalafx" %% "scalafx" % "22.0.0-R33"
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "2.3.0"
libraryDependencies += "org.playframework" %% "play-json" % "3.1.0-M1"
libraryDependencies ++= {
// Determine OS version of JavaFX binaries
lazy val osName = System.getProperty("os.name") match {
case n if n.startsWith("Linux") => "linux"
case n if n.startsWith("Mac") => "mac"
case n if n.startsWith("Windows") => "win"
case _ => throw new Exception("Unknown platform!")
}
Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
.map(m => "org.openjfx" % s"javafx-$m" % "21" classifier osName)
}
libraryDependencies += "net.codingwell" %% "scala-guice" % "7.0.0"
Test / testOptions += Tests.Filter(_.equals("de.knockoutwhist.TestSequence"))

View File

@@ -1 +1,3 @@
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.1")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.1")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.1")

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -1,5 +0,0 @@
import de.knockoutwhist.cards.CardManager
val originalDeck = List(CardManager.cardContainer)
CardManager.shuffleAndReset()
val shuffledDeck = CardManager.cardContainer

View File

@@ -1,24 +1,36 @@
package de.knockoutwhist
import de.knockoutwhist.control.MatchControl
import de.knockoutwhist.control.text.TextMatchControl
import com.google.inject.{Guice, Inject, Injector}
import de.knockoutwhist.components.{Configuration, DefaultConfiguration}
import de.knockoutwhist.control.{ControlHandler, ControlThread}
import de.knockoutwhist.di.KnockOutConfigurationModule
import de.knockoutwhist.events.ui.GameState.MAIN_MENU
import de.knockoutwhist.events.ui.GameStateUpdateEvent
import de.knockoutwhist.ui.gui.GUIMain
import de.knockoutwhist.ui.tui.TUIMain
object KnockOutWhist {
val matchControl: MatchControl = TextMatchControl
/*
Debug mode:
Debug mode
- Disables the random shuffle of the cards
*/
private[knockoutwhist] var DEBUG_MODE_VAR: Boolean = true
private val injector: Injector = Guice.createInjector(KnockOutConfigurationModule())
val config: Configuration = injector.getInstance(classOf[Configuration])
private[knockoutwhist] var DEBUG_MODE_VAR: Boolean = false
def DEBUG_MODE = DEBUG_MODE_VAR
def debugmode: Boolean = DEBUG_MODE_VAR
def main(args: Array[String]): Unit = {
if(!matchControl.initial()) throw new IllegalStateException("Game could not be started.")
ControlThread.start()
config.persistenceManager.loadManager()
if(!TUIMain.initial) throw new IllegalStateException("TUI could not be started.")
if(!GUIMain.initial) throw new IllegalStateException("GUI could not be started.")
ControlThread.runLater {
ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
}
}
}

View File

@@ -1,8 +1,5 @@
package de.knockoutwhist.cards
import de.knockoutwhist.cards.CardValue.Ten
import de.knockoutwhist.cards.Suit
enum Suit(identifier: String):
def cardType(): String = identifier
@@ -34,34 +31,6 @@ enum CardValue(identifier: String):
end CardValue
case class Card(cardValue: CardValue, suit: Suit) {
def cardColour(suit: Suit): String = suit match {
case Suit.Hearts | Suit.Diamonds => Console.RED
case Suit.Clubs | Suit.Spades => Console.BLACK
}
def renderAsString(): Vector[String] = {
if (cardValue == Ten) {
return Vector(
s"┌─────────┐",
s"${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}",
"│ │",
s"${cardColour(suit)}${Console.BOLD}${suit.cardType()}${Console.RESET}",
"│ │",
s"${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}",
s"└─────────┘"
)
}
Vector(
s"┌─────────┐",
s"${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}",
"│ │",
s"${cardColour(suit)}${Console.BOLD}${suit.cardType()}${Console.RESET}",
"│ │",
s"${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}",
s"└─────────┘"
)
}
override def toString: String = s"$cardValue of $suit"
//Combined String
override def toString: String = s"$cardValue of $suit"
}

View File

@@ -1,50 +1,21 @@
package de.knockoutwhist.cards
import de.knockoutwhist.KnockOutWhist
trait CardManager {
import scala.collection.mutable.ListBuffer
import scala.util.Random
def cardContainer: List[Card]
object CardManager {
def shuffleAndReset(): Unit
def resetOrder(): Unit
var cardContainer: List[Card] = {
val cc = ListBuffer[Card]()
for (suit <- Suit.values) {
for (cardValue <- CardValue.values) {
cc += Card(cardValue, suit)
}
}
cc.toList
}
private var currentIdx = 0
def nextCard(): Card
def shuffleAndReset(): Unit = {
cardContainer = Random.shuffle(cardContainer)
currentIdx = 0
}
def createHand(amount: Int = 7): Hand
def resetOrder(): Unit = {
cardContainer = cardContainer.sortBy(c => (c.suit.ordinal, c.cardValue.ordinal))
currentIdx = 0
}
def nextCard(): Card = {
val card = cardContainer(currentIdx)
if (currentIdx + 1 > 51) {
throw new IndexOutOfBoundsException("Trying to access card 53(out of bounds)")
} else {
currentIdx += 1
card
}
}
def grabSpecificCard(card: Card): Card
def createHand(amount: Int = 7): Hand = {
val hand = ListBuffer[Card]()
for (_ <- 1 to amount) {
hand += nextCard()
}
Hand(hand.toList)
}
def currentIndx: Int
def setState(cc: List[Card], currentIndex: Int): Unit
}

View File

@@ -1,7 +1,5 @@
package de.knockoutwhist.cards
import scala.collection.mutable.ListBuffer
case class Hand(cards: List[Card]) {
def removeCard(card: Card): Hand = {
@@ -19,11 +17,5 @@ case class Hand(cards: List[Card]) {
def hasTrumpSuit(trumpSuit: Suit): Boolean = {
cards.exists(_.suit == trumpSuit)
}
def renderAsString() : List[String] = {
val cardStrings = cards.map(_.renderAsString())
val zipped = cardStrings.transpose
zipped.map(_.mkString(" "))
}
}

View File

@@ -0,0 +1,60 @@
package de.knockoutwhist.cards.base
import de.knockoutwhist.cards.*
import scala.collection.mutable.ListBuffer
import scala.util.Random
class CardBaseManager extends CardManager {
override def setState(cc: List[Card], currentIndex: Int): Unit = {
this.cc = cc
this.currentIdx = currentIndex
}
override def cardContainer: List[Card] = cc
private var cc: List[Card] = {
val cc = ListBuffer[Card]()
for (suit <- Suit.values) {
for (cardValue <- CardValue.values) {
cc += Card(cardValue, suit)
}
}
cc.toList
}
private var currentIdx = 0
override def currentIndx: Int = currentIdx
override def shuffleAndReset(): Unit = {
cc = Random.shuffle(cc)
currentIdx = 0
}
override def resetOrder(): Unit = {
cc = cc.sortBy(c => (c.suit.ordinal, c.cardValue.ordinal))
currentIdx = 0
}
override def nextCard(): Card = {
val card = cc(currentIdx)
if (currentIdx + 1 > 51) {
throw new IndexOutOfBoundsException("Trying to access card 53(out of bounds)")
} else {
currentIdx += 1
card
}
}
override def createHand(amount: Int = 7): Hand = {
val hand = ListBuffer[Card]()
for (_ <- 1 to amount) {
hand += nextCard()
}
Hand(hand.toList)
}
override def grabSpecificCard(card: Card): Card = {
cc.filter(c => c.suit == card.suit && c.cardValue == card.cardValue).head
}
}

View File

@@ -0,0 +1,21 @@
package de.knockoutwhist.cards.stub
import de.knockoutwhist.cards.*
object StubCardManager extends CardManager {
override def cardContainer: List[Card] = List()
override def shuffleAndReset(): Unit = {}
override def resetOrder(): Unit = {}
override def nextCard(): Card = Card(CardValue.Ace, Suit.Clubs)
override def createHand(amount: Int): Hand = Hand(List(Card(CardValue.Ace, Suit.Clubs)))
override def grabSpecificCard(card: Card): Card = card
override def currentIndx: Int = -1
override def setState(cc: List[Card], currentIndex: Int): Unit = {}
}

View File

@@ -0,0 +1,23 @@
package de.knockoutwhist.components
import de.knockoutwhist.cards.CardManager
import de.knockoutwhist.control.*
import de.knockoutwhist.persistence.PersistenceManager
import de.knockoutwhist.persistence.formats.FileFormatter
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.utils.CustomPlayerQueue
trait Configuration {
def maincomponent: Maincomponent
def matchcomponent: Matchcomponent
def playeractrcomponent: Playeractrcomponent
def playerlogcomponent: Playerlogcomponent
def roundlogcomponent: Roundlogcomponent
def trickcomponent: Tricklogcomponent
def cardManager: CardManager
def persistenceManager: PersistenceManager
def fileFormatter: FileFormatter
def createRightQueue(players: Array[AbstractPlayer], start: Int = 0): CustomPlayerQueue[AbstractPlayer]
}

View File

@@ -0,0 +1,35 @@
package de.knockoutwhist.components
import com.google.inject.Guice
import de.knockoutwhist.cards.CardManager
import de.knockoutwhist.cards.base.CardBaseManager
import de.knockoutwhist.control.*
import de.knockoutwhist.control.controllerBaseImpl.*
import de.knockoutwhist.di.KnockOutLogicModule
import de.knockoutwhist.persistence.PersistenceManager
import de.knockoutwhist.persistence.formats.FileFormatter
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.utils.CustomPlayerQueue
import de.knockoutwhist.utils.baseQueue.{CustomPlayerBaseQueue, CustomPlayerQueueBuilder, QueueBuilder}
object DefaultConfiguration extends Configuration {
private val injector = Guice.createInjector(KnockOutLogicModule())
def maincomponent: Maincomponent = injector.getInstance(classOf[Maincomponent])
def matchcomponent: Matchcomponent = injector.getInstance(classOf[Matchcomponent])
def playeractrcomponent: Playeractrcomponent = injector.getInstance(classOf[Playeractrcomponent])
def playerlogcomponent: Playerlogcomponent = injector.getInstance(classOf[Playerlogcomponent])
def roundlogcomponent: Roundlogcomponent = injector.getInstance(classOf[Roundlogcomponent])
def trickcomponent: Tricklogcomponent = injector.getInstance(classOf[Tricklogcomponent])
def cardManager: CardManager = injector.getInstance(classOf[CardManager])
def persistenceManager: PersistenceManager = injector.getInstance(classOf[PersistenceManager])
def fileFormatter: FileFormatter = injector.getInstance(classOf[FileFormatter])
override def createRightQueue(players: Array[AbstractPlayer], start: Int): CustomPlayerQueue[AbstractPlayer] = {
val builder = injector.getInstance(classOf[QueueBuilder])
builder.setStart(start)
builder.setPlayer(players)
builder.build()
}
}

View File

@@ -0,0 +1,88 @@
package de.knockoutwhist.control
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.cards.base.CardBaseManager
import de.knockoutwhist.cards.{Card, Hand, Suit}
import de.knockoutwhist.control.ControlHandler
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Round, Trick}
import scala.util.Random
case object AILogic {
def decideCard(ai: AbstractPlayer, round: Round, trick: Trick): Card = {
if(trick.firstCard.isEmpty) return ai.currentHand().get.cards.maxBy(_.cardValue.ordinal)
val firstCardSuit = trick.firstCard.get.suit
val hand = ai.currentHand().get
val cardsOfSuit = hand.cards.filter(_.suit == firstCardSuit)
val trumpsInGame = trick.cards.keys.filter(_.suit == round.trumpSuit)
if (cardsOfSuit.isEmpty) {
val trumpCards = hand.cards.filter(_.suit == round.trumpSuit)
if (trumpCards.isEmpty) hand.cards.minBy(_.cardValue.ordinal)
else {
val bestOption = decideWhichTrumpCard(hand, round, trick, trumpsInGame.toList)
grabBestResult(bestOption, hand, round, trick)
}
} else {
if(trumpsInGame.nonEmpty) cardsOfSuit.minBy(_.cardValue.ordinal)
else cardsOfSuit.maxBy(_.cardValue.ordinal)
}
KnockOutWhist.config.cardManager.nextCard()
}
private def grabBestResult(bestOption: Option[Card], hand: Hand, round: Round, trick: Trick): Card = {
bestOption match {
case Some(card) => card
case None =>
val card = hand.cards.filter(_.suit != round.trumpSuit)
if (card.isEmpty) hand.cards.minBy(_.cardValue.ordinal)
else card.minBy(_.cardValue.ordinal)
}
}
private def decideWhichTrumpCard(hand: Hand, round: Round, trick: Trick, activeTrumps: List[Card]): Option[Card] = {
val trumpCards = hand.cards.filter(_.suit == round.trumpSuit)
if (round.playerQueue.size - trick.cards.size == 1 && activeTrumps.isEmpty) return Some(trumpCards.minBy(_.cardValue.ordinal))
val highestTrump = trumpCards.maxBy(_.cardValue.ordinal)
val activeTrump = activeTrumps.maxBy(_.cardValue.ordinal)
if (highestTrump.cardValue.ordinal < activeTrump.cardValue.ordinal) None
else {
val higherTrumps = trumpCards.filter(_.cardValue.ordinal > activeTrump.cardValue.ordinal)
if(round.playerQueue.size - trick.cards.size <= round.playersin.size * 0.5) Some(higherTrumps.minBy(_.cardValue.ordinal))
else Some(highestTrump)
}
}
def decideTrumpSuit(ai: AbstractPlayer): Suit = {
val hand = ai.currentHand().get
hand.cards.groupBy(_.suit).maxBy(_._2.size)._1
}
def decideTie(min: Int, max: Int): Int = {
Random.between(min, max+1)
}
def decideDogCard(ai: AbstractPlayer, round: Round, trick: Trick, needstoplay: Boolean): Option[Card] = {
val firstCardSuit = trick.firstCard.get.suit
val hand = ai.currentHand().get
val trumpsuit = round.trumpSuit
val trumpsuitPlayed = trick.cards.keys.exists(_.suit == trumpsuit)
if(needstoplay) {
Some(hand.cards.head)
} else if(trumpsuitPlayed) {
sortbestcard(trick, trumpsuit, hand)
} else {
sortbestcard(trick, firstCardSuit, hand)
}
}
private def sortbestcard(trick: Trick, suit: Suit, hand: Hand): Option[Card] = {
val highestCard = trick.cards.keys.filter(_.suit == suit).maxBy(_.cardValue.ordinal)
if (hand.cards.head.suit == suit && hand.cards.head.cardValue.ordinal > highestCard.cardValue.ordinal) {
return Some(hand.cards.head)
}
None
}
}

View File

@@ -0,0 +1,23 @@
package de.knockoutwhist.control
import de.knockoutwhist.ui.gui.GUIMain
import de.knockoutwhist.ui.tui.TUIMain
import de.knockoutwhist.utils.events.EventHandler
import de.knockoutwhist.utils.{CustomThread, DelayHandler}
object ControlHandler extends EventHandler {
addListener(GUIMain)
addListener(TUIMain)
addListener(DelayHandler)
}
object ControlThread extends CustomThread {
setName("ControlThread")
def isControlThread: Boolean = Thread.currentThread().equals(ControlThread)
override def instance: CustomThread = ControlThread
}

View File

@@ -0,0 +1,25 @@
package de.knockoutwhist.control
import de.knockoutwhist.cards.Card
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
trait Maincomponent {
def startMatch(): Unit
def enteredPlayers(players: List[AbstractPlayer]): Unit
def controlMatch(matchImpl: Match): Unit
def controlRound(matchImpl: Match, round: Round): Unit
def endRound(matchImpl: Match, round: Round, winner: AbstractPlayer, playersOut: List[AbstractPlayer]): Unit
def controlTrick(matchImpl: Match, round: Round, trick: Trick, currentIndex: Int = 0): Unit
def controlPlayer(matchImpl: Match, round: Round, trick: Trick, player: AbstractPlayer, currentIndex: Int): Unit
def playCard(trick: Trick, card: Card, player: AbstractPlayer): Trick
}

View File

@@ -1,24 +0,0 @@
package de.knockoutwhist.control
import de.knockoutwhist.rounds.{Match, Round, Trick}
trait MatchControl {
def initial(): Boolean
def start(): Unit
def playerControl: PlayerControl
/**
* Start the next round
* @return the next round or null if the match is over
*/
def nextRound(matchImpl: Match): Round
/**
* Start the next trick
* @return the last trick or null if the round is over
*/
def nextTrick(roundImpl: Round): Trick
}

View File

@@ -0,0 +1,8 @@
package de.knockoutwhist.control
import de.knockoutwhist.rounds.Match
trait Matchcomponent {
def isOver(matchImpl: Match): Boolean
}

View File

@@ -1,16 +0,0 @@
package de.knockoutwhist.control
import de.knockoutwhist.cards.{Card, Suit}
import de.knockoutwhist.player.Player
import de.knockoutwhist.rounds.Round
trait PlayerControl {
def playCard(player: Player): Card
def dogplayCard(player: Player, round: Round): Option[Card]
def determineWinnerTie(players: List[Player]): Player
def pickNextTrumpsuit(player: Player): Suit
def showCards(player: Player): Boolean
def showWon(player: Player, round: Round): String
}

View File

@@ -0,0 +1,15 @@
package de.knockoutwhist.control
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
trait Playeractrcomponent {
def playCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit
def dogplayCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit
def pickNextTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean, player: AbstractPlayer): Unit
}

View File

@@ -0,0 +1,23 @@
package de.knockoutwhist.control
import de.knockoutwhist.cards.{Card, Suit}
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round}
import scala.collection.immutable
import scala.util.Try
trait Playerlogcomponent {
def trumpsuitStep(matchImpl: Match, remaining_players: List[AbstractPlayer]): Unit
def trumpSuitSelected(matchImpl: Match, suit: Try[Suit], remaining_players: List[AbstractPlayer], firstRound: Boolean, decided: AbstractPlayer): Unit
def preSelect(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer]): Unit
def selectTie(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit
def selectedTie(winner: List[AbstractPlayer],matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], value: Try[Int], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit
def evaluateTieWinner(matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card]): Unit
}

View File

@@ -0,0 +1,19 @@
package de.knockoutwhist.control
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round}
trait Roundlogcomponent {
def isOver(round: Round): Boolean
def dogNeedsToPlay(round: Round): Boolean
def finalizeRound(round: Round, matchImpl: Match, force: Boolean = false): (Match, Round, List[AbstractPlayer], List[AbstractPlayer])
def remainingPlayers(round: Round): List[AbstractPlayer]
def provideCards(matchImpl: Match, players: List[AbstractPlayer]): (Match,List[AbstractPlayer])
def smashResults(round: Round): Round
}

View File

@@ -0,0 +1,18 @@
package de.knockoutwhist.control
import de.knockoutwhist.cards.Card
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
import scala.util.Try
trait Tricklogcomponent {
def controlSuitplayed(card: Try[Card], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit
def controlDogPlayed(card: Try[Option[Card]], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit
def alternativeCards(card: Card, round: Round, trick: Trick, player: AbstractPlayer): List[Card]
def wonTrick(trick: Trick, round: Round): (AbstractPlayer, Trick)
}

View File

@@ -0,0 +1,110 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.cards.Card
import de.knockoutwhist.control.*
import de.knockoutwhist.events.GLOBAL_STATUS.SHOW_FINISHED_MATCH
import de.knockoutwhist.events.PLAYER_STATUS.SHOW_WON_PLAYER_TRICK
import de.knockoutwhist.events.ROUND_STATUS.{PLAYERS_OUT, WON_ROUND}
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
import de.knockoutwhist.events.ui.GameState.{MAIN_MENU, PLAYERS, TIE}
import de.knockoutwhist.events.ui.GameStateUpdateEvent
import de.knockoutwhist.events.util.DelayEvent
import de.knockoutwhist.events.{ShowGlobalStatus, ShowPlayerStatus, ShowRoundStatus}
import de.knockoutwhist.persistence.MethodEntryPoint.{ControlMatch, ControlRound, ControlTrick}
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
import de.knockoutwhist.undo.UndoManager
import de.knockoutwhist.undo.commands.EnterPlayersCommand
import de.knockoutwhist.utils.Implicits.*
object MainLogic extends Maincomponent {
def startMatch(): Unit = {
ControlHandler.invoke(GameStateUpdateEvent(PLAYERS))
}
def enteredPlayers(players: List[AbstractPlayer]): Unit = {
UndoManager.doStep(EnterPlayersCommand(players))
}
def controlMatch(matchImpl: Match): Unit = {
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlMatch)
if(KnockOutWhist.config.matchcomponent.isOver(matchImpl)) {
ControlHandler.invoke(ShowGlobalStatus(SHOW_FINISHED_MATCH, KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last).head))
//ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
} else {
val remainingPlayer = matchImpl.roundlist.isEmpty ? matchImpl.totalplayers |: KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last)
val newMatch = KnockOutWhist.config.roundlogcomponent.provideCards(matchImpl, remainingPlayer)
KnockOutWhist.config.playerlogcomponent.trumpsuitStep(newMatch._1, newMatch._2)
}
}
def controlRound(matchImpl: Match, round: Round): Unit = {
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
KnockOutWhist.config.persistenceManager.updateRound(round)
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlRound)
if(!KnockOutWhist.config.roundlogcomponent.isOver(round)) {
val trick = Trick()
controlTrick(matchImpl, round, trick)
return
}
val result = KnockOutWhist.config.roundlogcomponent.finalizeRound(KnockOutWhist.config.roundlogcomponent.smashResults(round), matchImpl)
if(result._3.size == 1) {
endRound(result._1, result._2, result._3.head, result._4)
} else {
KnockOutWhist.config.playerlogcomponent.preSelect(result._3, result._1, result._2, result._4)
}
}
def endRound(matchImpl: Match, round: Round, winner: AbstractPlayer, playersOut: List[AbstractPlayer]): Unit = {
val finalRound = Round(round.trumpSuit, round.tricklist, round.playersin, playersOut, round.startingPlayer, winner, firstRound = round.firstRound)
val newMatch = matchImpl.addRound(finalRound)
ControlHandler.invoke(ShowRoundStatus(WON_ROUND, finalRound, winner))
ControlHandler.invoke(DelayEvent(2000L))
if (finalRound.playersout.nonEmpty) {
ControlHandler.invoke(ShowRoundStatus(PLAYERS_OUT, finalRound))
}
controlMatch(newMatch)
}
def controlTrick(matchImpl: Match, round: Round, trick: Trick, currentIndex: Int = 0): Unit = {
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
KnockOutWhist.config.persistenceManager.updateRound(round)
KnockOutWhist.config.persistenceManager.updateTrick(trick)
KnockOutWhist.config.persistenceManager.updateCurrentIndex(currentIndex)
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlTrick)
if(currentIndex < round.playersin.size) {
val player = round.playerQueue.nextPlayer()
controlPlayer(matchImpl, round, trick, player, currentIndex)
}else {
val result = KnockOutWhist.config.trickcomponent.wonTrick(trick, round)
val newRound = round.addTrick(result._2)
ControlHandler.invoke(ShowPlayerStatus(SHOW_WON_PLAYER_TRICK, result._1, result._2))
newRound.playerQueue.resetAndSetStart(result._1)
ControlHandler.invoke(DelayEvent(1000L))
controlRound(matchImpl, newRound)
}
}
def controlPlayer(matchImpl: Match, round: Round, trick: Trick, player: AbstractPlayer, currentIndex: Int): Unit = {
ControlHandler.invoke(ShowCurrentTrickEvent(round, trick))
if (!player.doglife) {
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
} else if (player.currentHand().exists(_.cards.nonEmpty)) {
KnockOutWhist.config.playeractrcomponent.dogplayCard(matchImpl, player, round, trick, currentIndex)
}else {
controlTrick(matchImpl, round, trick, currentIndex+1)
}
}
def playCard(trick: Trick, card: Card, player: AbstractPlayer): Trick = {
if (trick.firstCard.isEmpty) {
trick.setfirstcard(card).addCard(card, player)
} else {
trick.addCard(card, player)
}
}
}

View File

@@ -0,0 +1,15 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.control.{ControlHandler, Matchcomponent}
import de.knockoutwhist.rounds.Match
object MatchLogic extends Matchcomponent {
def isOver(matchImpl: Match): Boolean = {
if (matchImpl.roundlist.isEmpty) {
false
} else {
KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last).size == 1
}
}
}

View File

@@ -0,0 +1,36 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.control.{ControlHandler, Playeractrcomponent}
import de.knockoutwhist.events.PLAYER_STATUS.*
import de.knockoutwhist.events.ShowPlayerStatus
import de.knockoutwhist.events.cards.RenderHandEvent
import de.knockoutwhist.events.util.DelayEvent
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
object PlayerControl extends Playeractrcomponent {
def playCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit = {
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
ControlHandler.invoke(DelayEvent(500))
ControlHandler.invoke(ShowPlayerStatus(SHOW_PLAY_CARD, player))
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, true))
player.handlePlayCard(player.currentHand().get, matchImpl, round, trick, currentIndex)
}
def dogplayCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit = {
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
ControlHandler.invoke(DelayEvent(500))
ControlHandler.invoke(ShowPlayerStatus(SHOW_DOG_PLAY_CARD, player, KnockOutWhist.config.roundlogcomponent.dogNeedsToPlay(round)))
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
player.handleDogPlayCard(player.currentHand().get, matchImpl, round, trick, currentIndex, KnockOutWhist.config.roundlogcomponent.dogNeedsToPlay(round))
}
def pickNextTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean, player: AbstractPlayer): Unit = {
ControlHandler.invoke(ShowPlayerStatus(SHOW_TRUMPSUIT_OPTIONS, player))
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
player.handlePickTrumpsuit(matchImpl, remaining_players, firstRound)
}
}

View File

@@ -0,0 +1,107 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.cards.{Card, Suit}
import de.knockoutwhist.control.{ControlHandler, Playerlogcomponent}
import de.knockoutwhist.events.ERROR_STATUS.{INVALID_NUMBER, NOT_A_NUMBER}
import de.knockoutwhist.events.GLOBAL_STATUS.{SHOW_TIE, SHOW_TIE_TIE, SHOW_TIE_WINNER}
import de.knockoutwhist.events.PLAYER_STATUS.SHOW_TIE_NUMBERS
import de.knockoutwhist.events.cards.ShowTieCardsEvent
import de.knockoutwhist.events.ui.GameState.{INGAME, TIE}
import de.knockoutwhist.events.ui.GameStateUpdateEvent
import de.knockoutwhist.events.util.DelayEvent
import de.knockoutwhist.events.{ShowErrorStatus, ShowGlobalStatus, ShowPlayerStatus}
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round}
import de.knockoutwhist.ui.gui.TieMenu
import de.knockoutwhist.undo.UndoManager
import de.knockoutwhist.undo.commands.{SelectTieCommand, TrumpSuitSelectedCommand}
import scala.collection.immutable
import scala.collection.mutable.ListBuffer
import scala.util.Try
object PlayerLogic extends Playerlogcomponent {
def trumpsuitStep(matchImpl: Match, remaining_players: List[AbstractPlayer]): Unit = {
if (matchImpl.roundlist.isEmpty) {
val randomTrumpsuit = matchImpl.cardManager.nextCard().suit
val newMatchImpl = matchImpl.setNumberOfCards(matchImpl.numberofcards - 1)
val round = new Round(randomTrumpsuit, remaining_players, true)
KnockOutWhist.config.maincomponent.controlRound(newMatchImpl, round)
} else {
val winner = matchImpl.totalplayers.filter(matchImpl.roundlist.last.winner.name == _.name).head
KnockOutWhist.config.playeractrcomponent.pickNextTrumpsuit(matchImpl, remaining_players, false, winner)
}
}
def trumpSuitSelected(matchImpl: Match, suit: Try[Suit], remaining_players: List[AbstractPlayer], firstRound: Boolean, decided: AbstractPlayer): Unit = {
if (suit.isFailure) {
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
KnockOutWhist.config.playeractrcomponent.pickNextTrumpsuit(matchImpl, remaining_players, firstRound, decided)
return
}
ControlHandler.invoke(GameStateUpdateEvent(INGAME))
UndoManager.doStep(TrumpSuitSelectedCommand(matchImpl, suit.get, remaining_players, false, decided))
}
def preSelect(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer]): Unit = {
if (!KnockOutWhist.debugmode) matchImpl.cardManager.shuffleAndReset()
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE))
ControlHandler.invoke(GameStateUpdateEvent(TIE))
selectTie(winners, matchImpl, round, playersout, immutable.HashMap(), 0, matchImpl.cardManager.cardContainer.size - (winners.length - 1))
}
def selectTie(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
ControlHandler.invoke(GameStateUpdateEvent(TIE))
if(currentIndex == winners.size) {
evaluateTieWinner(matchImpl, round, playersout, cut)
} else {
val player = winners(currentIndex)
ControlHandler.invoke(ShowPlayerStatus(SHOW_TIE_NUMBERS, player, remaining))
player.handlePickTieCard(winners, matchImpl, round, playersout, cut, currentStep, remaining, currentIndex)
}
}
def selectedTie(winner: List[AbstractPlayer],matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], value: Try[Int], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
if (value.isFailure) {
ControlHandler.invoke(ShowErrorStatus(NOT_A_NUMBER))
selectTie(winner, matchImpl, round, playersout, cut, currentStep, remaining, currentIndex)
return
}
val selCard = matchImpl.cardManager.cardContainer(currentStep + (value.get - 1))
UndoManager.doStep(SelectTieCommand(winner, matchImpl, round, playersout, cut, value.get, selCard, currentStep, remaining, currentIndex))
}
def evaluateTieWinner(matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card]): Unit = {
ControlHandler.invoke(ShowTieCardsEvent(cut.toList))
val winner: ListBuffer[AbstractPlayer] = ListBuffer()
var currentHighest: Card = null
for ((player, card) <- cut) {
if (currentHighest == null) {
currentHighest = card
winner += player
} else {
val compared = card.cardValue.ordinal.compareTo(currentHighest.cardValue.ordinal)
if (compared > 0) {
currentHighest = card
winner.clear()
winner += player
} else if (compared == 0) {
winner += player
}
}
}
if (winner.size == 1) {
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE_WINNER, winner.head))
KnockOutWhist.config.maincomponent.endRound(matchImpl, round, winner.head, playersout)
return
}
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE_TIE))
ControlHandler.invoke(DelayEvent(2000))
preSelect(winner.toList, matchImpl, round, playersout)
}
}

View File

@@ -0,0 +1,81 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.control.{ControlHandler, Roundlogcomponent}
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
import de.knockoutwhist.utils.Implicits.*
import scala.collection.mutable.ListBuffer
object RoundLogic extends Roundlogcomponent{
def isOver(round: Round): Boolean = {
round.playersin.map(_.currentHand()).count(_.get.cards.isEmpty) == round.playersin.size
}
def dogNeedsToPlay(round: Round): Boolean = {
round.playersin.filter(!_.doglife).map(_.currentHand()).exists(_.get.cards.isEmpty)
}
def finalizeRound(round: Round, matchImpl: Match, force: Boolean = false): (Match, Round, List[AbstractPlayer], List[AbstractPlayer]) = {
if (!force && round.tricklist.isEmpty)
throw new IllegalStateException("No tricks played in this round")
if (!force && !isOver(round))
throw new IllegalStateException("Not all tricks were played in this round")
val tricksMapped = round.tricklist
.map(t => t.winner)
.groupBy(identity).map((p, l) => (p, l.size)) //l.size = Anzahl gewonnener Tricks
val winners = tricksMapped
.filter((p, i) => i == tricksMapped.values.max)
.keys
var playersOut = round.firstRound
? List()
|: round.playersin.filter(!tricksMapped.contains(_))
var newMatch = matchImpl
var newRound = round
if (playersOut.nonEmpty && !matchImpl.dogLife) {
newMatch = matchImpl.setDogLife()
val playersUpdated = ListBuffer[AbstractPlayer]()
playersUpdated ++= tricksMapped.keys
playersOut.foreach(p => {
playersUpdated += p.setDogLife()
})
newMatch = newMatch.updatePlayers(playersUpdated.toList)
newRound = newRound.updatePlayersIn(playersUpdated.toList)
playersOut = List()
}
(newMatch, newRound, winners.toList, playersOut)
}
def remainingPlayers(round: Round): List[AbstractPlayer] = {
if (round.playersout == null) {
return round.playersin
}
round.playersin.filter(!round.playersout.contains(_))
}
def provideCards(matchImpl: Match, players: List[AbstractPlayer]): (Match,List[AbstractPlayer]) = {
if (!KnockOutWhist.debugmode) matchImpl.cardManager.shuffleAndReset()
val listbuff = new ListBuffer[AbstractPlayer]()
for (player <- players) {
if (!player.doglife) {
val newPlayer = player.provideHand(matchImpl.cardManager.createHand(matchImpl.numberofcards))
listbuff.addOne(newPlayer)
} else {
val newPlayer = player.provideHand(matchImpl.cardManager.createHand(1))
listbuff.addOne(newPlayer)
}
}
val matchResult = matchImpl.totalplayers.appendedAll(listbuff.toList).filter(!players.contains(_))
(matchImpl.updatePlayers(matchResult), listbuff.toList)
}
def smashResults(round: Round): Round = {
val correctPlayers = round.playersin.groupMapReduce(_.id)(identity)((a, *) => a)
val newTricks = round.tricklist.map(t => Trick(t.cards, correctPlayers.getOrElse(t.winner.id, t.winner), t.finished, t.firstCard))
Round(round.trumpSuit, newTricks, round.playersin, round.playersout, round.startingPlayer, round.winner, round.firstRound)
}
}

View File

@@ -0,0 +1,84 @@
package de.knockoutwhist.control.controllerBaseImpl
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.cards.{Card, Hand}
import de.knockoutwhist.control.controllerBaseImpl.PlayerControl
import de.knockoutwhist.control.{ControlHandler, Tricklogcomponent}
import de.knockoutwhist.events.ERROR_STATUS.{INVALID_INPUT, INVALID_NUMBER, WRONG_CARD}
import de.knockoutwhist.events.ShowErrorStatus
import de.knockoutwhist.player.AbstractPlayer
import de.knockoutwhist.rounds.{Match, Round, Trick}
import de.knockoutwhist.undo.UndoManager
import de.knockoutwhist.undo.commands.{PlayerPlayCommand, PlayerPlayDogCommand}
import scala.util.Try
object TrickLogic extends Tricklogcomponent {
def controlSuitplayed(card: Try[Card], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit = {
if (card.isFailure) {
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
return
}
val realCard = card.get
if (trick.firstCard.isDefined) {
val firstCard = trick.firstCard.get
if (firstCard.suit != realCard.suit) {
var hasSuit = false
for (cardInHand <- player.currentHand().get.cards) {
if (cardInHand.suit == firstCard.suit) {
hasSuit = true
}
}
if (hasSuit) {
ControlHandler.invoke(ShowErrorStatus(WRONG_CARD, firstCard))
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
return
}
}
}
UndoManager.doStep(PlayerPlayCommand(matchImpl, round, trick, player, realCard, currentIndex))
}
def controlDogPlayed(card: Try[Option[Card]], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit = {
if (card.isFailure) {
ControlHandler.invoke(ShowErrorStatus(INVALID_INPUT))
KnockOutWhist.config.playeractrcomponent.dogplayCard(matchImpl, player, round, trick, currentIndex)
return
}
UndoManager.doStep(PlayerPlayDogCommand(matchImpl, round, trick, player, card.get, currentIndex))
}
def alternativeCards(card: Card, round: Round, trick: Trick, player: AbstractPlayer): List[Card] = {
if (trick.firstCard.isDefined) {
val firstCard = trick.firstCard.get
if (firstCard.suit != card.suit) {
val alternatives: List[Card] = for cardInHand <- player.currentHand().get.cards
if cardInHand.suit == firstCard.suit
yield cardInHand
if(round.trumpSuit == card.suit && alternatives.isEmpty) {
return Nil
}
if (alternatives.nonEmpty) {
return alternatives
}
}
}
Nil
}
def wonTrick(trick: Trick, round: Round): (AbstractPlayer, Trick) = {
val winningCard = {
if (trick.cards.keys.exists(_.suit == round.trumpSuit)) {
trick.cards.keys.filter(_.suit == round.trumpSuit).maxBy(_.cardValue.ordinal) //stream
} else {
trick.cards.keys.filter(_.suit == trick.firstCard.get.suit).maxBy(_.cardValue.ordinal) //stream
}
}
val winningPlayer = trick.cards(winningCard)
val finalTrick = Trick(trick.cards, winningPlayer, true)
(winningPlayer, finalTrick)
}
}

View File

@@ -1,205 +0,0 @@
package de.knockoutwhist.control.text
import de.knockoutwhist.KnockOutWhist
import de.knockoutwhist.cards.Card
import de.knockoutwhist.control.{MatchControl, PlayerControl}
import de.knockoutwhist.player.Player
import de.knockoutwhist.rounds.{Match, Round, Trick}
import de.knockoutwhist.utils.CustomPlayerQueue
import scala.compiletime.uninitialized
import scala.io.StdIn
import scala.util.Random
object TextMatchControl extends MatchControl {
private[control] var playerQueue: CustomPlayerQueue[Player] = uninitialized
private var init = false
override def initial(): Boolean = {
if(init) {
println("The game is already running.")
return false
}
init = true
println("Welcome to Knockout Whist!")
start()
true
}
override def start(): Unit = {
while(true) { //Main Gameplay Loop
val input = printMenu()
input match {
case "1" =>
startMatch()
case "2" =>
println("Exiting the game.")
return
case _ =>
println("Invalid input. Please try again.")
}
}
}
private[control] def startMatch(): Player = {
clearConsole()
println("Starting a new match.")
val players = enterPlayers()
playerQueue = CustomPlayerQueue[Player](players, Random.nextInt(players.length))
clearConsole()
controlMatch()
}
private[control] def enterPlayers(): Array[Player] = {
println("Please enter the names of the players, separated by a comma.")
val names = StdIn.readLine().split(",")
if(names.length < 2) {
println("Please enter at least two names.")
return enterPlayers()
}
if(names.distinct.length != names.length) {
println("Please enter unique names.")
return enterPlayers()
}
if(names.count(_.trim.isBlank) > 0 || names.count(_.trim.length <= 2) > 0 || names.count(_.trim.length > 10) > 0) {
println("Please enter valid names. Those can not be empty, shorter than 2 or longer then 10 characters.")
return enterPlayers()
}
names.map(s => Player(s))
}
private[control] def controlMatch(): Player = {
val matchImpl = Match(playerQueue.toList)
while (!matchImpl.isOver) {
val roundImpl = controlRound(matchImpl)
}
clearConsole()
println(s"The match is over. The winner is ${matchImpl.finalizeMatch().name}.")
matchImpl.finalizeMatch()
}
private[control] def controlRound(matchImpl: Match): Round = {
val roundImpl = nextRound(matchImpl)
clearConsole(10)
println(s"Starting a new round. The trump suit is ${roundImpl.trumpSuit}.")
clearConsole(2)
while (!roundImpl.isOver) {
controlTrick(roundImpl)
}
val (roundWinner, finalRound) = roundImpl.finalizeRound()
println(s"${roundWinner.name} won the round.")
if(!KnockOutWhist.DEBUG_MODE) Thread.sleep(5000L)
if(finalRound.players_out.nonEmpty) {
println("The following players are out of the game:")
finalRound.players_out.foreach(p => {
println(p.name)
playerQueue.remove(p)
})
}
playerQueue.resetAndSetStart(roundWinner)
finalRound
}
private[control] def controlTrick(round: Round): Trick = {
val trick = nextTrick(round)
for (player <- playerQueue) {
clearConsole()
println(printTrick(round))
if (!player.doglife) {
val rightCard = controlSuitplayed(trick, player)
player.removeCard(rightCard)
trick.playCard(rightCard, player)
} else if (player.currentHand().exists(_.cards.nonEmpty)) {
val card = playerControl.dogplayCard(player, round)
if (card.isEmpty) {
println(f"Player $player decided to not play his card")
} else {
player.removeCard(card.get)
trick.playCard(card.get, player)
}
}
}
val (winner, finalTrick) = trick.wonTrick()
clearConsole()
println(printTrick(round))
println(s"${winner.name} won the trick.")
clearConsole(2)
playerQueue.resetAndSetStart(winner)
if(!KnockOutWhist.DEBUG_MODE) Thread.sleep(3000L)
finalTrick
}
private[control] def controlSuitplayed(trick: Trick, player: Player): Card = {
var card = playerControl.playCard(player)
if (trick.get_first_card().isDefined) {
while (!(trick.get_first_card().get.suit == card.suit)) {
var hasSuit = false
for (cardInHand <- player.currentHand().get.cards) {
if (cardInHand.suit == trick.get_first_card().get.suit) {
hasSuit = true
}
}
if(!hasSuit) {
return card
}else {
println(f"You have to play a card of suit: ${trick.get_first_card().get.suit}\n")
card = playerControl.playCard(player)
}
}
}
card
}
private[control] def printMenu(): String = {
println("Please select an option:")
println("1. Start a new match")
println("2. Exit")
StdIn.readLine()
}
private[control] def printTrick(round: Round): String = {
val sb = new StringBuilder()
sb.append("Current Trick:\n")
sb.append("Trump-Suit: " + round.trumpSuit + "\n")
if(round.get_current_trick().get_first_card().isDefined) {
sb.append(s"Suit to play: ${round.get_current_trick().get_first_card().get.suit}\n")
}
for((card, player) <- round.get_current_trick().cards) {
sb.append(s"${player.name} played ${card.toString}\n")
}
sb.toString()
}
private def clearConsole(lines: Int = 32): Int = {
var l = 0
for(_ <- 0 until lines) {
println()
l += 1
}
l
}
override def playerControl: PlayerControl = {
TextPlayerControl
}
override def nextRound(matchImpl: Match): Round = {
if(matchImpl.isOver) {
println(s"The match is over. The winner is ${matchImpl.finalizeMatch().name}.")
return null
}
matchImpl.create_round()
}
override def nextTrick(roundImpl: Round): Trick = {
if(roundImpl.isOver) {
println("The round is over.")
return null
}
roundImpl.create_trick()
}
}

Some files were not shown because too many files have changed in this diff Show More