Skip to content

Commit 705febc

Browse files
committed
Refactor loading of Go games & states from SGF file to use new general SGF reader. This separates the Go-specific logic of rebuilding the states to games/go and the parsing of the SGF strings to utils/sgf_reader.cc.
PiperOrigin-RevId: 883275313 Change-Id: Ia44aa1ba4844dfb140b6176422cdb47131f62279
1 parent 07efd95 commit 705febc

File tree

16 files changed

+395
-688
lines changed

16 files changed

+395
-688
lines changed

open_spiel/games/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ set(GAME_SOURCES
9696
go/go.h
9797
go/go_board.cc
9898
go/go_board.h
99-
go/sgf_reader.cc
100-
go/sgf_reader.h
99+
go/sgf_game_loader.cc
100+
go/sgf_game_loader.h
101101
gomoku/gomoku.cc
102102
gomoku/gomoku.h
103103
gomoku/gomoku_grid.h
@@ -497,9 +497,9 @@ add_executable(go_test go/go_test.cc ${OPEN_SPIEL_OBJECTS}
497497
$<TARGET_OBJECTS:tests>)
498498
add_test(go_test go_test)
499499

500-
add_executable(sgf_reader_test go/sgf_reader_test.cc ${OPEN_SPIEL_OBJECTS}
500+
add_executable(sgf_game_loader_test go/sgf_game_loader_test.cc ${OPEN_SPIEL_OBJECTS}
501501
$<TARGET_OBJECTS:tests>)
502-
add_test(sgf_reader_test sgf_reader_test)
502+
add_test(sgf_game_loader_test sgf_game_loader_test)
503503

504504
add_executable(phantom_go_test phantom_go/phantom_go_test.cc ${OPEN_SPIEL_OBJECTS}
505505
$<TARGET_OBJECTS:tests>)

open_spiel/games/go/go.cc

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@
1616

1717
#include <algorithm>
1818
#include <array>
19+
#include <iostream>
1920
#include <memory>
2021
#include <sstream>
2122
#include <string>
2223
#include <utility>
2324
#include <vector>
2425

25-
#include "open_spiel/abseil-cpp/absl/strings/ascii.h"
2626
#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
2727
#include "open_spiel/abseil-cpp/absl/types/span.h"
2828
#include "open_spiel/game_parameters.h"
2929
#include "open_spiel/games/go/go_board.h"
30-
#include "open_spiel/games/go/sgf_reader.h"
3130
#include "open_spiel/observer.h"
3231
#include "open_spiel/spiel.h"
3332
#include "open_spiel/spiel_globals.h"
@@ -120,8 +119,7 @@ GoState::GoState(std::shared_ptr<const Game> game, int board_size, float komi,
120119
komi_(komi),
121120
handicap_(handicap),
122121
max_game_length_(game_->MaxGameLength()),
123-
to_play_(GoColor::kBlack),
124-
initial_sgf_string_("") {
122+
to_play_(GoColor::kBlack) {
125123
ResetBoard();
126124
}
127125

@@ -302,16 +300,6 @@ void GoState::ResetBoard() {
302300
superko_ = false;
303301
}
304302

305-
std::string GoState::Serialize() const {
306-
std::string ser_str = State::Serialize();
307-
if (!initial_sgf_string_.empty()) {
308-
return absl::StrCat(kSerializeStartingState, initial_sgf_string_, "\n",
309-
ser_str);
310-
} else {
311-
return ser_str;
312-
}
313-
}
314-
315303
GoGame::GoGame(const GameParameters& params)
316304
: Game(kGameType, params),
317305
komi_(ParameterValue<double>("komi")),
@@ -320,51 +308,5 @@ GoGame::GoGame(const GameParameters& params)
320308
max_game_length_(ParameterValue<int>(
321309
"max_game_length", DefaultMaxGameLength(board_size_))) {}
322310

323-
std::unique_ptr<State> GoGame::NewInitialState(
324-
const std::string& sgf_string) const {
325-
VectorOfGamesAndStates games_and_states = LoadGamesFromSGFString(sgf_string);
326-
const GameAndState& game_and_state = games_and_states.back();
327-
328-
// First check that the game parameters are the same.
329-
const GoGame* other_game =
330-
down_cast<const GoGame*>(game_and_state.first.get());
331-
SPIEL_CHECK_EQ(board_size_, other_game->board_size_);
332-
SPIEL_CHECK_EQ(komi_, other_game->komi_);
333-
SPIEL_CHECK_EQ(handicap_, other_game->handicap_);
334-
335-
const auto* other_state =
336-
static_cast<const GoState*>(game_and_state.second.get());
337-
auto state = std::unique_ptr<State>(
338-
new GoState(shared_from_this(), board_size_, komi_, handicap_));
339-
340-
// if there's a history, just play back the moves
341-
if (!other_state->History().empty()) {
342-
for (const auto& action : other_state->History()) {
343-
state->ApplyAction(action);
344-
}
345-
// Do not save the SGF string in this case because it is already included
346-
// in the state.
347-
static_cast<GoState*>(state.get())->initial_sgf_string_ = "";
348-
} else {
349-
// if there isn't, then just copy the boards
350-
GoBoard* my_board = static_cast<GoState*>(state.get())->mutable_board();
351-
*my_board = other_state->board();
352-
353-
// Change all the whitespace in the SGF string so that there are no
354-
// newlines.
355-
std::string sgf_string_copy = sgf_string;
356-
for (int i = 0; i < sgf_string_copy.length(); ++i) {
357-
if (absl::ascii_isspace(sgf_string_copy[i])) {
358-
sgf_string_copy[i] = ' ';
359-
}
360-
}
361-
static_cast<GoState*>(state.get())->initial_sgf_string_ = sgf_string_copy;
362-
}
363-
364-
SPIEL_CHECK_EQ(state->ToString(), other_state->ToString());
365-
366-
return state;
367-
}
368-
369311
} // namespace go
370312
} // namespace open_spiel

open_spiel/games/go/go.h

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ struct GoStateStruct : StateStruct {
103103
// The pass action is board_size * board_size.
104104
class GoState : public State {
105105
public:
106-
friend class SGFReader; // for mutable_board().
107-
friend class GoGame; // also for mutable_board(), constructing by SGF.
106+
friend class GoGame;
108107

109108
// Constructs a Go state for the empty board.
110109
GoState(std::shared_ptr<const Game> game, int board_size, float komi,
@@ -132,12 +131,14 @@ class GoState : public State {
132131
std::unique_ptr<State> Clone() const override;
133132
void UndoAction(Player player, Action action) override;
134133

135-
// Custom serialize only necessary when starting from an SGF string.
136-
// Uses standard serialization otherwise.
137-
virtual std::string Serialize() const override;
138-
139134
const GoBoard& board() const { return board_; }
140135

136+
// Use with care. Modifying the board directly can lead to undefined behavior.
137+
// The history is not maintained properly when using this method. This method
138+
// is mainly used by the SGF game loader to create arbitrary boards from SGF
139+
// files via the AB[] and AW[] properties.
140+
GoBoard* mutable_board() { return &board_; }
141+
141142
protected:
142143
void DoApplyAction(Action action) override;
143144

@@ -146,12 +147,6 @@ class GoState : public State {
146147

147148
GoBoard board_;
148149

149-
// Use with care. Modifying the board directly can lead to undefined behavior.
150-
// The history is not maintained properly when using this method. This method
151-
// is mainly used by the SGF reader to create arbitrary boards from SGF files
152-
// via the AB[] and AW[] properties.
153-
GoBoard* mutable_board() { return &board_; }
154-
155150
// RepetitionTable records which positions we have already encountered.
156151
// We are already indexing by board hash, so there is no need to hash that
157152
// hash again, so we use a custom passthrough hasher.
@@ -169,10 +164,6 @@ class GoState : public State {
169164
const int max_game_length_;
170165
GoColor to_play_;
171166
bool superko_;
172-
173-
// Only used when calling NewInitialState(sgf_string). The SGF string is
174-
// saved here to ensure that the state is properly serialized.
175-
std::string initial_sgf_string_;
176167
};
177168

178169
// Game object.
@@ -189,11 +180,6 @@ class GoGame : public Game {
189180
new GoState(shared_from_this(), board_size_, komi_, handicap_));
190181
}
191182

192-
// Starts a go game from the given SGF string. If there are multiple games in
193-
// the SGF string, only the last one is used.
194-
std::unique_ptr<State> NewInitialState(
195-
const std::string& sgf_string) const override;
196-
197183
std::vector<int> ObservationTensorShape() const override {
198184
// Planes: black, white, empty, and a bias plane indicating komi (whether
199185
// white is to play).

open_spiel/games/go/go_board.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ VirtualPoint GoBoard::Chain::single_liberty() const {
557557
return static_cast<VirtualPoint>(liberty_vertex_sum / num_pseudo_liberties);
558558
}
559559

560-
std::string GoBoard::ToString() {
560+
std::string GoBoard::ToString() const {
561561
std::ostringstream stream;
562562
stream << *this;
563563
return stream.str();

open_spiel/games/go/go_board.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class GoBoard {
175175
// Number of stones in a chain.
176176
inline int ChainSize(VirtualPoint p) const { return chain(p).num_stones; }
177177

178-
std::string ToString();
178+
std::string ToString() const;
179179

180180
class GroupIter {
181181
public:

0 commit comments

Comments
 (0)