-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdataset.py
More file actions
102 lines (81 loc) · 3.51 KB
/
Copy pathdataset.py
File metadata and controls
102 lines (81 loc) · 3.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import torch
from gomoku import Position, IntersectionState
class PositionDataset:
"""
(局面, 着手, 勝敗)のデータセット
"""
def __init__(self, path: str, max_count = 1.0 * 10 ** 18, verbose: bool = True):
# メモリを節約するために, 局面はbitboardで保持する.
self.__positions: list[tuple[int, int, int]] = []
self.__moves: list[int] = []
self.__outcomes: list[float] = []
with open(path, "r") as file:
for i, line in enumerate(file):
if i >= max_count:
break
pos, move, outcome = PositionDataset.parse_dataset_text(line)
self.__positions.append(pos)
self.__moves.append(move)
self.__outcomes.append(outcome)
if i % 100000 == 0 and verbose:
print(f"loaded {i} positions")
def __len__(self) -> int:
return len(self.__positions)
def __getitem__(self, index) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
"""
index番目の局面, 着手, 勝敗を返す.
"""
pos = self.__positions[index]
move = self.__moves[index]
outcome = self.__outcomes[index]
pos_tensor = PositionDataset.__position_to_tensor(pos)
move_tensor = torch.tensor(move, dtype=torch.int64)
outcome_tensor = torch.tensor(outcome, dtype=torch.float32)
return pos_tensor, move_tensor, outcome_tensor
@staticmethod
def __position_to_tensor(pos: tuple[int, int, int]) -> torch.Tensor:
"""
局面をone-hotベクトルに変換する.
posは(盤面サイズ, プレイヤーのbitboard, 相手のbitboard)のタプル.
"""
board_size, player, opponent = pos
tensor = torch.zeros((2, board_size, board_size), dtype=torch.float32)
for coord in range(board_size ** 2):
if player & (1 << coord):
tensor[0, coord // board_size, coord % board_size] = 1.0
elif opponent & (1 << coord):
tensor[1, coord // board_size, coord % board_size] = 1.0
return tensor
@staticmethod
def position_to_text(pos: Position, move: int, outcome: float) -> str:
"""
データセットでは, Xを手番側の石, Oを相手側の石, -を空きマスとして表現する.
また, 最後にその局面の直後に行われた着手と対局の結果を付与する.
"""
text = []
for coord in range(pos.size ** 2):
if pos.get_intersection_state_at(coord) == pos.side_to_move:
text.append('X')
elif pos.get_intersection_state_at(coord) == pos.opponent_color:
text.append('O')
else:
text.append('-')
text.append(f" {move} {outcome}")
return ''.join(text)
@staticmethod
def parse_dataset_text(text: str) -> tuple[tuple[int, int, int], int, float]:
"""
データセットのテキスト表現から局面, 着手, 勝敗を抽出する.
"""
board, move, outcome = text.strip().split()
board_size = Position.SQRT_TABLE[len(board)]
player = 0
opponent = 0
for coord, state in enumerate(board):
if state == 'X':
player |= 1 << coord
elif state == 'O':
opponent |= 1 << coord
move = int(move)
outcome = float(outcome)
return (board_size, player, opponent), move, outcome