ナンプレを解くアルゴリズム その5 | Photoshop CC Tutorials
今回は下図のように確定されている数字をマスの中に入れるプログラムを作成しました。
次回からは空いているマスすべてに数字を入れてナンプレを完成させてみたいと思います。

$ピック社長のブログ

参考サイト:http://itpro.nikkeibp.co.jp/article/COLUMN/20070109/258279/

実行結果
$ピック社長のブログ

Main.as
package 
{
import flash.display.Sprite;
import flash.events.Event;

/**
* ナンプレを解くプログラム
*/
public class Main extends Sprite
{
public var nanpleWork:Array = new Array(9);
/* 盤面 */
public var nanpleTable:Array = [
[0, 0, 8, 0, 0, 0, 0, 0, 0, ],
[1, 0, 0, 6, 0, 0, 3, 0, 0, ],
[0, 0, 0, 5, 1, 0, 9, 0, 0, ],
[0, 0, 1, 0, 0, 0, 4, 0, 0, ],
[0, 6, 0, 0, 8, 7, 0, 0, 0, ],
[0, 0, 0, 0, 3, 0, 5, 0, 2, ],
[0, 0, 9, 0, 0, 4, 0, 0, 0, ],
[0, 7, 0, 0, 0, 9, 0, 4, 0, ],
[5, 3, 0, 0, 0, 0, 0, 0, 0, ],
];

public function Main():void
{
// 二次元配列の作成
for (var i:int = 0; i < 9; i++ ) {
nanpleWork[i] = new Array(9);
for (var j:int = 0; j < 9; j++ ) {
nanpleWork[i][j] = new t_nanpleItem();
}
}

// 初期化
init();

for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
// 盤面のうち確定しているものを確認
item_set_checkno_fromareahitno(j, i);

if (nanpleWork[i][j].hitno == 0) {
// 候補の数を絞り込む
// 縦,横,3x3のいずれかで
item_set_hitno_fromareacheckno(j, i);
// 確定したかどうか確認
item_check_checknolist(j, i);
}
}
}

dump();
}

// 表示
public function dump():void
{
var string:String;
for (var i:int = 0; i < 9; i++ ) {
for (var j:int = 0; j < 9; j++ ) {
if (!string) {
string = nanpleWork[0][0].hitno.toString();
}else {
if (j == 8) {
string += nanpleWork[i][j].hitno.toString();
string += "\n";
}else {
string += nanpleWork[i][j].hitno.toString();
}
}
}
}
trace(string);
}

/* -------------------------------------------------------- */
/* 盤面のデータからnanpleWorkの設定へ */
public function init():void
{
var j:int, i:int, c:int;

for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
if (nanpleTable[i][j]) {
// テーブルから確定している数を設定
nanpleWork[i][j].hitno = nanpleTable[i][j];
} else {
// その位置の空き情報を初期化
nanpleWork[i][j].hitno = 0;
}
for (c = 1; c <= 9; c++) {
nanpleWork[i][j].checknolist[c] = 0;
}
}
}
}

/* -------------------------------------------------------- */
/* 現在見ている地点を基準にして,盤面のうち,縦,横,3×3の
すべてで確定しているものを全部得る */
public function item_set_checkno_fromareahitno(j:int, i:int):void
{
// 縦方向の確定しているものを設定
set_checkno_fromareahitno(0, j, 1, 9,
nanpleWork[i][j].checknolist);

// 横方向の確定しているものを設定
set_checkno_fromareahitno(i, 0, 9, 1,
nanpleWork[i][j].checknolist);

// 3x3のマス目で確定しているものを設定
set_checkno_fromareahitno(int(i / 3) * 3, int(j / 3) * 3, 3, 3,
nanpleWork[i][j].checknolist);
}

/* -------------------------------------------------------- */
/* 指定された領域にある確定した数を配列nolistに設定する */
/*
top: 探し始める縦の位置
left: 探し始める横の位置
width: 探す横方向の回数
height: 探す縦方向の回数
nolist: 候補の数を収める配列
*/
public function set_checkno_fromareahitno(top:int, left:int, width:int, height:int, nolist:Array):void
{
var j:int, i:int, c:int;

for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
if (nanpleWork[top + i][left + j].hitno) {
c = nanpleWork[top + i][left + j].hitno;
nolist[c] = 1;
}
}
}
}

// 現在見ている地点を基準にして,それぞれの方向に候補となっている数を得る
public function item_set_hitno_fromareacheckno(j:int, i:int):void
{
var result:int, c:int;

for (c = 1; c <= 9; c++) {
if (nanpleWork[i][j].checknolist[c] == 0) { // そのマスの候補が確定していないなら

// 縦方向の数の候補を得て確定できるか確認
set_hitno_fromareacheckno(nanpleWork[i][j], 0, j, 1, 9, c);

// 横方向の数の候補を得て確定できるか確認
set_hitno_fromareacheckno(nanpleWork[i][j], i, 0, 9, 1, c);

// 3x3領域のマス目で候補を得て確定できるか確認
set_hitno_fromareacheckno(nanpleWork[i][j], int(i / 3) * 3, int(j / 3) * 3, 3, 3, c);
}
}
}

// 指定された領域にある数の候補と比較して数を確定する
/*
item: 現在見ているマス
top: 探し始める縦の位置
left: 探し始める横の位置
width: 探す横方向の回数
height: 探す縦方向の回数
nolist: 候補の数を収めた配列
*/
public function set_hitno_fromareacheckno(item:t_nanpleItem, top:int, left:int, width:int, height:int, no:int):void
{
var j:int, i:int, hitcount:int;

// すでに値が確定していたのなら処理しない
if (item.hitno != 0)
return;
hitcount = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
if ((nanpleWork[top + i][left + j].hitno) ||
(nanpleWork[top + i][left + j].checknolist[no] != 0)) {
hitcount++;
}
}
}
// 8箇所当たっていたのなら値を確定する
if (hitcount == 8) {
item.hitno = no;
}
}

/* 現在見ている地点の数の候補を確定できるか確認 */
public function item_check_checknolist(j:int, i:int):int
{
var c:int, nocount:int, hitno:int;

// すでに確定していた
if (nanpleWork[i][j].hitno)
return 0;

// 候補の数を数える
nocount = 0;
for (c = 1; c <= 9; c++) {
if (nanpleWork[i][j].checknolist[c] == 0) {
nocount++;
hitno = c;
}
}

// 候補が1つだけになったら値を確定
if (nocount == 1) {
nanpleWork[i][j].hitno = hitno;
trace("x=" + j + " " + "y=" + i + "に" + hitno + "が確定しました。");
return 1;
}
return 0;
}

}

}


t_nanpleItem.as
package  
{
/**
* 作業用テーブル
*/
public class t_nanpleItem
{
public var hitno:int; /* 確定した数 */
public var checknolist:Array = new Array(9 + 1); /* 数の候補:要素が0なら可能性がある数 */

public function t_nanpleItem()
{

}

}

}