import java.applet.*;
import java.awt.*;
//---------------------------------------------------------
// 倉庫番を解く(Ver2.7) written by Kenichiro Takahashi
// http://www.ic-net.or.jp/home/takaken
// (AppletSize width=400 height=364)
//---------------------------------------------------------
public class soko207 extends Applet implements Runnable {
final int X_MAX = 12; // 横のサイズ
final int Y_MAX = 10; // 縦のサイズ
final int K_MAX = 9; // 荷物の最大個数
final int B_SIZE = 109987; // バケットサイズ
final int Q_SIZE = 100000; // キューサイズ
final int R_HASH = 491; // 再ハッシュ増分
final int AREA = X_MAX*Y_MAX; // マップの面積
final int DD = 30; // 単位長さ
final int diff[] = {-1,X_MAX,1,-X_MAX}; // 方向ベクトル
boolean imgloaded = false; // 画像読込完了
Graphics grf; // 画面定義
Image item[] = new Image[9]; // gif画像
Thread animation = null; // アニメスレッド
int IDX; // アニメポインタ
boolean animFlag = false; // アニメモード
boolean editFlag = true; // 編集モード
int parts = 4; // 選択部品番号
int ansMsg = 0; // 探索結果コード
int thinkBar = 0; // 進行状況表示
int disp_map[] = new int[AREA]; // 表示マップ
int edit_map[] = new int[AREA]; // 編集マップ
//------ 以下、電子頭脳の作業用 ------------------
byte BACKET[][] = new byte[B_SIZE][K_MAX+1]; // 1,099,870 byte
int LINK[] = new int[B_SIZE]; // 439,948 byte
byte OPTN[] = new byte[B_SIZE]; // 109,987 byte
int QUEUE[] = new int[Q_SIZE]; // 400,000 byte
// BACKET:局面の保存(荷物の位置と人の自由行動域先頭)
// LINK :どのパターンから派生したかリンク元アドレス
// OPTN :0:未定義 1:通常探索 2:逆解き探索 3,5:凍結しない局所パターン 4,6:凍結する局所パターン
// QUEUE :幅優先探索用キュー(通常探索は0から,逆解き探索はQ_SIZE-1から逆へ)
int Qtop1, Qend1, Qadd1, Qlen1; // 通常探索用キューの各ポインタ
int Qtop2, Qend2, Qadd2, Qlen2; // 逆解き探索用キューの各ポインタ
int chan, kara; // 通常探索と逆解き探索の衝突部連結
int backetCnt, kosu, sift, bbun;
int push, tesu, posS;
byte main_map[] = new byte[AREA]; // 探索メインマップ 1:壁 2:荷物
byte wall_map[] = new byte[AREA]; // 壁マップ 1:壁
byte dead_map[] = new byte[AREA]; // デッドゾーン 1:デッド
byte goal_map[] = new byte[AREA]; // ゴールマップ 1:格納地点
byte pack_map[] = new byte[AREA]; // 開始荷マップ 1:開始時荷物
byte work_map[] = new byte[AREA]; // 各種作業マップ
byte hstb[] = new byte[K_MAX+1]; // 局面の圧縮データ(BACKET登録用)
//---------------------------------------------------------
// 初期処理
//---------------------------------------------------------
public void init() {
setBackground(Color.gray);
/* ボタン配置 */
setLayout(new BorderLayout());
Panel psouth = new Panel();
psouth.add(new Button("CLEAR"));
psouth.add(new Button("RESET"));
psouth.add(new Button("START"));
add("South", psouth);
/* エディットマップ初期化 */
initMap();
}
public void initMap() { // 周辺を壁にする
for (int i=0; i<AREA; i++)
disp_map[i]=edit_map[i]=4;
for (int y=1; y<Y_MAX-1; y++)
for (int x=1; x<X_MAX-1; x++)
disp_map[y*X_MAX+x] = edit_map[y*X_MAX+x] = 0;
}
public void resetMap() { // 編集マップを表示マップへ
for (int i=0; i<AREA; i++)
disp_map[i] = edit_map[i];
}
//---------------------------------------------------------
// アニメーション処理
//---------------------------------------------------------
public void start() {
if (animation == null) {
animation = new Thread(this);
animation.start();
}
}
public void stop() {
if (animation != null) {
animation.stop();
animation = null;
}
}
public void run() {
if (!imgloaded) {
grf = getGraphics();
repaint();
/* gif画像ロード */
MediaTracker tracker = new MediaTracker(this);
for (int i=0; i<9; i++) {
item[i] = getImage(getCodeBase(),"item"+i+".gif");
tracker.addImage(item[i],0);
}
try {
tracker.waitForAll(0);
imgloaded = !tracker.isErrorAny();
} catch (InterruptedException e) {}
if (!imgloaded) {
stop();
grf.drawString("Image Load Error!", 10, 40);
return;
}
}
repaint();
while (true) {
try {
if (animFlag) {
int pAv = QUEUE[IDX++]; // キューをアニメ進行に併用
if (pAv < 0) animFlag=false;
else Moving(pAv,grf); // 次のシーンを表示
}
animation.sleep(300);
} catch (InterruptedException e) { stop(); }
}
}
public void Moving(int pAv, Graphics g) {
int posa, posb, posc, vect;
vect = pAv % 10; pAv /= 10; // 人の向き
posb = pAv % 1000; pAv /= 1000; // 移動先
posa = pAv; // 移動元
posc = posb + (posb - posa); // 移動先の先
disp_map[posa] = goal_map[posa]; // 移動元の人を消す
drawParts(posa,g);
if (disp_map[posb] > 1) { // 移動先に荷物があれば
disp_map[posc] += 2; // その先に荷物を表示
drawParts(posc,g);
push++; // 荷押回数カウントアップ
}
disp_map[posb] = vect+5; // 移動先に人を表示
drawParts(posb,g);
drawMsg(g); // 荷押回数表示
}
//---------------------------------------------------------
// 画面の表示
//---------------------------------------------------------
public void update(Graphics g) { // ちらつき防止処理
paint(g);
}
public void paint(Graphics g) { // アプレット全体表示
if (!imgloaded) {
g.drawString("Now Image Loading...", 10, 20);
} else {
for (int posi=0; posi<AREA; posi++) // マップ全体
drawParts(posi, g);
for (int i=0; i<6; i++) // パーツリスト
g.drawImage(item[i],X_MAX*DD+6,i*(DD+6)+15,this);
drawSelect(parts,Color.red,g); // 選択パーツ□印
drawBar(g); // 探索進行バー
drawMsg(g); // メッセージ
}
}
public void drawParts(int posi, Graphics g) { // マップ内posi地点の表示
int x, y, d;
x = posi % X_MAX;
y = posi / X_MAX;
d = disp_map[posi];
g.drawImage(item[d],x*DD,y*DD,this);
}
public void drawSelect(int p, Color c, Graphics g) { // 選択パーツ□印
g.setColor(c);
g.drawRect(X_MAX*DD+3,p*(DD+6)+12,DD+5,DD+5);
g.drawRect(X_MAX*DD+4,p*(DD+6)+13,DD+3,DD+3);
}
public void drawBar(Graphics g) { // 探索進行バー
g.setColor(Color.white);
g.fillRect(0,Y_MAX*DD+1,(X_MAX+1)*DD+10,10);
g.setColor(Color.red);
for (int i=1; i<=thinkBar; i++)
g.fillRect((i-1)*20+1,Y_MAX*DD+1,18,10);
}
public void drawMsg(Graphics g) { // メッセージ
g.setColor(Color.white);
g.fillRect(0,Y_MAX*DD+11,(X_MAX+1)*DD+10,23);
g.setFont(new Font("Helvetica",Font.PLAIN,14));
g.setColor(Color.black);
switch (ansMsg) {
case 1: g.drawString("Too many packages",DD,Y_MAX*DD+26); break;
case 2: g.drawString("Strange mapping", DD,Y_MAX*DD+26); break;
case 3: g.drawString("Impossible !", DD,Y_MAX*DD+26); break;
case 4: g.drawString("Give up !", DD,Y_MAX*DD+26); break;
case 5: g.drawString("Now thinking", DD,Y_MAX*DD+26); break;
case 6: g.drawString("Push Count "+Integer.toString(push)+" / "+
Integer.toString(tesu),DD,Y_MAX*DD+26);
}
}
//---------------------------------------------------------
// マウスイベント
//---------------------------------------------------------
public boolean mouseDown(Event e, int x, int y) {
if (animFlag == false) {
if (editFlag == false) { // 解答アニメ終了直後ならRESET
resetMap();
ansMsg = thinkBar = 0;
repaint();
editFlag = true;
}
int ex = x / DD;
int ey = y / DD;
if (ex>0 && ex<(X_MAX-1) && ey>0 && ey<(Y_MAX-1)) { // 編集マップ部
disp_map[ey*X_MAX+ex] = edit_map[ey*X_MAX+ex] = parts;
drawParts(ey*X_MAX+ex,grf);
} else if (x > X_MAX*DD) {
int d = (y - 15) / (DD+6);
if (d>=0 && d<=5 && d!=parts) { // 選択パーツ部
drawSelect(parts,Color.gray,grf);
parts = d;
drawSelect(parts,Color.red ,grf);
}
}
}
return true;
}
public boolean action(Event e, Object arg) {
if (e.target instanceof Button) {
animFlag =false;
if ("CLEAR".equals(arg)) { // CLEARボタン
initMap();
ansMsg = thinkBar = 0;
repaint();
editFlag = true;
} else
if ("RESET".equals(arg)) { // RESETボタン
resetMap();
ansMsg = thinkBar = 0;
repaint();
editFlag = true;
} else
if ("START".equals(arg)) { // STARTボタン
if (editFlag == false) return false; // 2度押し防止
ansMsg = 5; // Now thinking 表示
drawMsg(grf);
editFlag = false;
computer(); // 電子頭脳の起動
drawMsg(grf);
if (ansMsg == 6) { // 解を発見した
IDX=0;
animFlag=true; // 解答アニメ開始
}
}
}
return true;
}
//---------------------------------------------------------
// 以下、電子頭脳
//---------------------------------------------------------
//*********************************************************
//* アクティブゾーン(荷を押さずに自由行動可能域)調査 *
//*********************************************************
byte h1map[] = new byte[AREA]; // 本探索 /荷押前
byte h2map[] = new byte[AREA]; // 本探索 /荷押後
byte b1map[] = new byte[AREA]; // 局所探索/荷押前
byte b2map[] = new byte[AREA]; // 局所探索/荷押後
int ac_top; // アクティブゾーンの先頭
int ac_cnt; // アクティブゾーンの面積
/* (副関数)アクティブゾーンを再帰でposhから波状に調べる */
void active_zone_sub(byte actv_map[], int posh) {
int posi, vect;
actv_map[posh]=1;
ac_cnt++; // 面積更新
if (posh < ac_top) ac_top=posh; // 先頭位置の更新
for (vect=0; vect<4; vect++) {
posi = posh + diff[vect];
if (main_map[posi]==0 && actv_map[posi]==0)
active_zone_sub(actv_map,posi);
}
}
/* (主関数)アクティブゾーンをposhから調べactv_map[]に記録 */
int active_zone(byte actv_map[], int posh) {
int i;
ac_cnt=0;
ac_top=AREA;
for (i=X_MAX+1; i<AREA-X_MAX-1; i++) actv_map[i]=0;
active_zone_sub(actv_map,posh);
return ac_top; // 先頭位置を返す
}
//*********************************************************
//* デッドゾーン(進入禁止域調査) *
//*********************************************************
/* (副関数)荷物を置ける位置posiから再帰で波状に調べる */
void dead_zone_sub(int posi) {
int posj, posk, vect;
dead_map[posi]=0;
for (vect=0; vect<4; vect++) {
posj = posi + diff[vect];
posk = posj + diff[vect];
if (dead_map[posj]==1 && wall_map[posj]==0 && wall_map[posk]==0)
dead_zone_sub(posj); // 荷物を引っ張れるなら
}
}
/* (主関数)荷物の進入可能位置を格納地点から調べる */
void dead_zone() { // 0:進入可能 1:進入禁止
int i;
for (i=0; i<AREA; i++) dead_map[i]=1;
for (i=0; i<AREA; i++) // 格納地点から調査
if (goal_map[i]==1 && dead_map[i]==1) dead_zone_sub(i);
}
//*********************************************************
//* フリーズチェック(凍結検査) *
//*********************************************************
int Fflag; // 特例フラグ(凍結でも関連荷物総てが格納地点ならOK)
/* (副関数)vectの直角方向にpospの荷物を移動可能か */
int freeze_check_sub(int posp, int vect) { // 返り値= 0:移動可 1:移動不可
int pos1, pos2, retn=0;
if (goal_map[posp] == 0) Fflag=1; // 特例権利の喪失
vect = (vect + 1) % 2; // 方向を直角方向へ変換
pos1 = posp - diff[vect];
pos2 = posp + diff[vect];
if (main_map[pos1]==1 || main_map[pos2]==1) return 1; // どちらか壁
if (dead_map[pos1]==1 && dead_map[pos2]==1) return 1; // どちらもデッド
main_map[posp] = 1; // 堂々巡り防止の為荷物を一端壁にする
if (main_map[pos1]==2 && freeze_check_sub(pos1,vect)==1) retn=1;
else
if (main_map[pos2]==2 && freeze_check_sub(pos2,vect)==1) retn=1;
main_map[posp] = 2; // 荷物に戻す
return retn;
}
/* (主関数)pospの荷物は凍結しているか */
int freeze_check(int posp) { // 返り値= 0:凍結してない 1:凍結している
Fflag = 0;
if (freeze_check_sub(posp,0) == 0) return 0; // 縦方向へ移動可能か
if (freeze_check_sub(posp,1) == 0) return 0; // 横方向へ移動可能か
return Fflag;
}
//*********************************************************
//* 局所探索(閉空間を形成している荷物だけのミニ探索) *
//*********************************************************
byte taih_map[] = new byte[AREA]; // 本探索マップの退避
int BQtop, BQend; // 局所探索用キューポインタ
int Bkosu, Bsift, ALL_SP;
int Btb[] = new int[K_MAX];
//----------------------------------------
// 局所荷物(閉空間を形成している荷物)抽出
//----------------------------------------
/* 閉空間位置poshを塗りつぶしながら再帰で波状に調べる */
int get_packs_sub(int posh) {
int posi, vect;
work_map[posh]=1;
for (vect=0; vect<4; vect++) {
posi = posh + diff[vect];
if (work_map[posi] == 0) {
if (main_map[posi] == 0) { // 空間の場合
if (get_packs_sub(posi) == 1) return 1;
} else if (main_map[posi] == 2) { // 荷物の場合
work_map[posi]=1; // 2度抽出しないように
Btb[Bkosu++] = posi; // 荷物の位置を記録
if (Bkosu == bbun+1) return 1; // 多すぎ中止
}
}
}
return 0;
}
/* (主関数)poshに属する閉空間に隣接する荷物を抽出する */
int get_packs(int posh) {
int i;
Bkosu=0;
for (i=X_MAX+1; i<AREA-X_MAX-1; i++) work_map[i]=0; // 作業域初期化
return get_packs_sub(posh);
}
//----------------------------------------
// ハッシュ(局所探索用)
//----------------------------------------
int Bhash_func(int post, int muk) {
int i, j, hash, retn;
int data=0;
/* データ圧縮 */
for (i=j=0; j<Bkosu; i++)
if (main_map[i] == 2) hstb[j++]=(byte)i;
hstb[j++]=(byte)post;
while (j <= kosu) hstb[j++]=0;
/* 全ゴール */
if (muk == 1) {
for (i=0; i<Bkosu; i++)
if (goal_map[hstb[i]] != 1) break;
if (i == Bkosu) return 3; // 3:全ゴールならOK
} else {
for (i=0; i<Bkosu; i++)
if (pack_map[hstb[i]] != 1) break;
if (i == Bkosu) return 5; // 5:全ゴールならOK
}
/* ハッシュ値を求める */
for (i=Bkosu; i>=0; i--)
data = (data << Bsift) + hstb[i];
if (data < 0) data *= -1;
hash = (int)(data % B_SIZE);
/* バケット内を探す */
for (;;) {
if (BACKET[hash][0] == 0) break;
for (i=0; i<=kosu; i++)
if (BACKET[hash][i] != hstb[i]) break;
if (i > kosu) {
if ((retn = OPTN[hash]) == 0) return 0; // 0:続行
if ((retn>>2) == muk-1) return retn; // 3,5:OK 4,6:NO
}
hash = (hash + R_HASH) % B_SIZE;
}
/* バケットに記録 */
for (i=0; i<=kosu; i++)
BACKET[hash][i]=hstb[i];
QUEUE[BQend++]=hash;
if (BQend-Qadd1>1000) return (muk==1)? 3: 5; // 3,5:打切りOK
return 0; // 0:続行
}
//----------------------------------------
// 幅優先探索(局所探索用)
//----------------------------------------
int btb[] = new int[K_MAX];
int Bsearch(int all_space, int muk) {
int i, adr, posp, posi, posj, pack, vect, post;
while (BQtop < BQend) {
adr=QUEUE[BQtop++];
for (i=0; i<Bkosu; i++)
main_map[btb[i]=BACKET[adr][i]]=2;
active_zone(b1map,BACKET[adr][Bkosu]);
for (pack=0; pack<Bkosu; pack++) {
posp = btb[pack]; // 荷物の位置
for (vect=0; vect<4; vect++) {
posi = posp + diff[vect]; // 荷物の手前
if (b1map[posi] != 1) continue;
if (muk == 1) {
posj = posp - diff[vect]; // 荷物の先
if (main_map[posj]==0 && dead_map[posj]==0) {
main_map[posj]=2;
main_map[posp]=0;
if (freeze_check(posj) == 0) {
post = active_zone(b2map,posp);
if (ac_cnt == all_space) return 3; // 3:OK(閉空間で無くなった)
if (Bhash_func(post,muk) == 3) return 3; // 3:OK(全ゴールor過去の記録より)
}
main_map[posj]=0;
main_map[posp]=2;
}
} else {
posj = posi + diff[vect]; // 荷物の前の前
if (main_map[posj] == 0) {
main_map[posp]=0;
main_map[posi]=2;
post = active_zone(b2map,posj);
if (ac_cnt == all_space) return 5; // 5:OK(閉空間で無くなった)
if (Bhash_func(post,muk) == 5) return 5; // 5:OK(全ゴールor過去の記録より)
main_map[posp]=2;
main_map[posi]=0;
}
}
}
}
for (i=0; i<Bkosu; i++) main_map[btb[i]]=0;
}
return (muk == 1)? 4: 6; // 4,6:NO(凍結する)
}
//----------------------------------------
// 局所探索主処理(0:凍結しない 1:凍結する)
//----------------------------------------
int check1(int posp, int posh, int muk) {
int i, vect, posi=0, post, retn;
/* pospの荷物が閉空間に接しているか? */
for (vect=0; vect<4; vect++) {
posi = posp + diff[vect];
if (main_map[posi]==0 && h2map[posi]==0) break;
}
if (vect == 4) return 0;
if (muk == 1) {
if (get_packs(posi) == 1) return 0; // 局所荷物を抽出(多すぎの場合中止)
} else {
if (get_packs(posh) == 1) return 0; // 局所荷物を抽出(多すぎの場合中止)
}
/* 本探索マップの退避と局所みにマップ作成 */
for (i=X_MAX+1; i<AREA-X_MAX-1; i++) {
taih_map[i]=main_map[i]; main_map[i]=wall_map[i];
}
for (i=0; i<Bkosu; i++) main_map[Btb[i]]=2;
BQtop = BQend = Qadd1;
Bsift = 24 / Bkosu;
post = active_zone(b1map,posh);
retn = Bhash_func(post,muk); // 0でない場合は過去の記録より即決
// 3:凍結しない 4:凍結する
if (retn == 0) {
/* 探索処理 */
for (i=0; i<Bkosu; i++) main_map[Btb[i]]=0;
retn = Bsearch(ALL_SP - Bkosu,muk); // 引数=閉空間が解放された場合の空間面積
/* 結果の書き込み */
OPTN[QUEUE[Qadd1]]=(byte)retn; // 3,5:OK 4,6:NO
for (i=Qadd1+1; i<BQend; i++) // 作業に使用したバケット消去
BACKET[QUEUE[i]][0]=0;
if ((++backetCnt)%5000 == 0) { // 探索進行バー
thinkBar++; drawBar(grf);
}
}
/* 本探索マップ復元 */
for (i=X_MAX+1; i<AREA-X_MAX-1; i++)
main_map[i]=taih_map[i];
return (retn==3 || retn==5)? 0: 1;
}
//*********************************************************
//* 本探索 *
//*********************************************************
//----------------------------------------
// ハッシュ法(本探索用)
//----------------------------------------
int hash_func(int post, int adr, int muk) {
int i, j, hash, data=0;
/* 局面圧縮 */
for (i=j=0; j<kosu; i++)
if (main_map[i] == 2) hstb[j++]=(byte)i;
hstb[kosu]=(byte)post;
/* ハッシュ値を求める */
for (i=kosu; i>=0; i--)
data = (data << sift) + hstb[i];
hash = data % B_SIZE;
/* バケット内を探す */
for (;;) {
if (BACKET[hash][0] == 0) break;
for (i=0; i<=kosu; i++)
if (BACKET[hash][i] != hstb[i]) break;
if (i > kosu) {
if (OPTN[hash] == muk) return -1; // 同形あり/探索続行
chan=hash; kara=adr; return 0; // 衝突地点発見
}
hash = (hash + R_HASH) % B_SIZE;
}
/* 新規パターン記録 */
for (i=0; i<=kosu; i++)
BACKET[hash][i]=hstb[i];
LINK[hash]=adr; // リンク元
OPTN[hash]=(byte)muk; // 探索方向
if (muk == 1) QUEUE[Qadd1++]=hash;
else QUEUE[Qadd2--]=hash;
if ((++backetCnt)%5000 == 0) { // 探索進行バー
thinkBar++; drawBar(grf);
}
if (backetCnt >= Q_SIZE) return 4; // 不足
return -1; // 探索続行
}
//----------------------------------------
// 幅優先探索(本探索用)
//----------------------------------------
int postb[] = new int[K_MAX];
/* 通常探索 */
int search1() {
int i, adr, posp, posi, posj, post, pack, vect;
while (Qtop1 < Qend1) {
adr=QUEUE[Qtop1++];
for (i=0; i<kosu; i++)
main_map[postb[i]=BACKET[adr][i]]=2;
active_zone(h1map,BACKET[adr][kosu]);
for (pack=0; pack<kosu; pack++) {
posp = postb[pack]; // 荷物の位置
for (vect=0; vect<4; vect++) {
posi = posp + diff[vect]; // 荷物の手前
if (h1map[posi] != 1) continue;
posj = posp - diff[vect]; // 荷物の先
if (main_map[posj]==0 && dead_map[posj]==0) {
main_map[posj]=2;
main_map[posp]=0;
if (freeze_check(posj) == 0) { // フリーズチェック
post = active_zone(h2map,posp);
if (check1(posj,posp,1) == 0) // 局所探索
if ((i=hash_func(post,adr,1)) >= 0) return i;
}
main_map[posj]=0;
main_map[posp]=2;
}
}
}
for (i=0; i<kosu; i++) main_map[postb[i]]=0;
}
Qlen1 = Qadd1 - Qend1;
Qtop1 = Qend1;
Qend1 = Qadd1;
if (Qlen1 == 0) return 3; // 解が無かった
return -1; // 探索続行
}
/* 逆解き探索 */
int search2() {
int i, adr, posp, posi, posj, post, pack, vect;
while (Qend2 < Qtop2) {
adr=QUEUE[Qtop2--];
for (i=0; i<kosu; i++)
main_map[postb[i]=BACKET[adr][i]]=2;
active_zone(h1map,BACKET[adr][kosu]);
for (pack=0; pack<kosu; pack++) {
posp = postb[pack]; // 荷物の位置
for (vect=0; vect<4; vect++) {
posi = posp + diff[vect]; // 荷物の手前
if (h1map[posi] != 1) continue;
posj = posi + diff[vect]; // 荷物の前の前
if (h1map[posj] == 1) {
main_map[posp]=0;
main_map[posi]=2;
post = active_zone(h2map,posj);
if (check1(posi,posj,2) == 0) // 局所探索
if ((i=hash_func(post,adr,2)) >= 0) return i;
main_map[posp]=2;
main_map[posi]=0;
}
}
}
for (i=0; i<kosu; i++) main_map[postb[i]]=0;
}
Qlen2 = Qend2 - Qadd2;
Qtop2 = Qend2;
Qend2 = Qadd2;
if (Qlen2 == 0) return 3; // 解が無かった
return -1; // 探索続行
}
//***************************************
//* 倉庫番を解く *
//***************************************
int puzzle() {
int i, j, k, posh=0, retn;
/* 編集マップ読み取り */
for (i=j=k=kosu=0; i<AREA; i++) {
switch (edit_map[i]) {
case 0: wall_map[i]=0; goal_map[i]=0; pack_map[i]=0; main_map[i]=0; break;
case 1: wall_map[i]=0; goal_map[i]=1; pack_map[i]=0; main_map[i]=0; k++; break;
case 2: wall_map[i]=0; goal_map[i]=0; pack_map[i]=1; main_map[i]=2; kosu++; break;
case 3: wall_map[i]=0; goal_map[i]=1; pack_map[i]=1; main_map[i]=2; kosu++; k++; break;
case 4: wall_map[i]=1; goal_map[i]=0; pack_map[i]=0; main_map[i]=1; break;
case 5: wall_map[i]=0; goal_map[i]=0; pack_map[i]=0; main_map[i]=0; posS=i; j++; break;
}
}
if (k==0 || k!=kosu || j!=1) return 2; // 2:マップが異常/
if (kosu > K_MAX) return 1; // 1:荷物が多すぎ/
/* 作業領域初期化 */
for (i=0; i<B_SIZE; i++) BACKET[i][0]=0;
Qtop1 = Qend1 = Qadd1 = 0;
Qtop2 = Qend2 = Qadd2 = Q_SIZE-1;
backetCnt = 0;
sift = 24 / kosu;
bbun = kosu / 2;
if (bbun < 2) bbun=0;
if (bbun > 6) bbun=6;
/* ダメを詰める(3方が壁に囲まれたゴールも無く人もいない空間をつぶす) */
k=1;
while (k == 1) {
k=0;
for (posh=0; posh<AREA; posh++) {
if (main_map[posh]==0 && goal_map[posh]==0 && posh!=posS) {
for (i=j=0; i<4; i++)
if (wall_map[posh+diff[i]]==1) j++;
if (j > 2) { wall_map[posh]=main_map[posh]=1; k=1; }
}
}
}
/* 開始型登録 */
posh = active_zone(h1map,posS);
hash_func(posh,-1,1);
for (i=0; i<AREA; i++) main_map[i]=wall_map[i];
Qlen1 = Qadd1 - Qend1;
Qtop1 = Qend1;
Qend1 = Qadd1;
/* 完了型登録(人の位置により複数ある場合がある) */
active_zone(h1map,posh);
ALL_SP = ac_cnt;
for (i=0; i<AREA; i++)
if (goal_map[i] == 1) main_map[i]=2;
for (i=0; i<AREA; i++) h2map[i]=0;
for (i=0; i<AREA; i++) {
if (main_map[i]==0 && h1map[i]==1 && h2map[i]==0) {
active_zone(h2map,i);
for (j=0; h2map[j]==0; j++);
if (j == i)
if (hash_func(i,-1,2) == 0) return 0; // 初めから完成
}
}
for (i=0; i<AREA; i++) main_map[i]=wall_map[i];
Qlen2 = Qend2 - Qadd2;
Qtop2 = Qend2;
Qend2 = Qadd2;
/* デッドゾーン調査 */
dead_zone();
/* 間口幅調整式逆解き挟みうち法 */
do {
if (Qlen1 < Qlen2) retn=search1(); // 通常探索
else retn=search2(); // 逆解き探索
} while (retn == -1);
return retn;
}
//***************************************
//* javaGUIと電子頭脳のインターフェース *
//***************************************
/* 2地点間の最短ルートを見つける為の歩数マップを作る */
void root(int pos1, byte step) {
int pos2, vect;
work_map[pos1]=step++;
for (vect=0; vect<4; vect++) {
pos2 = pos1 + diff[vect];
if (main_map[pos2]==0 && work_map[pos2]>step)
root(pos2,step);
}
}
void computer() {
int ret, next, prev, idx, adr, i, vect, step;
int pos0, pos1=0, pos2=0, posh=0, posa, posb=0;
thinkBar = push = 0;
ret = puzzle();
if (ret == 0) {
/* リンクポインタを解答手順向きに統一する */
if (OPTN[chan] == 1) {
next=kara; adr=chan;
} else {
next=chan; adr=kara;
}
for ( ; adr>=0; adr=prev) {
prev=LINK[adr]; LINK[adr]=next; next=adr;
}
/* 解答アニメ用データを作る */
/* QUEUE[]をアニメ用データに併用 */
/* main_map[]を荷を押す前の局面に使用 */
/* dead_map[]を荷を押した後の局面に併用 */
adr=QUEUE[0];
for (i=0; i<AREA; i++) main_map[i]=wall_map[i];
for (i=0; i<kosu; i++) main_map[BACKET[adr][i]] = 2;
posh = posS; // 最初の人の位置
idx=0;
/* リンクポインタを辿る */
for (adr=LINK[adr],tesu=0; adr>=0; adr=LINK[adr],tesu++) {
for (i=0; i<AREA; i++) dead_map[i]=wall_map[i];
for (i=0; i<kosu; i++) dead_map[BACKET[adr][i]] = 2;
for (i=0; i<AREA; i++) {
if (main_map[i]==2 && dead_map[i]==0) pos1=i; // 押す前の位置
if (main_map[i]==0 && dead_map[i]==2) pos2=i; // 押した後の位置
work_map[i] = (byte)AREA;
}
pos0 = pos1 - ( pos2 - pos1); // 押す前の人の位置
root(pos0,(byte)1); // 歩数マップを作る
work_map[pos1]=0;
/* 歩数マップを見ながら最短ルートを歩く */
for (posa=posh,step=work_map[posh]-1; step>=0; posa=posb,step--) {
for (vect=0; vect<4; vect++) {
posb = posa + diff[vect];
if (work_map[posb] == step) break;
}
QUEUE[idx++] = posa*10000 + posb*10 + vect; // 登録
}
/* 次の局面変化の為の準備 */
for (i=0; i<AREA; i++)
main_map[i]=dead_map[i];
posh=pos1;
}
QUEUE[idx]=-1; // 終端を(-1)で閉じる
ansMsg=6;
} else {
ansMsg=ret;
}
}
}