diff --git a/src/main/client/src/feature/game/BoardSettings.jsx b/src/main/client/src/feature/game/BoardSettings.jsx
index 245ad01..20aef59 100644
--- a/src/main/client/src/feature/game/BoardSettings.jsx
+++ b/src/main/client/src/feature/game/BoardSettings.jsx
@@ -6,6 +6,7 @@ import {
FaVolumeUp,
FaSearchPlus,
FaSearchMinus,
+ FaDownload,
} from "react-icons/fa"
import {
useMuteStore,
@@ -13,12 +14,18 @@ import {
import {
useViewStateStore,
} from "src/layout.js"
+import {
+ base,
+} from "src/util.js"
+
+export function BoardSettings({gameId, black, white}) {
+
-export function BoardSettings() {
return (
+
)
}
@@ -66,3 +73,19 @@ function Zoom() {
>
)
}
+
+function SaveGameFile({gameId, black, white}) {
+ return (
+
+
+
+
+
+ )
+}
diff --git a/src/main/client/src/feature/game/Game.jsx b/src/main/client/src/feature/game/Game.jsx
index b9f3267..61c93ea 100644
--- a/src/main/client/src/feature/game/Game.jsx
+++ b/src/main/client/src/feature/game/Game.jsx
@@ -69,7 +69,7 @@ export function Game() {
-
+
diff --git a/src/main/java/com/bernd/GameController.java b/src/main/java/com/bernd/GameController.java
index 184f9b8..26d9d22 100644
--- a/src/main/java/com/bernd/GameController.java
+++ b/src/main/java/com/bernd/GameController.java
@@ -11,7 +11,11 @@
import com.bernd.model.OpenGame;
import com.bernd.model.ViewGame;
import com.bernd.util.RandomString;
+import com.bernd.util.SgfCreator;
+import java.security.Principal;
+import java.time.LocalDate;
import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.core.MessageSendingOperations;
import org.springframework.messaging.handler.annotation.MessageMapping;
@@ -23,8 +27,6 @@
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ResponseStatusException;
-import java.security.Principal;
-
import static com.bernd.util.Auth.getPrincipal;
import static com.bernd.util.Util.COLORS;
@@ -144,4 +146,15 @@ public ResponseEntity> accept(@RequestBody AcceptRequest acceptRequest) {
operations.convertAndSend("/topic/lobby/active_games", activeGames.games());
return ResponseEntity.ok().build();
}
+
+ @GetMapping("/api/sgf/{id}/{black}_vs_{white}.sgf")
+ public ResponseEntity getSgf(
+ @PathVariable String id) {
+ Game game = games.get(id);
+ if (game == null) {
+ return ResponseEntity.notFound().build();
+ }
+ String sgf = SgfCreator.createSgf(game, LocalDate.now());
+ return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(sgf);
+ }
}
diff --git a/src/main/java/com/bernd/game/Board.java b/src/main/java/com/bernd/game/Board.java
index a67a6c3..6936c57 100644
--- a/src/main/java/com/bernd/game/Board.java
+++ b/src/main/java/com/bernd/game/Board.java
@@ -111,4 +111,5 @@ public static int[][] removeDeadStonesAround(
}
return result;
}
+
}
diff --git a/src/main/java/com/bernd/util/SgfCreator.java b/src/main/java/com/bernd/util/SgfCreator.java
new file mode 100644
index 0000000..8712b8d
--- /dev/null
+++ b/src/main/java/com/bernd/util/SgfCreator.java
@@ -0,0 +1,55 @@
+package com.bernd.util;
+
+import com.bernd.model.Game;
+import com.bernd.model.Move;
+import java.time.LocalDate;
+
+public final class SgfCreator {
+
+ public static String createSgf(Game game, LocalDate date) {
+ int twoPass = 0;
+ int asciiAddOn = 97;
+ StringBuilder sb = new StringBuilder();
+ sb.append("(;");
+ sb
+ .append("FF[4]\n")
+ .append("CA[UTF-8]\n")
+ .append("GM[1]\n")
+ .append("DT[" + date.toString() + "]\n")
+ .append("GN[" + game.id() + "]\n")
+ .append("PB[" + game.black() + "]\n")
+ .append("PW[" + game.white() + "]\n")
+ .append("RE[" + (game.gameHasEnded() ? game.getScore() : "?") + "]\n")
+ .append("SZ[" + game.dim() + "]\n");
+ for (Move move : game.moves().moves()) {
+ sb
+ .append(";")
+ .append(getColorFromValue(move.color()))
+ .append("[");
+ if (!move.pass()) {
+ twoPass = 0;
+ sb
+ .append((char) (move.x() + asciiAddOn))
+ .append((char) (move.y() + asciiAddOn));
+ } else {
+ twoPass++;
+ if (twoPass == 2) {
+ sb.append("]\n");
+ break;
+ }
+ }
+ sb
+ .append("]\n");
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private static String getColorFromValue(int value) {
+ if (value == 32) {
+ return "B";
+ }
+ return "W";
+ }
+
+}
diff --git a/src/test/java/com/bernd/util/SgfCreatorTest.java b/src/test/java/com/bernd/util/SgfCreatorTest.java
new file mode 100644
index 0000000..576ae12
--- /dev/null
+++ b/src/test/java/com/bernd/util/SgfCreatorTest.java
@@ -0,0 +1,26 @@
+package com.bernd.util;
+
+import com.bernd.game.Board;
+import com.bernd.game.MoveList;
+import com.bernd.model.Game;
+import com.bernd.model.Move;
+import java.time.LocalDate;
+import java.time.Month;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class SgfCreatorTest {
+
+ @Test
+ void testCreate() {
+ MoveList moveList = MoveList.create(20);
+ moveList.add(new Move(Board.B, 0, null, 3, 4));
+ moveList.add(new Move(Board.W, 0, null, 6, 4));
+ Game game = new Game("1234", "B", "W", false, new int[9][], 9, 0, null, moveList);
+ String sgf = SgfCreator.createSgf(game, LocalDate.of(2024, Month.AUGUST, 30));
+ assertEquals("(;FF[4]CA[UTF-8]GM[1]DT[2024-08-30]GN[1234]PB[B]PW[W]RE[?]SZ[9];B[de];W[ge])",
+ sgf.replace("\n", ""));
+ }
+
+}