Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

例とパターン

局面の操作、棋譜の変換、エラー処理の例を示します。 基本的な使い方は クイックスタート を参照してください。

対局のシミュレーション

ランダム対局

import random
from rsshogi.core import Board

board = Board()

# 最大200手までランダムに対局
for i in range(200):
    moves = board.legal_moves()
    if not moves:
        break

    move = random.choice(moves)
    board.apply_move(move)

    if board.is_repetition():
        break

# 結果を確認
if board.is_mated():
    # is_mated() が True のとき board.turn は詰まされた側。勝者はその相手。
    winner = "先手" if board.turn.is_white() else "後手"
    print(f"{board.game_ply - 1}手で{winner}の勝ち(詰み)")
elif board.is_repetition():
    print(f"千日手: {board.repetition_state().to_usi()}")
else:
    print(f"{board.game_ply - 1}手で終了")

game_ply は SFEN の手数欄に対応し、平手初期局面では 1 です。 この例のように初期局面から進めた場合、指し終えた手数は game_ply - 1 になります。 is_repetition() は同一局面の 4 回目の出現を判定します。 repetition_state() が返す持ち駒の優等局面や劣等局面は、対局の終了条件には使いません。

合法手を探索(1手先読み)

from rsshogi.core import Board

board = Board()

# 各合法手を試して評価
for move in board.legal_moves():
    board.apply_move(move)

    # 相手の合法手数を評価値として使用
    score = len(board.legal_moves())
    print(f"{move.to_usi()}: 相手の合法手 {score} 手")

    board.undo_move(move)

棋譜処理

複数の棋譜ファイルを処理

この例は Shift_JIS の .kif ファイルを読みます。 UTF-8 のファイルを扱う場合は Record.from_kif_file()encoding="utf-8" を指定してください。

from pathlib import Path
from rsshogi.record import Record

kif_dir = Path("kifu")

for kif_file in kif_dir.glob("*.kif"):
    try:
        record = Record.from_kif_file(str(kif_file))
        print(f"{kif_file.name}: {record.move_count}手 - {record.result.name}")
    except Exception as e:
        print(f"{kif_file.name}: エラー - {e}")

棋譜から特定の局面を抽出

from rsshogi.core import Board
from rsshogi.record import Record

record = Record.from_kif_file("example.kif")
board = Board(sfen=record.init_position_sfen)

# 本譜の先頭から最大10手を再生
replayed = record.moves[:10]
for move_rec in replayed:
    board.apply_move(move_rec.move)

print(f"{len(replayed)}手進めた局面: {board.to_sfen()}")

棋譜のフォーマット変換

from rsshogi.record import Record

# KIF → CSA
record = Record.from_kif_file("input.kif")
record.write_csa("output.csa")

# CSA → KIF
record = Record.from_csa_file("input.csa")
record.write_kif("output.kif")

# 一括変換
from pathlib import Path

for kif_file in Path("kifu").glob("*.kif"):
    record = Record.from_kif_file(str(kif_file))
    csa_file = kif_file.with_suffix(".csa")
    record.write_csa(str(csa_file))

局面の分析

駒の配置を確認

from rsshogi.core import Board
from rsshogi.types import Color, PieceType, Square

board = Board()

# 全てのマスを走査
for file in range(9, 0, -1):  # 9〜1筋
    for rank in range(1, 10):  # 1〜9段
        sq = Square.from_usi(f"{file}{chr(ord('a') + rank - 1)}")
        piece = board.piece_on(sq)
        if piece.piece_type != PieceType.NO_PIECE_TYPE:
            print(f"{file}{rank}: {piece.piece_type.to_usi()}")

特定の駒の位置を取得

from rsshogi.core import Board
from rsshogi.types import Color, PieceType

board = Board()

# 先手の歩の位置をビットボードで取得
pawns = board.pieces_for(PieceType.PAWN, Color.BLACK)
print(f"先手の歩: {pawns.count()}枚")

# 全ての飛車・角の位置
rooks = board.pieces_by_type(PieceType.ROOK)
bishops = board.pieces_by_type(PieceType.BISHOP)

持ち駒の確認

from rsshogi.core import Board
from rsshogi.types import Color, PieceType

board = Board()

# 指し手を適用して駒を取る
board.apply_usi("7g7f")
board.apply_usi("3c3d")
board.apply_usi("8h2b+")  # 角を取り、馬に成る

# 持ち駒を確認
for color in [Color.BLACK, Color.WHITE]:
    hand = board.hand(color)
    name = "先手" if color == Color.BLACK else "後手"
    pieces = []
    for pt in [PieceType.ROOK, PieceType.BISHOP, PieceType.GOLD,
               PieceType.SILVER, PieceType.KNIGHT, PieceType.LANCE, PieceType.PAWN]:
        count = hand.count(pt)
        if count > 0:
            pieces.append(f"{pt.to_usi()}:{count}")
    if pieces:
        print(f"{name}の持ち駒: {', '.join(pieces)}")

エラーハンドリング

違法手の検出

from rsshogi.core import Board, Move

board = Board()

# 方法1: 例外をキャッチ
try:
    board.apply_usi("9a9b")  # 違法手
except ValueError as e:
    print(f"違法手です: {e}")

# 方法2: 事前にチェック
move = Move.from_usi("7g7f")
if board.is_legal_move(move):
    board.apply_move(move)
else:
    print("この手は指せません")

最後の手を取り消す

from rsshogi.core import Board

board = Board()

# 方法1: last_move を確認してから undo_move32
last_move = board.last_move()
if last_move:
    board.undo_move32(last_move)
else:
    print("戻せる手がありません")

Move32 と Move の使い分け

from rsshogi.core import Board, Move32, Move

board = Board()

# Move: legal_moves() が返す型(基本はこちら)
moves = board.legal_moves()  # list[Move]
mv = moves[0]
print(type(mv).__name__)  # Move

# Move32: 32bit 指し手が必要な場合
moves32 = board.legal_moves_move32()  # list[Move32]
move32 = moves32[0]
print(type(move32).__name__)  # Move32

# 型に対応するメソッドを使う
board.apply_move(mv)
board.undo_move(mv)
board.apply_move32(move32)

Rust 内部では Move が 16 ビット、Move32 が 32 ビットの表現です。 Python オブジェクトには別途管理用のメモリが必要なため、Python のリストが 1 手あたり 2 バイトまたは 4 バイトになるわけではありません。

実行可能なサンプル

リポジトリの examples/python/ に実行可能なサンプルがあります。

# 基本的な盤面操作
python examples/python/basic.py

# apply_move と undo_move
python examples/python/push_pop.py

# 合法手と擬似合法手
python examples/python/board_moves.py

次のステップ