Skip to content

Commit 20a0b6e

Browse files
committed
wip moves
1 parent 267b0de commit 20a0b6e

File tree

12 files changed

+290
-49
lines changed

12 files changed

+290
-49
lines changed

src/main/client/src/Game.jsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,20 +196,21 @@ export const Game = () => {
196196
let game = JSON.parse(message.body)
197197
setGameState(game)
198198
})
199+
let sub2 = stompClient.subscribe("/topic/move/" + gameId, (message) => {
200+
let move = JSON.parse(message.body)
201+
console.log(move) // TODO
202+
})
199203
doTry(async () => {
200-
await tfetch("/api/game/hello", {
201-
method: "POST",
204+
let game = await tfetch("/api/game/" + gameId, {
202205
headers: {
203206
"Authorization": "Bearer " + auth.token,
204-
"Content-Type": "application/json",
205207
},
206-
body: JSON.stringify({
207-
id: gameId,
208-
}),
209208
})
209+
setGameState(game)
210210
})
211211
return () => {
212212
sub1.unsubscribe()
213+
sub2.unsubscribe()
213214
}
214215
}, [setGameState, initialized, stompClient, gameId, auth])
215216
if (!board.length) {
@@ -249,7 +250,7 @@ function showStone({ canvasRef, grid, stoneRadius }, grid_x, grid_y, style) {
249250
ctx.fill()
250251
}
251252

252-
function showTriangle({ isCursorInBounds, canvasRef, grid, stoneRadius, lastStoneXref, lastStoneYref }, board) {
253+
function paintLastMove({ isCursorInBounds, canvasRef, grid, stoneRadius, lastStoneXref, lastStoneYref }, board) {
253254
let grid_x = lastStoneXref.current
254255
let grid_y = lastStoneYref.current
255256
if (!isCursorInBounds(grid_x, grid_y)) {
@@ -261,11 +262,12 @@ function showTriangle({ isCursorInBounds, canvasRef, grid, stoneRadius, lastSton
261262
"rgba(0,0,0)"
262263
let [x, y] = grid[grid_y][grid_x]
263264
let ctx = canvasRef.current.getContext("2d")
265+
let length = stoneRadius * 0.875
264266
ctx.fillStyle = style
265267
ctx.beginPath()
266268
ctx.moveTo(x, y)
267-
ctx.lineTo(x + stoneRadius, y)
268-
ctx.lineTo(x , y + stoneRadius)
269+
ctx.lineTo(x + length, y)
270+
ctx.lineTo(x , y + length)
269271
ctx.fill()
270272
}
271273

@@ -328,7 +330,7 @@ function paintStones(context, board) {
328330
}
329331
}
330332
}
331-
showTriangle(context, board)
333+
paintLastMove(context, board)
332334
}
333335

334336
function paintStonesCounting(context, board, countingGroup) {

src/main/client/src/feature/OpenGames.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,7 @@ function AcceptDialog({acceptableGame, onAccept}) {
175175
<IconContext.Provider value={{
176176
size: "1.25em",
177177
className: twJoin(
178-
"pl-[4px]",
179-
"pr-[4px]",
178+
"px-1",
180179
handi === 0 && "text-slate-400",
181180
)
182181
}}>

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

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@
33
import com.bernd.model.AcceptRequest;
44
import com.bernd.model.ActiveGame;
55
import com.bernd.model.Game;
6-
import com.bernd.model.JoinGameRequest;
76
import com.bernd.model.Move;
87
import com.bernd.model.OpenGame;
8+
import com.bernd.model.ViewGame;
9+
import com.bernd.util.Auth;
910
import com.bernd.util.RandomString;
11+
import java.security.Principal;
1012
import org.springframework.http.ResponseEntity;
1113
import org.springframework.messaging.core.MessageSendingOperations;
1214
import org.springframework.messaging.handler.annotation.MessageMapping;
13-
import org.springframework.security.core.context.SecurityContextHolder;
1415
import org.springframework.stereotype.Controller;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.PathVariable;
1518
import org.springframework.web.bind.annotation.PostMapping;
1619
import org.springframework.web.bind.annotation.RequestBody;
1720
import org.springframework.web.bind.annotation.ResponseBody;
1821

19-
import java.util.Objects;
20-
2122
@Controller
2223
public class GameController {
2324

@@ -37,39 +38,51 @@ public class GameController {
3738
this.activeGames = activeGames;
3839
}
3940

40-
@PostMapping(value = "/api/game/hello", consumes = "application/json")
41-
public ResponseEntity<?> sayHello(@RequestBody JoinGameRequest request) {
42-
Game game = games.get(request.id());
43-
operations.convertAndSend("/topic/game/" + request.id(), game);
44-
return ResponseEntity.ok().build();
41+
@ResponseBody
42+
@GetMapping(value = "/api/game/{id}")
43+
public ViewGame getGame(@PathVariable String id) {
44+
Game game = games.get(id);
45+
if (game == null) {
46+
return null;
47+
}
48+
return game.toView();
4549
}
4650

4751
@MessageMapping("/game/move")
48-
public void action(Move move) {
52+
public void action(Move move, Principal principal) {
4953
Game game = games.get(move.id());
54+
if (game == null) {
55+
return;
56+
}
57+
int moveNumber = game.moves().size();
58+
int color = game.currentColor();
59+
if (!principal.getName().equals(game.currentPlayer())) {
60+
return; // discard
61+
}
5062
Game updated = game.update(move);
5163
games.put(updated);
52-
operations.convertAndSend("/topic/game/" + game.id(), updated);
64+
operations.convertAndSend("/topic/move/" + game.id(), move.toView(color, moveNumber));
65+
operations.convertAndSend("/topic/game/" + game.id(), updated.toView());
5366
}
5467

5568
@ResponseBody
5669
@PostMapping(value = "/api/create", consumes = "application/json")
5770
public OpenGame newGame(@RequestBody OpenGame game) {
58-
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
59-
OpenGame result = openGames.put(game.withUser(Objects.toString(principal, ""))
71+
String principal = Auth.getPrincipal();
72+
OpenGame result = openGames.put(game.withUser(principal)
6073
.withId(RandomString.get()));
6174
operations.convertAndSend("/topic/lobby/open_games", openGames.games());
6275
return result;
6376
}
6477

6578
@PostMapping(value = "/api/accept", consumes = "application/json")
6679
public ResponseEntity<?> accept(@RequestBody AcceptRequest acceptRequest) {
67-
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
68-
openGames.remove(Objects.toString(principal));
80+
String principal = Auth.getPrincipal();
81+
openGames.remove(principal);
6982
OpenGame openGame = openGames.remove(acceptRequest.game().user().name());
70-
Game fullGame = games.put(openGame.accept(principal.toString(), acceptRequest));
83+
Game fullGame = games.put(openGame.accept(principal, acceptRequest));
7184
activeGames.put(ActiveGame.fromGame(fullGame));
72-
operations.convertAndSend("/topic/game/" + fullGame.id(), fullGame);
85+
operations.convertAndSend("/topic/game/" + fullGame.id(), fullGame.toView());
7386
operations.convertAndSend("/topic/lobby/open_games", openGames.games());
7487
operations.convertAndSend("/topic/lobby/active_games", activeGames.games());
7588
return ResponseEntity.ok().build();

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
package com.bernd;
22

3+
import com.bernd.game.MoveList;
34
import com.bernd.model.ActiveGame;
45
import com.bernd.model.ActiveGameList;
56
import com.bernd.model.Game;
67
import com.bernd.model.MatchRequest;
78
import com.bernd.model.OpenGameList;
89
import com.bernd.model.User;
10+
import com.bernd.model.ViewGame;
11+
import com.bernd.util.Auth;
912
import com.bernd.util.RandomString;
1013
import org.springframework.http.ResponseEntity;
1114
import org.springframework.messaging.core.MessageSendingOperations;
12-
import org.springframework.security.core.context.SecurityContextHolder;
1315
import org.springframework.stereotype.Controller;
1416
import org.springframework.web.bind.annotation.GetMapping;
1517
import org.springframework.web.bind.annotation.PostMapping;
1618
import org.springframework.web.bind.annotation.RequestBody;
1719
import org.springframework.web.bind.annotation.ResponseBody;
1820

19-
import java.util.Objects;
20-
2121
import static com.bernd.game.Board.B;
2222

2323
@Controller
@@ -44,8 +44,8 @@ public class LobbyController {
4444

4545
@GetMapping(value = "/api/lobby/hello")
4646
public ResponseEntity<?> sayHello() {
47-
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
48-
lobbyUsers.add(Objects.toString(principal));
47+
String principal = Auth.getPrincipal();
48+
lobbyUsers.add(principal);
4949
operations.convertAndSend("/topic/lobby/users", lobbyUsers.users());
5050
operations.convertAndSend("/topic/lobby/open_games", openGames.games());
5151
operations.convertAndSend("/topic/lobby/active_games", activeGames.games());
@@ -66,25 +66,26 @@ public OpenGameList getOpenGames() {
6666

6767
@ResponseBody
6868
@PostMapping(value = "/api/start_edit", consumes = "application/json")
69-
public Game startEdit(@RequestBody MatchRequest request) {
70-
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
71-
lobbyUsers.remove(Objects.toString(principal));
72-
User user = new User(Objects.toString(principal));
69+
public ViewGame startEdit(@RequestBody MatchRequest request) {
70+
String principal = Auth.getPrincipal();
71+
lobbyUsers.remove(principal);
72+
User user = new User(principal);
7373
operations.convertAndSend("/topic/lobby/users", lobbyUsers.users());
7474
Game game = games.put(new Game(
7575
RandomString.get(),
7676
user,
7777
user,
7878
true,
7979
false,
80-
Objects.toString(principal),
80+
principal,
8181
B,
8282
false,
8383
createEmptyBoard(request.dim()),
8484
0,
85-
new int[]{-1, -1}));
85+
new int[]{-1, -1},
86+
MoveList.create(request.dim())));
8687
activeGames.put(ActiveGame.fromGame(game));
87-
return game;
88+
return game.toView();
8889
}
8990

9091
public static int[][] createEmptyBoard(int dimension) {
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.bernd.game;
2+
3+
import com.bernd.model.GameMove;
4+
import com.bernd.model.Move;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
9+
import static com.bernd.util.Util.divUp;
10+
11+
public final class MoveList {
12+
13+
private static final int LO = 0xffff;
14+
private static final int HI = 0xffff0000;
15+
private static final int WHITE = 0x1000;
16+
private static final int PASS = 0x2000;
17+
private static final int DATA = 0x0fff;
18+
19+
public static void main(String[] args) {
20+
int n = 1024 * 4;
21+
System.out.printf("%x\n", n);
22+
System.out.println(n);
23+
System.out.printf("%x\n", 2 * n);
24+
System.out.println(2 * n);
25+
}
26+
27+
private int pos;
28+
private int capacity;
29+
private final int dim;
30+
private int[] buffer;
31+
32+
private MoveList(
33+
int dim,
34+
int[] buffer) {
35+
this.capacity = dim * dim;
36+
this.dim = dim;
37+
this.buffer = buffer;
38+
}
39+
40+
public static MoveList create(int dim, int size) {
41+
return new MoveList(dim, new int[divUp(size, 2)]);
42+
}
43+
44+
public static MoveList create(int dim) {
45+
return new MoveList(dim, new int[16]);
46+
}
47+
48+
public void add(int color, Move move) {
49+
if (pos >= capacity) {
50+
int newCapacity = 2 * capacity;
51+
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
52+
capacity = newCapacity;
53+
}
54+
int ptId;
55+
if (move.pass()) {
56+
ptId = PASS;
57+
} else {
58+
ptId = dim * move.y() + move.x();
59+
}
60+
if (color == Board.W) {
61+
ptId |= WHITE;
62+
}
63+
set(ptId);
64+
pos++;
65+
}
66+
67+
public GameMove get(int i) {
68+
int code = buffer[i / 2];
69+
int ptId = i % 2 == 0 ? code & LO : (code >> 16);
70+
int color = (ptId & WHITE) != 0 ? Board.W : Board.B;
71+
if ((ptId & PASS) != 0) {
72+
return new GameMove(i, color, true, -1, -1);
73+
} else {
74+
int data = ptId & DATA;
75+
int x = data % dim;
76+
int y = data / dim;
77+
return new GameMove(i, color, true, x, y);
78+
}
79+
}
80+
81+
private void set(int ptId) {
82+
int i = pos / 2;
83+
if (pos % 2 == 0) {
84+
buffer[i] = (buffer[i] & HI) | ptId;
85+
} else {
86+
buffer[i] = (ptId << 16) | (buffer[i] & LO);
87+
}
88+
}
89+
90+
public int size() {
91+
return pos;
92+
}
93+
94+
public List<GameMove> asList() {
95+
List<GameMove> result = new ArrayList<>(size());
96+
for (int i = 0; i < pos; i++) {
97+
result.add(get(i));
98+
}
99+
return result;
100+
}
101+
102+
public int dim() {
103+
return dim;
104+
}
105+
106+
@Override
107+
public String toString() {
108+
if (pos == 0) {
109+
return "[]";
110+
}
111+
StringBuilder sb = new StringBuilder("[");
112+
for (int i = 0; i < pos; i++) {
113+
sb.append("(")
114+
.append(get(i))
115+
.append("), ");
116+
}
117+
sb.setLength(sb.length() - 2);
118+
sb.append("]");
119+
return sb.toString();
120+
}
121+
}

0 commit comments

Comments
 (0)