メインコンテンツまでスキップ

useShogiProblem

useShogiProblem は、「次の一手問題」UIを構築するためのフックです。課題局面を受け取り、ユーザーが指した手と正解手を比較して正誤判定を行います。

主な使い方: extractProblemsFromKifu との組み合わせ

問題データを手動で作成する必要はありません。エンジン解析済みの棋譜(KIF)があれば、extractProblemsFromKifu自動的に悪手局面を抽出して useShogiProblem に渡せる形式で返してくれます

解析済みKIF → extractProblemsFromKifu → ShogiProblem[] → useShogiProblem
import React from 'react';
import {
extractProblemsFromKifu,
useShogiProblem,
ShogiBoard,
CandidateList,
} from 'react-kifu-player';

const kifuString = `...(エンジン解析コメント付きのKIF)...`;

function ProblemApp() {
const [index, setIndex] = React.useState(0);

// 解析済み棋譜から問題を自動生成(後手側の悪手を最大5問抽出)
const problems = React.useMemo(() =>
extractProblemsFromKifu(kifuString, {
playerColor: 'white',
evalDropThreshold: 300,
correctMoveThreshold: 150,
maxProblems: 5,
}), []
);

const current = problems[index];

// useShogiProblem は ShogiProblem をそのまま受け取れる
// ※ フックのルールにより、常に呼び出す必要がある
const problem = useShogiProblem(current ?? {
sfen: 'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1',
playerColor: 'black',
correctMoves: [],
});

if (!current) return <p>問題がありません</p>;

return (
<div>
<p>{index + 1}/{problems.length} 問目 (評価値 -{Math.abs(current.evalDrop)} の悪手局面)</p>

<ShogiBoard
position={problem.position}
lastMove={problem.lastMove}
interactive={problem.status === 'playing'}
onSquareClick={problem.handleSquareClick}
selectedSquare={problem.selectedSquare}
highlightSquares={problem.legalMoveSquares}
reversed={current.playerColor === 'white'} // 後手番なら盤面を反転
/>

{problem.status === 'correct' && (
<p>🎉 正解! ({problem.result?.correctMovesText?.[0]})</p>
)}
{problem.status === 'incorrect' && (
<div>
<p>❌ 不正解。正解: {problem.result?.correctMovesText?.join(' / ')}</p>
{/* 正解手の読み筋を候補手リストで表示することも可能 */}
{current.correctMoveCandidates && (
<CandidateList
candidates={current.correctMoveCandidates}
onCandidateClick={(cand) => problem.startPlayback(cand)}
/>
)}
</div>
)}

<button onClick={problem.reset}>やり直す</button>
<button onClick={() => setIndex((i) => (i + 1) % problems.length)}>
次の問題
</button>
</div>
);
}

SFENを直接指定する使い方

問題データを自分で用意している場合は、SFEN・手番・正解手を直接指定することもできます。

import { useShogiProblem, ShogiBoard } from 'react-kifu-player';

function ManualProblem() {
const problem = useShogiProblem({
sfen: 'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1',
playerColor: 'black',
correctMoves: ['7g7f'], // USI形式で指定
});

return (
<ShogiBoard
position={problem.position}
lastMove={problem.lastMove}
interactive={true}
onSquareClick={problem.handleSquareClick}
selectedSquare={problem.selectedSquare}
highlightSquares={problem.legalMoveSquares}
/>
);
}

💡 正解手なし(correctMoves: [])にすると、自由に駒を動かせるインタラクティブな盤面として使えます。

入力オプション

パラメータ必須説明
sfenstring課題局面のSFEN文字列
playerColor'black' | 'white'自分の手番
correctMovesstring[]正解手のリスト(USI形式)。extractProblemsFromKifu から取得した値をそのまま渡せます
correctMoveCandidatesCandidate[]正解手の読み筋(extractProblemsFromKifu の返り値から取得できます)
badMovestring当時の悪手(USI形式)。extractProblemsFromKifu の返り値から自動で入ります
badMoveEvalnumber悪手時の評価値
bestMoveEvalnumber最善手の評価値

返り値

プロパティ/メソッド説明
positionPosition現在の局面(ShogiBoardposition にそのまま渡せます)
lastMove{from, to} | undefined最終手の座標
status'playing' | 'correct' | 'incorrect'現在の解答状況
selectedSquareBoardSquareCoord | null選択中のマス(ShogiBoardselectedSquare にそのまま渡せます)
legalMoveSquaresBoardSquareCoord[]合法手のマスリスト(ShogiBoardhighlightSquares にそのまま渡せます)
handleSquareClick(sq: SquareClick) => voidマスクリックハンドラ(ShogiBoardonSquareClick にそのまま渡せます)
resultProblemResult | null手を指した後の正誤結果情報
reset()() => void問題を最初からやり直す
startPlayback(candidate)(candidate: Candidate) => void正解手の読み筋を自動再生する
playbackState{currentPly, totalPlies} | null再生中の状態

実際の動作デモ

以下は extractProblemsFromKifudemo.kifu から実際の次の一手問題を抽出し、useShogiProblem で出題するデモです。駒をクリック→移動先をクリックで解答できます。

Loading Demo...