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

extractProblemsFromKifu

extractProblemsFromKifu は、エンジン解析付き棋譜から「次の一手問題」を自動生成するユーティリティ関数です。

解析済み棋譜(KIFコメントに ** 解析 候補N ... 形式でAI評価値が記録されているもの)を読み込み、「自分が悪手を指してしまった局面」を自動的に抽出して問題化します。

なぜこれが必要か

useShogiProblem で問題を出題するには、課題局面のSFEN・正解手(USI形式)・プレイヤーの手番などのデータが必要です。 これらを手動で作成するのは大変ですが、エンジン解析済みの棋譜さえあれば extractProblemsFromKifu が全て自動で用意してくれます。

解析済みKIF → extractProblemsFromKifu → ShogiProblem[] → useShogiProblem

基本的な使い方

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

// 解析コメント付きのKIF文字列(Floodgate棋譜・将棋所出力など)
const kifuString = `...`;

// 後手側の悪手を最大5問抽出する
const problems = extractProblemsFromKifu(kifuString, {
playerColor: 'white', // 問題にする手番 ('black' or 'white')
evalDropThreshold: 300, // 評価値が300以上落ちた手を悪手と判定
correctMoveThreshold: 150, // 最善手との差が150以内を全て正解とする
maxProblems: 5,
});

// 問題を使って出題する
const problem = useShogiProblem(problems[0]);

オプション

パラメータデフォルト説明
playerColor'black' | 'white'✅ 必須悪手判定の対象となる手番。自分(問題を解くプレイヤー)の手番を指定します
evalDropThresholdnumber500悪手と判定する評価値落差のしきい値(正の値で指定)。300 なら評価値が300以上落ちた手を抽出します
correctMoveThresholdnumber100複数正解を許容する範囲。AI最善手との評価値差がこの値以内の候補手を全て正解とします
maxProblemsnumber無制限抽出する最大問題数。評価値落差(evalDrop)が大きい順(最悪手が先)にN件返されます
minAdvantagenumber-200問題抽出の対象とする局面の最低評価値。すでに大きく不利な局面での悪手は除外できます

返り値の型: ShogiProblem

type ShogiProblem = {
sfen: string; // 課題局面のSFEN文字列
playerColor: 'black' | 'white'; // 解答プレイヤーの手番
correctMoves: string[]; // 正解手のリスト(USI形式)
correctMoveCandidates?: Candidate[]; // 正解手の読み筋データ(CandidateListに渡せる)
badMove: string; // 当時の悪手(USI形式)
badMoveEval: number; // 悪手を指した後の評価値
bestMoveEval: number; // AIが示した最善手の評価値
evalDrop: number; // 評価値の落差(負の値)
sourcePly?: number; // 元棋譜での手数(参考情報)
};

この ShogiProblem オブジェクトは useShogiProblem にそのまま渡せます(全てのフィールドが対応しています)。

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);

const problems = React.useMemo(() =>
extractProblemsFromKifu(kifuString, {
playerColor: 'white',
evalDropThreshold: 300,
correctMoveThreshold: 150,
maxProblems: 5,
}), []
);

const current = problems[index];

// useShogiProblem は常に呼び出す(フックのルール)
const problem = useShogiProblem(current ?? {
sfen: 'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1',
playerColor: 'black',
correctMoves: [],
});

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

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>🎉 正解! AIも推奨した最善手です</p>}

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

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

解析済み棋譜の作り方

extractProblemsFromKifu は棋譜のKIFコメントにエンジン評価値が含まれている必要があります。以下のツールで解析済み棋譜を生成できます。

  • 将棋所 / ShogiGUI: メニューから「エンジン解析」を実行し、解析コメント付きでKIF保存
  • Floodgate棋譜: すでに解析済みコメントが付いているものが多い
  • やねうら王 / dlshogi: CLI から解析出力を KIF コメントとして書き出す

解析コメントの形式(自動認識されます):

** 解析 0 ○ 候補1 時間 00:10.0 深さ 22 ノード数 12345 評価値 450 読み筋 ▲7六歩 △8四歩 ...
** 解析 0 候補2 時間 00:10.0 深さ 18 ノード数 12345 評価値 380 読み筋 ▲2六歩 ...