Skip to content

Commit 2936d09

Browse files
author
Christopher Strauss
committed
create sgf
1 parent ac39d63 commit 2936d09

File tree

6 files changed

+139
-4
lines changed

6 files changed

+139
-4
lines changed

src/main/client/src/feature/game/BoardSettings.jsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,26 @@ import {
66
FaVolumeUp,
77
FaSearchPlus,
88
FaSearchMinus,
9+
FaDownload,
910
} from "react-icons/fa"
1011
import {
1112
useMuteStore,
1213
} from "src/store.js"
1314
import {
1415
useViewStateStore,
1516
} from "src/layout.js"
17+
import {
18+
base,
19+
} from "src/util.js"
20+
21+
export function BoardSettings({gameState, setGameState}) {
22+
1623

17-
export function BoardSettings() {
1824
return (
1925
<div className="absolute pl-2 pt-1 flex flex-col items-center">
2026
<MuteIcon />
2127
<Zoom />
28+
<SaveGameFile gameState={gameState} setGameState={setGameState} />
2229
</div>
2330
)
2431
}
@@ -66,3 +73,19 @@ function Zoom() {
6673
</>
6774
)
6875
}
76+
77+
function SaveGameFile({gameState}) {
78+
return (
79+
<a
80+
href={base + "/api/sgf/" + gameState.id + "/" + gameState.black + "_vs_" + gameState.white + ".sgf"}
81+
target="_blank"
82+
download={gameState.id + "_" + gameState.black + "_vs_" + gameState.white + ".sgf"}
83+
className="mt-[0.25rem]">
84+
<IconContext.Provider value={{
85+
size: "1.5em",
86+
}}>
87+
<FaDownload />
88+
</IconContext.Provider>
89+
</a>
90+
)
91+
}

src/main/client/src/feature/game/Game.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export function Game() {
6969
<div
7070
style={{ width: vw() - sidebarWidth }}
7171
className="h-full">
72-
<BoardSettings />
72+
<BoardSettings gameState={gameState} setGameState={setGameState} />
7373
<Board gameState={gameState} setGameState={setGameState} />
7474
<GamePanel gameState={gameState} setGameState={setGameState} />
7575
</div>

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
import com.bernd.model.OpenGame;
1212
import com.bernd.model.ViewGame;
1313
import com.bernd.util.RandomString;
14+
import com.bernd.util.SgfCreator;
15+
import java.security.Principal;
1416
import org.springframework.http.HttpStatus;
17+
import org.springframework.http.MediaType;
1518
import org.springframework.http.ResponseEntity;
1619
import org.springframework.messaging.core.MessageSendingOperations;
1720
import org.springframework.messaging.handler.annotation.MessageMapping;
@@ -23,8 +26,6 @@
2326
import org.springframework.web.bind.annotation.ResponseBody;
2427
import org.springframework.web.server.ResponseStatusException;
2528

26-
import java.security.Principal;
27-
2829
import static com.bernd.util.Auth.getPrincipal;
2930
import static com.bernd.util.Util.COLORS;
3031

@@ -144,4 +145,15 @@ public ResponseEntity<?> accept(@RequestBody AcceptRequest acceptRequest) {
144145
operations.convertAndSend("/topic/lobby/active_games", activeGames.games());
145146
return ResponseEntity.ok().build();
146147
}
148+
149+
@GetMapping("/api/sgf/{id}/{black}_vs_{white}.sgf")
150+
public ResponseEntity<String> getSgf(
151+
@PathVariable String id) {
152+
Game game = games.get(id);
153+
if (game == null) {
154+
return ResponseEntity.notFound().build();
155+
}
156+
String sgf = SgfCreator.createSgf(game);
157+
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(sgf);
158+
}
147159
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,12 @@ public static int[][] removeDeadStonesAround(
111111
}
112112
return result;
113113
}
114+
115+
public static String getColorFromValue(int value) {
116+
if (value == 32) {
117+
return "B";
118+
}
119+
return "W";
120+
}
121+
114122
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.bernd.util;
2+
3+
import com.bernd.game.Board;
4+
import com.bernd.model.Game;
5+
import com.bernd.model.Move;
6+
import java.text.SimpleDateFormat;
7+
import java.util.Date;
8+
9+
public final class SgfCreator {
10+
11+
public static String createSgf(Game game) {
12+
int asciiAddOn = 97;
13+
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
14+
StringBuilder sb = new StringBuilder();
15+
sb.append("(;");
16+
sb
17+
.append("FF[4]\n")
18+
.append("CA[UTF-8]\n")
19+
.append("GM[1]\n")
20+
.append("DT[" + formatter.format(new Date()) + "]\n")
21+
.append("PC[localhost]\n")
22+
.append("GN[" + game.id() + "]\n")
23+
.append("PB[" + game.black() + "]\n")
24+
.append("PW[" + game.white() + "]\n")
25+
.append("RE[" + (game.gameHasEnded() ? game.getScore() : "?") + "]\n")
26+
.append("SZ[" + game.dim() + "]\n");
27+
for (Move move : game.moves().moves()) {
28+
sb
29+
.append(";")
30+
.append(Board.getColorFromValue(move.color()))
31+
.append("[")
32+
.append((char) (move.x() + asciiAddOn))
33+
.append((char) (move.y() + asciiAddOn));
34+
if (move == game.getLastMove()) {
35+
sb
36+
.append("]");
37+
} else {
38+
sb
39+
.append("]\n");
40+
}
41+
}
42+
sb.append(")");
43+
return sb.toString();
44+
}
45+
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.bernd.util;
2+
3+
import com.bernd.game.MoveList;
4+
import com.bernd.model.Game;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
import static org.junit.jupiter.api.Assertions.assertNotNull;
9+
10+
class SgfCreatorTest {
11+
12+
@Test
13+
void testCreate() {
14+
MoveList moveList = MoveList.create(20);
15+
Game game = new Game("1234", "SpielerSchwarz", "SpielerWeiß", false, new int[9][], 9, 0, null, moveList);
16+
String sgf = SgfCreator.createSgf(game);
17+
assertNotNull(sgf);
18+
}
19+
20+
@Test
21+
void testGrow() {
22+
BoardUpdateImpl update = BoardUpdateImpl.builder(9);
23+
for (int i = 0; i < 9; i++) {
24+
update.add(i, 0);
25+
}
26+
for (int i = 0; i < 9; i++) {
27+
update.add(i, 1);
28+
}
29+
for (int i = 0; i < 9; i++) {
30+
update.add(i, 2);
31+
}
32+
assertEquals(27, update.size());
33+
for (int i = 0; i < 9; i++) {
34+
assertEquals(i % 9, update.x(i));
35+
assertEquals(0, update.y(i));
36+
}
37+
for (int i = 10; i < 18; i++) {
38+
assertEquals(i % 9, update.x(i));
39+
assertEquals(1, update.y(i));
40+
}
41+
for (int i = 19; i < 27; i++) {
42+
assertEquals(i % 9, update.x(i));
43+
assertEquals(2, update.y(i));
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)