Last Update: May.25,2001

C Source Library

「LSI C-86 Ver.3.30c 試食版」、「Borland C++ 5.5」、「Microsoft Visual C++ 6.0」でコンパイル出来ます。

■ 「おしどり遊び」を解く

/*
 *  oshidori.c - 「おしどり遊び」を解く
 *
 *      Copyright (c) 2001 AOK. (oshidori.c Rev.1 - 2001.5.25)
 *
 *  黒石3個,白石3個を次のように並べます。
 *
 *  |●|○|●|○|●|○| | |
 *
 *  並んだ2個の碁石を、そのままの順で空いている所
 *  へ移動させることを繰り返し、下図のようにする。
 *
 *  | | |○|○|○|●|●|●|
 *
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/**** ●: 1    ○: 2    -: 0 ****/

#define MAX_LEN    8 /* 移動可能な範囲 */
#define QUE_LEN  100 /* 大きめにしないとオーバーフロー */

const char *start = "12121200";
const char *end   = "00222111";

typedef struct {
    char cond[MAX_LEN+1]; /* 石の状態 */
    int  prev; /* 手前の局面の位置 */
} NODE;

NODE que[QUE_LEN]; /* 局面の保存用 */
int sp; /* 探索位置 */
int mp; /* 局面数 */

/* 同一の局面を探す(手抜きです)*/
int search(const char* s)
{
    int i;
    for (i=0; i<mp; i++)
        if (strcmp(que[i].cond, s)==0) return 1;
    return 0;
}

/* 表示用 */
void display(int c)
{
    static int n = 0;
    int i, t;
    if (c == -1) return;
    display(que[c].prev);
    t = strlen(que[c].cond);
    printf("%d.", n++);
    for (i=0; i<t; i++) {
        switch (que[c].cond[i]) {
            case '1': printf("●"); break;
            case '2': printf("○"); break;
            case '0': printf("-"); break;
        }
    }
    putchar('\n');
}

/* 石を移動する */
void move(void)
{
    int i, j;
    char t[2], *f1, *f2, q[MAX_LEN+1], r[MAX_LEN+1];
    for (i=0; i<MAX_LEN-1; i++) {
        t[0]= que[sp].cond[i]; t[1] = que[sp].cond[i+1];
        if ((t[0]=='0') || (t[1]=='0')) continue;
        strcpy(r, que[sp].cond);
        r[i] = '0'; r[i+1] = '0'; f1 = r;
        while ((f2 = strstr(f1, "00"))!=NULL) {
            if ((r==f2) && (*(f2+2)=='0')) {
                f1 = ++f2; continue;
            }
            if ((r!=f2) && (*(f2-1)=='0') && 
                ((*(f2+2)=='0') || (*(f2+2)==0))) {
                f1 = ++f2; continue;
            }           
            strcpy(q, r);
            q[(f2-r)/sizeof(char)]   = t[0];
            q[(f2-r)/sizeof(char)+1] = t[1];
            if (!search(q)) {
                if (mp >= QUE_LEN) {
                    puts("エラー:局面数がキューの上限を超えました。");
                    exit(1);
                }
                strcpy(que[mp].cond, q);
                que[mp].prev = sp;
                if (strcmp(q, end)==0) {
                    display(mp);
                    printf("\n--- 探索数=%d, 局面数=%d\n", sp, mp+1);
                    for (j=0; j<=mp; j++) {
                        printf("[%2d-%2d] %s ", que[j].prev, j, que[j].cond);
                        if (j%4==3) putchar('\n');
                    }
                    exit(0);
                }
                mp++;
            }
            f1 = ++f2;
        }
    }
}

/* メインルーチン */
int main()
{
    strcpy(que[0].cond, start);
    que[0].prev = -1; sp = 0; mp = 1;
    while (sp != mp) { move(); ++sp; }
    return 0;
}

/* --- 実行結果 -------------------------------------

0.●○●○●○--
1.●--○●○○●
2.●●○○--○●
3.●●○○○●--
4.--○○○●●●

--- 探索数=20, 局面数=45
[-1- 0] 12121200 [ 0- 1] 00121212 [ 0- 2] 10021221 [ 0- 3] 12001212 
[ 0- 4] 12100221 [ 1- 5] 21100212 [ 1- 6] 12120012 [ 1- 7] 21121002 
[ 2- 8] 11220021 [ 2- 9] 12221001 [ 3-10] 12211002 [ 4-11] 00112221 
[ 4-12] 12122001 [ 5-13] 20011212 [ 5-14] 21112200 [ 6-15] 10022112 
[ 7-16] 20021112 [ 7-17] 21001122 [ 8-18] 00221121 [ 8-19] 11002221 
[ 8-20] 11222100 [ 9-21] 12001221 [ 9-22] 12200211 [10-23] 00211122 
[10-24] 10011222 [10-25] 12200112 [11-26] 22110021 [11-27] 22112001 
[12-28] 00122121 [12-29] 10022211 [12-30] 12002121 [13-31] 21210012 
[13-32] 22111002 [13-33] 21211200 [14-34] 20012211 [14-35] 21002211 
[15-36] 11122002 [16-37] 22100112 [16-38] 21120012 [16-39] 21221100 
[17-40] 21110022 [18-41] 21200121 [19-42] 11222001 [19-43] 11212200 
[20-44] 00222111

 ------------------------------------------------- */