M.Hiroi's Home Page

Puzzle DE Programming

「おしどりの遊び」と「6 パズル」のプログラムリスト

[ Home | Puzzle ]

●oshidori.c

/*
 * oshidori.c : パズル「おしどり」の解法
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TRUE  1
#define FALSE 0
#define S     0
#define B     1
#define W     2
#define SIZE  8

/* 状態の最大値 */
#define MAX_STATE 140

/* 状態 */
char  state[MAX_STATE + 1][SIZE];    /* +1 はワーク領域 */
char  space_position[MAX_STATE];
short prev_state[MAX_STATE];

/* 初期状態 */
char initial_state[SIZE] = {
  B, W, B, W, B, W, S, S
};

/* 最終状態 */
char final_state[SIZE] = {
  B, B, B, W, W, W, S, S
};

/* 手順の表示 */
void print_answer( int n )
{
  int i;
  if( n != 0 ) print_answer( prev_state[n] );
  for( i = 0; i < SIZE; i++ ){
    switch( state[n][i] ){
    case S:
      printf("空 "); break;
    case B:
      printf("黒 "); break;
    case W:
      printf("白 "); break;
    }
  }
  printf("\n");
}

/* 同じ状態をチェックする */
int check_same_state( int n )
{
  /* とりあえず単純な線形探索 */
  int i;
  for( i = 0; i < n; i++ ){
    if( !memcmp( state[i], state[n], SIZE ) ) return TRUE;
  }
  return FALSE;
}

/* 番人を使う方法 */
int check_same_state1( int n )
{
  int i = 0;
  while( memcmp( state[i], state[n], SIZE ) ) i++;
  return (i != n) ? TRUE : FALSE;
}

/* 石の移動 */
void move_stone( int front, int rear, int dest )
{
  int j = space_position[front];
  memcpy( state[rear], state[front], SIZE );
  state[rear][j] = state[front][dest];
  state[rear][j + 1] = state[front][dest + 1];
  state[rear][dest] = S;
  state[rear][dest + 1] = S;
  space_position[rear] = dest;
  prev_state[rear] = front;
}

/* 探索関数 */
void search( void )
{
  int front = 0, rear = 1;
  /* 初期化 */
  memcpy( state[0], initial_state, SIZE );
  prev_state[0] = -1;
  space_position[0] = 6;
  while( front < rear ){
    int i;
    /* 移動 (0 から 6 までチェック) */
    for( i = 0; i < SIZE - 1; i++ ){
      if( state[front][i] && state[front][i + 1] ){
        /* 移動可能 */
        move_stone( front, rear, i );
        /* チェックする */
        if( !memcmp( state[rear], final_state, SIZE ) ){
          /* 解けた */
          print_answer( rear );
          printf("状態数 %d 個\n", rear );
          return;
        } else if( !check_same_state1( rear ) ){
          /* 同じ状態はない */
          rear++;
        }
      }
    }
    front++;
  }
}

int main()
{
  search();
  return 0;
}

戻る


●hex1.c

/*
 * hex1.c : パズル「6 パズル」の解法
 *
 */

#include <stdio.h>
#include <string.h>
#include <time.h>

#define TRUE  1
#define FALSE 0
#define SIZE  7

/* 最大の状態数 7! = 5040 */
#define MAX_STATE 5040

/* 隣接リスト */
const char adjacent[SIZE][7] = {
  1, 2, 3, -1, -1, -1, -1,  /* 0 */
  0, 3, 4, -1, -1, -1, -1,  /* 1 */
  0, 3, 5, -1, -1, -1, -1,  /* 2 */
  0, 1, 2,  4,  5,  6, -1,  /* 3 */
  1, 3, 6, -1, -1, -1, -1,  /* 4 */
  2, 3, 6, -1, -1, -1, -1,  /* 5 */
  3, 4, 5, -1, -1, -1, -1   /* 6 */
};

/* キュー */
char  state[MAX_STATE + 1][SIZE];      /* +1 はワーク領域 */
char  space_position[MAX_STATE];
short prev_state[MAX_STATE];
int count = 0;

/* 初期状態 */
char init_state[SIZE] = {
  1, 5, 2, 6, 3, 4, 0
};

/* 最終状態 */
char final_state[SIZE] = {
  1, 2, 3, 4, 5, 6, 0
};

/* 同じ状態があるか */
int check_same_state( int n )
{
  int i;
  for( i = 0; i < n; i++ ){
    count++;
    if( !memcmp( state[i], state[n], SIZE ) ) return TRUE;
  }
  return FALSE;
}

/* 結果を出力 */
void print_answer( int n )
{
  int i;
  if( n != 0 ) print_answer( prev_state[n] );
  for( i = 0; i < SIZE; i++ ){
    printf("%d ", state[n][i] );
  }
  printf("\n");
}

/* 探索 */
void search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0], init_state, SIZE );
  space_position[0] = 6;
  prev_state[0] = -1;
  while( front < rear ){
    int s = space_position[front];
    int n;
    for( i = 0; (n = adjacent[s][i]) != -1; i++ ){
      /* 状態をコピー */
      memcpy( state[rear], state[front], SIZE );
      /* 移動 */
      state[rear][s] = state[rear][n];
      state[rear][n] = 0;
      space_position[rear] = n;
      prev_state[rear] = front;
      if( !memcmp( state[rear], final_state, SIZE ) ){
        print_answer( rear );
        printf("状態数 %d 個\n", rear );
        return;
      } else if( !check_same_state( rear ) ){
        /* 登録 */
        rear++;
      }
    }
    front++;
  }
}

int main()
{
  int start, end;
  start = clock();
  search();
  end = clock();
  printf("比較回数 %d, 時間 %d \n", count, end - start );
  return 0;
}

戻る


●hex2.c

/*
 * hex2.c : パズル「6 パズル」の解法(改良版)
 *
 */

#include <stdio.h>
#include <string.h>
#include <time.h>

#define TRUE  1
#define FALSE 0
#define SIZE  7
#define FORWARD  0
#define BACKWARD 1 

/* 最大の状態数 7! = 5040 */
#define MAX_STATE 5040

/* 隣接リスト */
const char adjacent[SIZE][7] = {
  1, 2, 3, -1, -1, -1, -1,  /* 0 */
  0, 3, 4, -1, -1, -1, -1,  /* 1 */
  0, 3, 5, -1, -1, -1, -1,  /* 2 */
  0, 1, 2,  4,  5,  6, -1,  /* 3 */
  1, 3, 6, -1, -1, -1, -1,  /* 4 */
  2, 3, 6, -1, -1, -1, -1,  /* 5 */
  3, 4, 5, -1, -1, -1, -1   /* 6 */
};

/* キュー */
char  state[MAX_STATE + 1][SIZE];      /* +1 はワーク領域 */
char  space_position[MAX_STATE];
short prev_state[MAX_STATE];
char  direction[MAX_STATE];


/* 初期状態 */
char init_state[SIZE] = {
  1, 5, 2, 6, 3, 4, 0
};

/* 最終状態 */
char final_state[SIZE] = {
  1, 2, 3, 4, 5, 6, 0
};

/* 同じ状態があるか */
int check_same_state( int n )
{
  int i;
  for( i = 0; i < n; i++ ){
    if( !memcmp( state[i], state[n], SIZE ) ) return i;
  }
  return -1;
}

/* 結果を出力 */
void print_answer_forward( int n )
{
  int i;
  if( n > 1 ) print_answer_forward( prev_state[n] );
  for( i = 0; i < SIZE; i++ ){
    printf("%d ", state[n][i] );
  }
  printf("\n");
}

void print_answer_backward( int n )
{
  do {
    int i;
    n = prev_state[n];
    for( i = 0; i < SIZE; i++ ){
      printf("%d ", state[n][i] );
    }
    printf("\n");
  } while( prev_state[n] != -1 );
}

void print_answer( int i, int j )
{
  if( direction[i] == FORWARD ){
    print_answer_forward( i );
    print_answer_backward( j );
  } else {
    print_answer_forward( j );
    print_answer_backward( i );
  }
}

/* 探索 */
void search( void )
{
  int front = 0, rear = 2;
  /* 初期化 */
  memcpy( state[0], init_state, SIZE );
  space_position[0] = 6;
  prev_state[0] = -1;
  direction[0] = FORWARD;
  memcpy( state[1], final_state, SIZE );
  space_position[1] = 6;
  prev_state[1] = -1;
  direction[1] = BACKWARD;
  while( front < rear ){
    int s = space_position[front];
    int i, j, n;
    for( i = 0; (n = adjacent[s][i]) != -1; i++ ){
      /* 状態をコピー */
      memcpy( state[rear], state[front], SIZE );
      /* 移動 */
      state[rear][s] = state[rear][n];
      state[rear][n] = 0;
      space_position[rear] = n;
      prev_state[rear] = front;
      direction[rear] = direction[front];
      /* 検索する */
      if( (j = check_same_state( rear )) >= 0 ){
        if( direction[j] != direction[rear] ){
          /* 前後からの検索が一致 */
          print_answer( j, rear );
          printf("状態数 %d 個\n", rear );
          return;
        }
      } else {
        /* 登録 */
        rear++;
      }
    }
    front++;
  }
}

int main()
{
  int start, end;
  start = clock();
  search();
  end = clock();
  printf("時間 %d \n",end - start );
  return 0;
}

戻る


●hex3.c

/*
 * hex3.c : パズル「6 パズル」の解法(最長手数の局面を求める)
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define TRUE  1
#define FALSE 0
#define SIZE  7

/* 最大の状態数 7! = 5040 */
#define MAX_STATE 5040

/* 隣接リスト */
const char adjacent[SIZE][7] = {
  1, 2, 3, -1, -1, -1, -1,  /* 0 */
  0, 3, 4, -1, -1, -1, -1,  /* 1 */
  0, 3, 5, -1, -1, -1, -1,  /* 2 */
  0, 1, 2,  4,  5,  6, -1,  /* 3 */
  1, 3, 6, -1, -1, -1, -1,  /* 4 */
  2, 3, 6, -1, -1, -1, -1,  /* 5 */
  3, 4, 5, -1, -1, -1, -1   /* 6 */
};

/* キュー */
char state[MAX_STATE + 1][SIZE];     /* +1 はワーク領域 */
char space_position[MAX_STATE];
char move[MAX_STATE];

/* 初期状態 */
char init_state[SIZE] = {
  1, 2, 3, 4, 5, 6, 0
};

int count = 0;

/* 同じ状態があるか */
int check_same_state( int n )
{
  int i;
  for( i = 0; i < n; i++ ){
    count++;
    if( !memcmp( state[i], state[n], SIZE ) ) return TRUE;
  }
  return FALSE;
}

/* 結果を出力 */
void print_answer( int n )
{
  int m = move[n - 1], c = 0, i;
  while( move[--n] == m ){
    c++;
    for( i = 0; i < SIZE; i++ ){
      printf("%d ", state[n][i] );
    }
    printf("\n");
  }
  printf("最長手数 %d 手、総数 %d 個\n", m, c );
}

void print_answer_all( int n )
{
  int i, j;
  for( j = 0; j < n; j++ ){
    printf("手数 %d : ", move[j] );
    for( i = 0; i < SIZE; i++ ){
      printf("%d ", state[j][i] );
    }
    printf("\n");
  }
}

/* 探索 */
void search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0], init_state, SIZE );
  space_position[0] = 6;
  move[0] = 0;
  while( front < rear ){
    int s = space_position[front];
    int n;
    for( i = 0; (n = adjacent[s][i]) != -1; i++ ){
      /* 状態をコピー */
      memcpy( state[rear], state[front], SIZE );
      /* 移動 */
      state[rear][s] = state[rear][n];
      state[rear][n] = 0;
      if( !check_same_state( rear ) ){
        /* 登録 */
        space_position[rear] = n;
        move[rear] = move[front] + 1;
        rear++;
      }
    }
    front++;
  }
  print_answer( rear );
}

int main()
{
  int start, end;
  start = clock();
  search();
  end = clock();
  printf("比較回数 %d 回、時間 %d \n", count, end - start );
  return 0;
}

戻る


Copyright (C) 2002,2003 Makoto Hiroi
All rights reserved.

[ Home | Puzzle ]