N-Queens問題は、n×nのチェスボード上にn個のクイーンを配置する問題です。クイーンは縦・横・斜めの全方向に移動できるため、互いに攻撃し合わない位置に配置する必要があります。
/**
* N-Queens問題を解く関数
* @param n - チェスボードのサイズ (n x n)
* @returns 全ての解の配列。各解は文字列の配列で、'Q'はクイーン、'.'は空きマスを表す
*/
function solveNQueens(n: number): string[][] {
const result: string[][] = [];
const board: string[][] = Array(n).fill(null).map(() => Array(n).fill('.'));
/**
* 指定された位置にクイーンを配置できるかチェック
* @param row - 行のインデックス
* @param col - 列のインデックス
* @returns 配置可能かどうか
*/
function isSafe(row: number, col: number): boolean {
// 同じ列をチェック(上方向のみ、下はまだ配置していないため)
for (let i = 0; i < row; i++) {
if (board[i][col] === 'Q') return false;
}
// 左上対角線をチェック
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] === 'Q') return false;
}
// 右上対角線をチェック
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (board[i][j] === 'Q') return false;
}
return true;
}
/**
* バックトラッキングを使用してクイーンを配置
* @param row - 現在の行
*/
function backtrack(row: number): void {
// ベースケース:全ての行にクイーンを配置完了
if (row === n) {
// 現在のボード状態を文字列配列として結果に追加
result.push(board.map(row => row.join('')));
return;
}
// 現在の行の各列でクイーンの配置を試行
for (let col = 0; col < n; col++) {
if (isSafe(row, col)) {
// クイーンを配置
board[row][col] = 'Q';
// 次の行に進む
backtrack(row + 1);
// バックトラック(クイーンを取り除く)
board[row][col] = '.';
}
}
}
backtrack(0);
return result;
}
result とボード配列
board を初期化します。ボードは二次元配列で、全てのセルを '.'
で初期化します。
col の上方向(row=0からrow-1まで)にクイーンが存在するかチェック
(row-1, col-1) から
(0, 0) 方向へ対角線上にクイーンが存在するかチェック
(row-1, col+1) から
(0, n-1) 方向へ対角線上にクイーンが存在するかチェック
// 実際のパフォーマンス測定例
function measurePerformance() {
const testCases = [4, 5, 6, 7, 8];
testCases.forEach(n => {
const start = performance.now();
const solutions = solveNQueens(n);
const end = performance.now();
console.log(`N=${n}: ${solutions.length} solutions in ${(end - start).toFixed(2)}ms`);
});
}
// 期待される結果:
// N=4: 2 solutions
// N=5: 10 solutions
// N=6: 4 solutions
// N=7: 40 solutions
// N=8: 92 solutions
// 型注釈による安全性向上
function solveNQueens(n: number): string[][] {
// 戻り値の型が明確
const result: string[][] = [];
// 2次元配列の型が明示的
const board: string[][] = Array(n).fill(null)
.map((): string[] => Array(n).fill('.'));
// 内部関数も適切な型注釈
function isSafe(row: number, col: number): boolean {
// パラメータと戻り値の型が明確
// ...
}
}
Array(n).fill(null).map()
を使用してTypeScriptの型チェッカーを満足させつつ、効率的な初期化を実現
board.map(row => row.join('')) で文字列変換時のみ新しい配列を作成
isSafe 関数で攻撃される位置が見つかったら即座にfalseを返す
// テスト実行例
console.log("N=1の場合:");
console.log(solveNQueens(1));
// 出力: [["Q"]]
console.log("N=4の場合:");
const result4 = solveNQueens(4);
console.log(`解の数: ${result4.length}`);
result4.forEach((solution, index) => {
console.log(`解 ${index + 1}:`);
solution.forEach(row => console.log(row));
console.log();
});
// 出力:
// 解の数: 2
// 解 1:
// .Q..
// ...Q
// Q...
// ..Q.
//
// 解 2:
// ..Q.
// Q...
// ...Q
// .Q..