Skip to content

Commit 65ba4f1

Browse files
committed
game end
1 parent 6df9887 commit 65ba4f1

File tree

13 files changed

+137
-58
lines changed

13 files changed

+137
-58
lines changed

src/main/client/src/Game.jsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const Game = () => {
4040
let lastStoneXref = useRef(-1)
4141
let lastStoneYref = useRef(-1)
4242
let [zoom, setZoom] = useState(0)
43-
let { gameId } = useParams()
43+
let {gameId} = useParams()
4444
let stompClient = useContext(StompContext)
4545
let auth = useAuthStore(state => state.auth)
4646
let setGameState = useGameStore(state => state.setGameState)
@@ -50,11 +50,11 @@ export const Game = () => {
5050
let currentPlayer = useGameStore(state => state.currentPlayer)
5151
let counting = useGameStore(state => state.counting)
5252
let currentColor = useGameStore(state => state.currentColor)
53-
let { board, forbidden } = useGameStore(state => state.gameState)
53+
let {board, forbidden, gameHasEnded} = useGameStore(state => state.gameState)
5454
let [forbidden_x, forbidden_y] = forbidden
5555
let initialized = useRef()
5656
let canvasRef = useRef()
57-
let countingGroup = counting() ? getCountingGroup(board, cursor_x, cursor_y) : undefined
57+
let countingGroup = !gameHasEnded && counting() ? getCountingGroup(board, cursor_x, cursor_y) : undefined
5858

5959
let context = useMemo(() => {
6060
let dim = board.length
@@ -118,6 +118,9 @@ export const Game = () => {
118118
}, [board.length, canvasRef, zoom])
119119

120120
let onMouseMove = useCallback((e) => {
121+
if (gameHasEnded) {
122+
return
123+
}
121124
if (!board.length) {
122125
return
123126
}
@@ -128,9 +131,12 @@ export const Game = () => {
128131
let cursor_y = Math.round((e.nativeEvent.offsetY - context.margin) / context.step)
129132
setCursor_x(cursor_x + 0)
130133
setCursor_y(cursor_y + 0)
131-
}, [context, currentPlayer, auth, board.length, counting])
134+
}, [context, currentPlayer, auth, board.length, counting, gameHasEnded])
132135

133136
let onClick = useCallback((e) => {
137+
if (gameHasEnded) {
138+
return
139+
}
134140
if (!board.length) {
135141
return
136142
}
@@ -165,7 +171,7 @@ export const Game = () => {
165171
y: cursor_y,
166172
}),
167173
})
168-
}, [context, currentPlayer, currentColor, auth, board, gameId, stompClient, counting, forbidden_x, forbidden_y, queueLength])
174+
}, [context, currentPlayer, currentColor, auth, board, gameId, stompClient, counting, forbidden_x, forbidden_y, queueLength, gameHasEnded])
169175

170176
useEffect(() => {
171177
if (!board.length) {

src/main/client/src/component/Button.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
2-
twJoin,
2+
twMerge,
33
} from "tailwind-merge"
44

55
export const Button = ({ type, children, disabled, className, onClick, ...rest }) => {
6-
let classes = twJoin(
6+
let classes = twMerge(
77
"border-2 border-slate-600 rounded-lg px-8 py-2",
88
disabled && "text-slate-500 bg-slate-200 border-slate-400 border-2",
99
!disabled && "hover:text-white text-slate-200 hover:border-sky-700",

src/main/client/src/feature/GamePanel.jsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ function Panel({zoom, setZoom}) {
5050
let white = useGameStore(state => state.white)
5151
let queueLength = useGameStore(state => state.queueLength)
5252
let counting = useGameStore(state => state.counting)
53+
let countingComplete = useGameStore(state => state.countingComplete)
5354
let currentPlayer = useGameStore(state => state.currentPlayer)
54-
let { board } = useGameStore(state => state.gameState)
55+
let { board, gameHasEnded } = useGameStore(state => state.gameState)
5556
let navigate = useNavigate()
5657
let onExit = useCallback(() => {
5758
navigate(base + "/lobby")
@@ -76,10 +77,20 @@ function Panel({zoom, setZoom}) {
7677
}),
7778
})
7879
}, [stompClient, gameId, queueLength])
80+
let onCountingAgree = useCallback(() => {
81+
stompClient.publish({
82+
destination: "/app/game/move",
83+
body: JSON.stringify({
84+
id: gameId,
85+
n: queueLength(),
86+
agreeCounting: true,
87+
}),
88+
})
89+
}, [stompClient, gameId, queueLength])
7990
if (!board.length) {
8091
return <span>Loading...</span>
8192
}
82-
let result = counting() ? getScore(board) : undefined
93+
let result = gameHasEnded ? getScore(board) : undefined
8394
return (
8495
<>
8596
<div className="inline-flex gap-x-2">
@@ -123,21 +134,33 @@ function Panel({zoom, setZoom}) {
123134
<div>vs</div>
124135
<div>{black.name}</div>
125136
</div>
137+
<div>Move {queueLength()}</div>
126138
<div className="mt-2">
127139
<Button
128140
onClick={onPass}
129-
disabled={counting() || currentPlayer() !== auth.name}>
141+
className="py-1 px-4"
142+
disabled={gameHasEnded || counting() || currentPlayer() !== auth.name}>
130143
Pass
131144
</Button>
132145
</div>
133-
{counting() && (
146+
{counting() && <>
134147
<div className="mt-2">
135148
<Button
149+
className="py-1 px-4"
150+
disabled={gameHasEnded}
136151
onClick={onResetCounting}>
137152
Reset Counting
138153
</Button>
139154
</div>
140-
)}
155+
<div className="mt-2">
156+
<Button
157+
disabled={gameHasEnded || !countingComplete()}
158+
className="py-1 px-4"
159+
onClick={onCountingAgree}>
160+
OK
161+
</Button>
162+
</div>
163+
</>}
141164
{result && (
142165
<div className="mt-4">
143166
<div>
@@ -151,11 +174,6 @@ function Panel({zoom, setZoom}) {
151174
</div>
152175
</div>
153176
)}
154-
{!counting() && (
155-
<div className="mt-2">
156-
{currentPlayer() + " ist dran..."}
157-
</div>
158-
)}
159177
</>
160178
)
161179
}

src/main/client/src/store.js

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import {
44
import {
55
produce,
66
} from "immer"
7+
import {
8+
persist,
9+
} from "zustand/middleware"
710
import {
811
BLACK,
912
WHITE,
@@ -23,41 +26,56 @@ import {
2326
resetCounting,
2427
} from "./model/count.js"
2528

26-
export const useAuthStore = create((set) => ({
27-
auth: {
28-
name: "",
29-
state: "anonymous",
30-
token: "",
31-
},
32-
setAuth: (payload) => {
33-
set(produce(state => {
34-
state.auth.name = payload.name
35-
state.auth.state = "authenticated"
36-
state.auth.token = payload.token
37-
}))
38-
},
39-
setPending: (b) => {
40-
set(produce(state => {
41-
state.auth.state = b ? "pending" : "anonymous"
42-
}), true)
43-
},
44-
}))
29+
export const useAuthStore = create(
30+
persist(
31+
(set) => ({
32+
auth: {
33+
name: "",
34+
state: "anonymous",
35+
token: "",
36+
},
37+
setAuth: (payload) => {
38+
set(produce(state => {
39+
state.auth.name = payload.name
40+
state.auth.state = "authenticated"
41+
state.auth.token = payload.token
42+
}))
43+
},
44+
setPending: (b) => {
45+
set(produce(state => {
46+
state.auth.state = b ? "pending" : "anonymous"
47+
}), true)
48+
},
49+
}),
50+
{ name: "auth-storage" },
51+
),
52+
)
4553

4654
export const useGameStore = create((set, get) => ({
4755
moves: [],
4856
baseBoard: [],
57+
dim: 0,
4958
queueStatus: "behind",
5059
black: {
5160
name: "",
5261
},
5362
white: {
5463
name: "",
5564
},
56-
isInCountingGroup: undefined,
57-
setIsInCountingGroup: (has) => {
58-
set(produce(state => {
59-
state.isInCountingGroup = has
60-
}))
65+
countingComplete: () => {
66+
if (!get().counting()) {
67+
return false
68+
}
69+
let baseBoard = get().baseBoard
70+
let dim = get().dim
71+
for (let y = 0; y < dim; y++) {
72+
for (let x = 0; x < dim; x++) {
73+
if (!baseBoard[y][x]) {
74+
return false
75+
}
76+
}
77+
}
78+
return true
6179
},
6280
currentPlayer: () => {
6381
let moves = get().moves
@@ -88,9 +106,15 @@ export const useGameStore = create((set, get) => ({
88106
gameState: {
89107
board: [],
90108
forbidden: [-1, -1],
109+
gameHasEnded: false,
91110
},
92111
addMove: (move) => {
93112
set(produce(state => {
113+
if (move.end) {
114+
state.moves.push(move)
115+
state.gameState.gameHasEnded = true
116+
return
117+
}
94118
let moves = get().moves
95119
let baseBoard = get().baseBoard
96120
if (move.n < moves.length) {
@@ -119,11 +143,17 @@ export const useGameStore = create((set, get) => ({
119143
let moves = []
120144
let forbidden = [-1, -1]
121145
for (let move of game.moves) {
146+
if (move.end) {
147+
moves.push(move)
148+
state.gameState.gameHasEnded = true
149+
break
150+
}
122151
let [storedMove, updated, newForbidden] = createMoveData(baseBoard, moves, move)
123152
moves.push(storedMove)
124153
forbidden = newForbidden
125154
baseBoard = updated
126155
}
156+
state.dim = game.dim
127157
state.baseBoard = baseBoard
128158
state.moves = moves
129159
state.gameState.board = rehydrate(baseBoard)

src/main/java/com/bernd/GameController.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.bernd.game.Board;
44
import com.bernd.model.AcceptRequest;
55
import com.bernd.model.ActiveGame;
6-
import com.bernd.model.CountingMove;
76
import com.bernd.model.Game;
87
import com.bernd.model.Move;
98
import com.bernd.model.OpenGame;
@@ -68,7 +67,11 @@ public void action(Move move, Principal principal) {
6867
}
6968
Game updated = game.update(move);
7069
games.put(updated);
71-
operations.convertAndSend("/topic/move/" + game.id(), move.toView(color, updated.counting()));
70+
if (updated.gameHasEnded()) {
71+
operations.convertAndSend("/topic/move/" + game.id(), move.gameEnd(color, updated.counting()));
72+
} else if (!move.agreeCounting()) {
73+
operations.convertAndSend("/topic/move/" + game.id(), move.toView(color, updated.counting()));
74+
}
7275
}
7376

7477
@ResponseBody

src/main/java/com/bernd/LobbyController.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public ViewGame startEdit(@RequestBody MatchRequest request) {
7676
user,
7777
user,
7878
false,
79+
0,
7980
principal,
8081
B,
8182
false,

src/main/java/com/bernd/game/MoveList.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static MoveList create(int dim) {
3939
return new MoveList(dim, new int[16]);
4040
}
4141

42-
public void gameEnd() {
42+
public void addGameEndMarker() {
4343
ensureCapacity();
4444
set(GAME_END);
4545
pos++;

src/main/java/com/bernd/model/Game.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public record Game(
1919
User black,
2020
User white,
2121
boolean counting,
22+
int countingAgreed,
2223
String currentPlayer,
2324
int currentColor,
2425
boolean opponentPassed,
@@ -42,6 +43,12 @@ public Game update(Move move) {
4243
}
4344

4445
private Game updateInternal(Move move) {
46+
if (move.agreeCounting()) {
47+
if ((countingAgreed | currentColor()) == COLORS) {
48+
moves.addGameEndMarker();
49+
}
50+
return countingAgreed(countingAgreed | currentColor());
51+
}
4552
moves.add(currentColor, move, counting);
4653
if (counting) {
4754
if (move.resetCounting()) {
@@ -55,7 +62,7 @@ private Game updateInternal(Move move) {
5562
if (opponentPassed) {
5663
return startCounting();
5764
}
58-
return game(board, counting, true, NOT_FORBIDDEN);
65+
return game(board, counting, 0, true, NOT_FORBIDDEN);
5966
}
6067
int x = move.x();
6168
int y = move.y();
@@ -124,13 +131,15 @@ private Direction getDirection(
124131
private Game game(
125132
int[][] board,
126133
boolean counting,
134+
int countingAgreed,
127135
boolean opponentPassed,
128136
int[] forbidden) {
129137
return new Game(
130138
id,
131139
black,
132140
white,
133141
counting,
142+
countingAgreed,
134143
nextPlayer(),
135144
nextColor(),
136145
opponentPassed,
@@ -142,11 +151,11 @@ private Game game(
142151
}
143152

144153
private Game game(int[][] board, int[] forbidden) {
145-
return game(board, counting, false, forbidden);
154+
return game(board, counting, 0, false, forbidden);
146155
}
147156

148157
private Game startCounting() {
149-
return game(Count.count(board), true, true, NOT_FORBIDDEN);
158+
return game(Count.count(board), true, 0, true, NOT_FORBIDDEN);
150159
}
151160

152161
private String nextPlayer() {
@@ -163,4 +172,12 @@ private int nextColor() {
163172
public ViewGame toView() {
164173
return ViewGame.fromGame(this);
165174
}
175+
176+
private Game countingAgreed(int countingAgreed) {
177+
return game(board, counting, countingAgreed, opponentPassed, forbidden);
178+
}
179+
180+
public boolean gameHasEnded() {
181+
return countingAgreed == COLORS;
182+
}
166183
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.bernd.model;
2+
3+
public record GameEndMove(boolean gameHasEnded) {
4+
5+
public static GameEndMove create() {
6+
return new GameEndMove(true);
7+
}
8+
}

0 commit comments

Comments
 (0)