Skip to content

Commit

Permalink
Merge pull request #87 from kobanium/develop
Browse files Browse the repository at this point in the history
Support #81, #83, #84, Fix #82
  • Loading branch information
kobanium authored Dec 31, 2023
2 parents 3a5461d + 4e91913 commit d4fbe56
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 30 deletions.
79 changes: 78 additions & 1 deletion board/go_board.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""碁盤のデータ定義と操作処理。
"""
from typing import List, NoReturn
from typing import List, Tuple, NoReturn
from collections import deque
import numpy as np

Expand Down Expand Up @@ -184,6 +184,56 @@ def put_stone(self, pos: int, color: Stone) -> NoReturn:
self.record.save(self.moves, color, pos, self.positional_hash)
self.moves += 1

def put_handicap_stone(self, pos: int, color: Stone) -> NoReturn:
"""指定された座標に指定された色の置き石を置く。
Args:
pos (int): 石を置く座標。
color (Stone): 置く石の色。
"""
opponent_color = Stone.get_opponent_color(color)

self.board[pos] = color
self.pattern.put_stone(pos, color)
self.positional_hash = affect_stone_hash(self.positional_hash, pos, color)

neighbor4 = self.get_neighbor4(pos)

connection = []
prisoner = 0

for neighbor in neighbor4:
if self.board[neighbor] == color:
self.strings.remove_liberty(neighbor, pos)
connection.append(self.strings.get_id(neighbor))
elif self.board[neighbor] == opponent_color:
self.strings.remove_liberty(neighbor, pos)
if self.strings.get_num_liberties(neighbor) == 0:
removed_stones = self.strings.remove_string(self.board, neighbor)
prisoner += len(removed_stones)
for removed_pos in removed_stones:
self.pattern.remove_stone(removed_pos)
self.positional_hash = affect_string_hash(self.positional_hash, \
removed_stones, opponent_color)

if color == Stone.BLACK:
self.prisoner[0] += prisoner
elif color == Stone.WHITE:
self.prisoner[1] += prisoner

if len(connection) == 0:
self.strings.make_string(self.board, pos, color)
if prisoner == 1 and self.strings.get_num_liberties(pos) == 1:
self.ko_move = self.moves
self.ko_pos = self.strings.string[self.strings.get_id(pos)].lib[0]
elif len(connection) == 1:
self.strings.add_stone(self.board, pos, color, connection[0])
else:
self.strings.connect_string(self.board, pos, color, connection)

# 着手した時に記録
self.record.save_handicap(pos)

def _is_suicide(self, pos: int, color: Stone) -> bool:
"""自殺手か否かを判定する。
自殺手ならTrue、そうでなければFalseを返す。
Expand Down Expand Up @@ -469,6 +519,33 @@ def get_komi(self) -> float:
"""
return self.komi

def get_to_move(self) -> Stone:
"""手番の色を取得する。
Returns:
Stone: 手番の色。
"""
if self.moves == 1:
return Stone.BLACK
last_move_color, _, _ = self.record.get(self.moves - 1)
return Stone.get_opponent_color(last_move_color)

def get_move_history(self) -> List[Tuple[Stone, int, np.array]]:
"""着手の履歴を取得する。
Returns:
[(Stone, int, np.array), ...]: (着手の色、座標、ハッシュ値) のリスト。
"""
return [self.record.get(m) for m in range(1, self.moves)]

def get_handicap_history(self) -> List[int]:
"""置き石の座標を取得する。
Returns:
List[int]: 置き石の座標のリスト。
"""
return self.record.handicap_pos[:]

def count_score(self) -> int: # pylint: disable=R0912
"""領地を簡易的にカウントする。
Expand Down
83 changes: 83 additions & 0 deletions board/handicap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""置き石の座標。
"""
from typing import List


handicap_coordinate_map = {
9 : {
2 : ["G7", "C3",],
3 : ["C7", "G7", "C3"],
4 : ["C7", "G7", "C3", "G3"],
5 : ["C7", "G7", "E5", "C3", "G3"],
6 : ["C7", "G7", "C5", "G5", "C3", "G3"],
7 : ["C7", "G7", "C5", "E5", "G5", "C3", "G3"],
8 : ["C7", "E7", "G7", "C5", "G5", "C3", "E3", "G3"],
9 : ["C7", "E7", "G7", "C5", "E5", "G5", "C3", "E3", "G3"],
},
11 : {
2 : ["J9", "C3"],
3 : ["C9", "J9", "C3"],
4 : ["C9", "J9", "C3", "J3"],
5 : ["C9", "J9", "F6", "C3", "J3"],
6 : ["C9", "J9", "C6", "J6", "C3", "J3"],
7 : ["C9", "J9", "C6", "F6", "J6", "C3", "J3"],
8 : ["C9", "F9", "J9", "C6", "J6", "C3", "F3", "J3"],
9 : ["C9", "F9", "J9", "C6", "F6", "J6", "C3", "F3", "J3"],
},
13 : {
2 : ["K10", "D4"],
3 : ["D10", "K10", "D4"],
4 : ["D10", "K10", "D4", "K4"],
5 : ["D10", "K10", "G7", "D4", "K4"],
6 : ["D10", "K10", "D7", "K7", "D4", "K4"],
7 : ["D10", "K10", "D7", "G7", "K7", "D4", "K4"],
8 : ["D10", "G10", "K10", "D7", "K7", "D4", "G4", "K4"],
9 : ["D10", "G10", "K10", "D7", "G7", "K7", "D4", "G4", "K4"],
},
15 : {
2 : ["M12", "D4"],
3 : ["D12", "M12", "D4"],
4 : ["D12", "M12", "D4", "M4"],
5 : ["D12", "M12", "H8", "D4", "M4"],
6 : ["D12", "M12", "D8", "M8", "D4", "M4"],
7 : ["D12", "M12", "D8", "H8", "M8", "D4", "M4"],
8 : ["D12", "H12", "M12", "D8", "M8", "D4", "H4", "M4"],
9 : ["D12", "H12", "M12", "D8", "H8", "M8", "D4", "H4", "M4"],
},
17 : {
2 : ["O14", "D4"],
3 : ["D14", "O14", "D4"],
4 : ["D14", "O14", "D4", "O4"],
5 : ["D14", "O14", "J9", "D4", "O4"],
6 : ["D14", "O14", "D9", "O9", "D4", "O4"],
7 : ["D14", "O14", "D9", "J9", "O9", "D4", "O4"],
8 : ["D14", "J14", "O14", "D9", "O9", "D4", "J4", "O4"],
9 : ["D14", "J14", "O14", "D9", "J9", "O9", "D4", "J4", "O4"],
},
19 : {
2 : ["Q16", "D4"],
3 : ["D16", "Q16", "D4"],
4 : ["D16", "Q16", "D4", "Q4"],
5 : ["D16", "Q16", "K10", "D4", "Q4"],
6 : ["D16", "Q16", "D10", "Q10", "D4", "Q4"],
7 : ["D16", "Q16", "D10", "K10", "Q10", "D4", "Q4"],
8 : ["D16", "K16", "Q16", "D10", "Q10", "D4", "K4", "Q4"],
9 : ["D16", "K16", "Q16", "D10", "K10", "Q10", "D4", "K4", "Q4"],
},
}


def get_handicap_coordinates(size: int, handicaps: int) -> List[int]:
"""置き石の座標リストを取得する。
Args:
size (int): 碁盤のサイズ。
handicaps (int): 置き石の数。
Returns:
List[int]: 置き石の座標リスト。
"""
if size in handicap_coordinate_map and \
handicaps in handicap_coordinate_map[size]:
return handicap_coordinate_map[size][handicaps]
return None
10 changes: 10 additions & 0 deletions board/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ def __init__(self):
self.color = [Stone.EMPTY] * MAX_RECORDS
self.pos = [PASS] * MAX_RECORDS
self.hash_value = np.zeros(shape=MAX_RECORDS, dtype=np.uint64)
self.handicap_pos = []

def clear(self) -> NoReturn:
"""データを初期化する。
"""
self.color = [Stone.EMPTY] * MAX_RECORDS
self.pos = [PASS] * MAX_RECORDS
self.hash_value.fill(0)
self.handicap_pos = []

def save(self, moves: int, color: Stone, pos: int, hash_value: np.array) -> NoReturn:
"""着手の履歴の記録する。
Expand All @@ -41,6 +43,14 @@ def save(self, moves: int, color: Stone, pos: int, hash_value: np.array) -> NoRe
else:
print_err("Cannot save move record.")

def save_handicap(self, pos: int) -> NoReturn:
"""置き石の座標を記録する。
Args:
pos (int): 置き石の座標。
"""
self.handicap_pos.append(pos)

def has_same_hash(self, hash_value: np.array) -> bool:
"""同じハッシュ値があるかを確認する。
Expand Down
Loading

0 comments on commit d4fbe56

Please sign in to comment.