ホームに戻る
総当り式さめがめ自動解法検索
#include <stdio.h>
/*
さめがめを総当りによって自動で解くプログラムです。
ステージの横幅と縦幅を設定して、
stage_data の配列にコマの状態をセットしてください。
コマの種類は KOMA_1 〜 KOMA_5 の最大5種類までとなっています。
なおこのアルゴリズムでは 20×12 のステージなどの場合、
解法を導き出すまでに10時間超の時間を要する場合があり、
その場合ステージを分割する等のアルゴリムの変更が望まれます。
*/
#define STAGE_WIDTH 6
#define STAGE_HEIGHT 10
/*
6*10 のステージの場合のメモリ状態の模式図です。
K はコマが置かれている部分 0 は空白です
P はステージの先頭ポインタ位置
E は P からのステージサイズの終端です
探索は P から E まで行います。
0000000
PKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKK0
KKKKKKE
000000
*/
#define SPACE 0
#define KOMA_1 (1 << 0)
#define KOMA_2 (1 << 1)
#define KOMA_3 (1 << 2)
#define KOMA_4 (1 << 3)
#define KOMA_5 (1 << 4)
#define KOMA_ALL (KOMA_1 | KOMA_2 | KOMA_3 | KOMA_4 | KOMA_5)
#define KOMA_TAKEN (1 << 5)
#define LEFT (-1)
#define RIGHT (1)
#define UP (-STAGE_WIDTH-1)
#define DOWN (STAGE_WIDTH+1)
#define LIST_SIZE (KOMA_5 + 1)
#define STAGE_SIZE ((STAGE_WIDTH*STAGE_HEIGHT)+STAGE_HEIGHT-1)
#define MEMORY_SIZE ((STAGE_WIDTH*(STAGE_HEIGHT+2))+STAGE_HEIGHT+1)
typedef char stage;
static stage stage_data[STAGE_WIDTH * STAGE_HEIGHT] = {
KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_2,KOMA_4
,KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_4,KOMA_1
,KOMA_2,KOMA_1,KOMA_1,KOMA_3,KOMA_4,KOMA_2
,KOMA_5,KOMA_1,KOMA_4,KOMA_3,KOMA_4,KOMA_2
,KOMA_1,KOMA_3,KOMA_4,KOMA_1,KOMA_1,KOMA_1
,KOMA_2,KOMA_3,KOMA_1,KOMA_1,KOMA_1,KOMA_2
,KOMA_2,KOMA_1,KOMA_1,KOMA_3,KOMA_2,KOMA_2
,KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_1
,KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_1,KOMA_5
,KOMA_3,KOMA_3,KOMA_1,KOMA_1,KOMA_2,KOMA_2
};
// 残りコマ数を記録するリスト
static int first_list[LIST_SIZE]; // 初期状態のリスト
static int now_list[LIST_SIZE]; // 現在の状態のリスト
// コマが配置されるステージ
static stage first_stage[MEMORY_SIZE]; // 初期状態のステージ
static stage now_stage[MEMORY_SIZE]; // 現在のステージ
// ステージアクセス用の先頭ポインタ
static stage *pfirst_stage = &first_stage[STAGE_WIDTH + 1];
static stage *pnow_stage = &now_stage[STAGE_WIDTH + 1];
void initStage(stage *sd);
void resetStage();
int takeKoma(int index);
void printList();
void printStage();
static void clearList(int num);
static inline void addList(stage koma);
static inline void subList(stage koma);
static inline int getListTotal();
static void clearStage(stage *pstage, int num);
static inline stage getKoma(int index);
static inline int cantTakeKoma(int index);
static inline void checkRoundKoma(int index);
static inline void downKoma(int index, int d);
static inline void downSlideKoma(int index);
static inline void leftKoma(int index, int d);
static inline void leftSlideKoma(int index, int d);
// 初期状態、現在のリストを num でクリア
void clearList(int num){
int i;
for(i = 0; i < LIST_SIZE; i++){
first_list[i] = num;
now_list[i] = num;
}
}
// 現在のリストにおいて koma について1を足す
inline void addList(stage koma){
first_list[koma]++;
return;
}
// 現在のリストにおいて koma について1を引く
inline void subList(stage koma){
now_list[koma]--;
return;
}
// 現在の全コマ数を返す
inline int getListTotal(){
return (now_list[KOMA_1] + now_list[KOMA_2] + now_list[KOMA_3] + now_list[KOMA_4] + now_list[KOMA_5]);
}
// ステージの全メモリ領域を num で埋める
void clearStage(stage *pstage, int num){
int i;
for(i = 0; i < MEMORY_SIZE; i++){
pstage[i] = num;
}
return;
}
// 初期状態の設定 resetStage で現在の状態へのコピーをしている
void initStage(stage *sd){
int i, t;
int index;
clearList(0);
clearStage(first_stage, 0);
clearStage(now_stage, 0);
for(t = 0; t < STAGE_HEIGHT; t++){
for(i = 0; i < STAGE_WIDTH; i++){
index = t * STAGE_WIDTH + i;
addList(sd[index]);
pfirst_stage[index + t] = sd[index];
}
}
resetStage();
return;
}
// 現在の状態に初期状態をコピー 要は現在の状態を初期状態に
void resetStage(){
int i;
now_list[KOMA_1] = first_list[KOMA_1];
now_list[KOMA_2] = first_list[KOMA_2];
now_list[KOMA_3] = first_list[KOMA_3];
now_list[KOMA_4] = first_list[KOMA_4];
now_list[KOMA_5] = first_list[KOMA_5];
for(i = 0; i < STAGE_SIZE; i++){
pnow_stage[i] = pfirst_stage[i];
}
return;
}
// インデックスからコマを返す
inline stage getKoma(int index){
return pnow_stage[index];
}
// コマがとれれば 0 を返す とれなければ 1 を返す
inline int cantTakeKoma(int index){
if(getKoma(index) & SPACE)return 1;
if(getKoma(index) & getKoma(index + LEFT))return 1;
if(getKoma(index) & getKoma(index + UP))return 1;
if(getKoma(index) & getKoma(index + RIGHT))return 0;
if(getKoma(index) & getKoma(index + DOWN))return 0;
return 1;
}
// とれるコマを縦横探索する とれる場合は KOMA_TAKEN のフラグをたてる
inline void checkRoundKoma(int index){
if(getKoma(index) & KOMA_TAKEN)return;
subList(getKoma(index));
pnow_stage[index] |= KOMA_TAKEN;
if(getKoma(index) & getKoma(index + UP))checkRoundKoma(index + UP);
if(getKoma(index) & getKoma(index + LEFT))checkRoundKoma(index + LEFT);
if(getKoma(index) & getKoma(index + DOWN))checkRoundKoma(index + DOWN);
if(getKoma(index) & getKoma(index + RIGHT))checkRoundKoma(index + RIGHT);
return;
}
inline void downKoma(int index, int d){
if(getKoma(index)){
if(getKoma(index) & KOMA_TAKEN){
downKoma(index + UP, d + DOWN);
}
else{
pnow_stage[index + d] = getKoma(index);
downKoma(index + UP, d);
}
return;
}
if(d == 0)return;
pnow_stage[index + d] = SPACE;
downKoma(index, d + UP);
return;
}
inline void downSlideKoma(int index){
if(!getKoma(index))return;
downKoma(index, 0);
downSlideKoma(++index);
}
inline void leftKoma(int index, int d){
if(!getKoma(index + d))return;
pnow_stage[index] = getKoma(index + d);
pnow_stage[index + d] = SPACE;
leftKoma(index + UP, d);
return;
}
inline void leftSlideKoma(int index, int d){
if(index + d == STAGE_SIZE)return;
if(getKoma(index)){
leftSlideKoma(++index, 1);
}
else if(!getKoma(index + d)){
leftSlideKoma(index, ++d);
}
else{
leftKoma(index, d);
leftSlideKoma(++index, 1);
}
return;
}
// インデックスのコマを取る とれない場合は 0 を返す とれれば現在の状態を更新して 1 を返す
int takeKoma(int index){
if(cantTakeKoma(index))return 0;
checkRoundKoma(index);
downSlideKoma(STAGE_SIZE - STAGE_WIDTH);
leftSlideKoma(STAGE_SIZE - STAGE_WIDTH, 1);
return 1;
}
void printList(){
printf("KOMA_1= %d ", now_list[KOMA_1]);
printf("KOMA_2= %d ", now_list[KOMA_2]);
printf("KOMA_3= %d ", now_list[KOMA_3]);
printf("KOMA_4= %d ", now_list[KOMA_4]);
printf("KOMA_5= %d ", now_list[KOMA_5]);
putchar('\n');
return;
}
void printStage(){
int i, t;
for(t = 0; t < STAGE_HEIGHT; t++){
for(i = 0; i < STAGE_WIDTH; i++){
switch(getKoma(t * (STAGE_WIDTH + 1) + i) & KOMA_ALL){
case SPACE:
putchar(' ');
break;
case KOMA_1:
putchar('A');
break;
case KOMA_2:
putchar('B');
break;
case KOMA_3:
putchar('C');
break;
case KOMA_4:
putchar('D');
break;
case KOMA_5:
putchar('E');
break;
default:
break;
}
}
putchar('\n');
}
return;
}
int main(){
int i;
int index = 0;
int take_flag;
int buffer[STAGE_SIZE >> 1];
for(i = 0; i < (STAGE_SIZE >> 1); i++){
buffer[i] = 0;
}
initStage(stage_data);
for(;;){
take_flag = takeKoma(buffer[index]);
if(take_flag){
index++;
continue;
}
buffer[index]++;
if(buffer[index] - STAGE_SIZE == 0){
if(!getKoma(STAGE_SIZE - STAGE_WIDTH)){
printf("\nClear!\n");
for(i = 0; i < index; i++){
printf("(%d,%d),", buffer[i] % (STAGE_WIDTH + 1), buffer[i] / (STAGE_WIDTH + 1));
}
break;
}
if(index == 0){
printf("\nThis stage cannot be solved!\n");
break;
}
buffer[index - 1]++;
for(i = index; i < (STAGE_SIZE >> 1); i++){
buffer[i] = 0;
}
index = 0;
resetStage();
}
}
return 0;
}