NAME

Game::Shogi - shogi, Japanese chess, where a captured piece changes sides

VERSION

Version 0.01

SYNOPSIS

use Game::Shogi;

my $game = Game::Shogi->new;                       # an even game
my $give = Game::Shogi->new(handicap => 'bishop'); # White without its bishop, moving first

if (my $refusal = $game->play('7g7f')) {
    print $refusal->message, "\n";
}
print $_->usi, "\n" for $game->legal;

$game->undo;
print $game->sfen, "\n";
if (my $r = $game->result) { print $r->how, ' ', $r->winner // 'draw', "\n" }

my $again = Game::Shogi->from_log($game->log);

DESCRIPTION

Shogi is played by two on a board of nine by nine squares, twenty pieces a side. A piece that is captured goes into its captor's hand and may be dropped back onto the board as the captor's own.

This is the game: a board, the moves made on it, and how it ended. Every rule is the board's, Game::Shogi::Engine; this class keeps the game and says why a move was refused. A refused move comes back as a Game::Shogi::Error and is never thrown.

A side is 'b' for Black, who moves first in an even game, and 'w' for White. A move is a USI string (7g7f, 8h2b+, P*5e) or a Game::Shogi::Move.

It is the engine behind the Shogi at https://peer2peergames.com.

CONSTRUCTOR

new

Game::Shogi->new
Game::Shogi->new(handicap => 'rook')
Game::Shogi->new(sfen => $sfen, cap => 300)

An even game; a handicap game from Game::Shogi::Handicap, White without those pieces and to move; or a game from any position. cap is the move count at which the game is drawn (500, the Japan Shogi Association's). Croaks for a handicap that is not one, a handicap and a position together, or a position the board refuses.

A misspelt argument name is not caught: Object::Proto::Sugar drops an unknown name, or reads the arguments by position, so handicapp would start an even game. Check handicap after construction when it matters.

from_log

my $game = Game::Shogi->from_log($log, cap => 300);

The game a "log" writes, replayed move by move. Croaks, naming the move, when one is refused.

ATTRIBUTES

handicap

The handicap's name, or undef for a game without one.

THE POSITION

board

A copy of the board, a Game::Shogi::Engine. Changing it changes nothing here.

start

The SFEN the game started from.

sfen

The position now, as SFEN.

side

The side to move, 'b' or 'w'.

turn

The side to move, or undef once the game is over.

status

'active' or 'finished'.

move_number

The board's move number: 1 at the start, and one more for each move by either side.

in_check

True when the side to move is in check.

can_declare

True when the side to move may declare the impasse now.

hand

my $hand = $game->hand('b');    # { P => 2, R => 1 }

A side's pieces in hand, only those it has.

Every legal move of the side to move, as Game::Shogi::Moves; none once the game is over.

moves

The moves made, as USI strings, oldest first.

history

The keys of the positions the game has stood in before this one, oldest first, which a search needs to see a repetition coming.

PLAYING

Each of these returns 0 when it is done, or a Game::Shogi::Error saying why it was refused.

play

my $refusal = $game->play('7g7f');

Makes a move. A move that breaks a rule is refused with the first rule it breaks: not_your_piece, not_in_hand, cannot_reach, occupied, promote_not_allowed, promote_required, dead_piece, two_pawns, in_check or pawn_drop_mate; bad_move for a string that is not a move; game_over once the game is over. A move that ends the game sets "result".

undo

Takes back the last move, and any ending it made. Refused with nothing_to_undo before the first move, and with game_over after a resignation or a declaration, which are not moves.

resign

$game->resign('b');

The side to move resigns, and the other wins. not_your_turn for the other side; game_over once the game is over.

declare

The side to move declares the impasse and wins: its king and ten other pieces in the enemy camp, not in check, and 28 points as Black or 27 as White. cannot_declare, with the condition that failed, otherwise.

THE END

result

A Game::Shogi::Result, or undef while the game is on: mate, no_move and perpetual_check are losses for the side they name, sennichite and cap are draws, and resign and impasse_declared are what a side did.

winner

The result's winner: 'b', 'w', or undef while the game is on or for a draw.

THE LOG

log

{ start => $sfen, moves => [ '7g7f', ... ], handicap => 'rook' }

What a game needs to be played again: the start, the moves as USI, and the handicap when there was one.

record

The game written down by Game::Shogi::Notation: each move with its side, its Hodges and its Japanese.

to_text

my $text = $game->to_text;

The game as a string, from which "from_text" builds the same game again: the handicap when there was one, the start as SFEN, the cap, every move as USI, and a resignation or a declaration, which the moves cannot show. Two games with the same history write the same string.

from_text

my $again = Game::Shogi->from_text($text);

A new game built from a string "to_text" wrote, by replaying its moves and then its ending. A string that is not one to_text writes croaks with a sentence naming what is wrong: a missing or unknown line, a cap that is not a number, a move the replay refuses by its number, or an ending refused.

THE RULES THIS DISTRIBUTION CHOSE

Where the rules of shogi leave a choice, or differ between tournament play and casual play, this is the choice made here.

An illegal move is refused, not lost

Tournament play loses a game for an illegal move. Here "play" refuses it and says why, and the side to move moves again.

Perpetual check loses

The fourth time a position repeats, the side that gave check with every one of its moves in the cycle loses (perpetual_check). Any other fourfold repetition is a draw (sennichite), with no replay.

The impasse is the 27-point declaration

On its turn a side may declare when its king is in the enemy camp, ten of its other pieces are there, it is not in check, and it has 28 points (Black) or 27 (White), counting a rook or bishop as five and every other piece as one, from the pieces in the camp and in hand. A correct declaration wins (impasse_declared); see "declare".

A game that nobody ends is drawn at 500 moves

The JSA's rule (cap). A side in check at the cap plays on until it is not. cap in "new" changes the number.

Black moves first in an even game

The furigoma, the toss that decides who takes Black, is left to the caller. In a handicap game the giver plays White and moves first.

SEE ALSO

Game::Shogi::Engine, the board and its rules; Game::Shogi::Notation; Game::Shogi::Handicap.

Games::Shogi describes the boards and pieces of shogi's large variants. It has no move generator and no search.

AUTHOR

LNATION <email@lnation.org>

BUGS

Please report any bugs or feature requests to bug-game-shogi at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Game-Shogi. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Game::Shogi

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION <email@lnation.org>.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)