M.Hiroi's Home Page

Puzzle DE Programming

「6 パズル」と「8 パズル」のプログラムリスト

[ Home | Puzzle ]

●hex4.c

/*
 * hex4.c : パズル「6 パズル」の解法(最長手数の局面を求める)
 *
 *          二分探索木を使った高速バージョン
 */

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

#define TRUE  1
#define FALSE 0
#define SIZE  7
#define NIL   (-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 */
};

/* 二分探索木 */
typedef struct node {
  char board[SIZE];
  int  right;
  int  left;
} NODE;

/* キュー */
NODE state[MAX_STATE + 1];        /* +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 insert_tree( int i )
{
  int r, n = 0, *np = &n;
  while( *np != NIL ){
    r = memcmp( state[i].board, state[*np].board, SIZE );
    count++;
    if( r == 0 ){
      return FALSE;      /* 登録済み */
    } else if( r < 0 ){
      np = &(state[*np].left);
    } else {
      np = &(state[*np].right);
    }
  }
  /* 登録する */
  *np = i;
  state[i].left = NIL;
  state[i].right = NIL;
  return TRUE;
}

/* 結果を出力 */
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].board[i] );
    }
    printf("\n");
  }
  printf("最長手数 %d 手、総数 %d 個\n", m, c );
}

/* 探索 */
int search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0].board, init_state, SIZE );
  state[0].right = NIL;
  state[0].left = NIL;
  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].board, state[front].board, SIZE );
      /* 移動 */
      state[rear].board[s] = state[rear].board[n];
      state[rear].board[n] = 0;
      if( insert_tree( 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;
}

戻る


●eight1.c

/*
 * eigth1.c : 8 パズルの解法(最長手数の局面を求める)
 *
 */

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

#define TRUE  1
#define FALSE 0
#define SIZE  9
#define NIL   (-1)

/* 状態数 (9! / 2) */
#define MAX_STATE 181440

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

/* 二分探索木 */
typedef struct node {
  char board[SIZE];
  int  right;
  int  left;
} NODE;

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

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

int count = 0;

/* 二分探索木への登録 */
int insert_tree( int i )
{
  int r, n = 0, *np = &n;
  while( *np != NIL ){
    r = memcmp( state[i].board, state[*np].board, SIZE );
    count++;
    if( r == 0 ){
      return FALSE;      /* 登録済み */
    } else if( r < 0 ){
      np = &(state[*np].left);
    } else {
      np = &(state[*np].right);
    }
  }
  /* 登録する */
  *np = i;
  state[i].left = NIL;
  state[i].right = NIL;
  return TRUE;
}

/* 結果を出力 */
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].board[i] );
    }
    printf("\n");
  }
  printf("最長手数 %d 手、総数 %d 個\n", m, c );
}

/* 探索 */
int search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0].board, init_state, SIZE );
  state[0].right = NIL;
  state[0].left = NIL;
  space_position[0] = 8;
  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].board, state[front].board, SIZE );
      /* 移動 */
      state[rear].board[s] = state[rear].board[n];
      state[rear].board[n] = 0;
      if( insert_tree( rear ) ){
	/* 登録 */
	space_position[rear] = n;
	move[rear] = move[front] + 1;
	rear++;
      }
    }
    front++;
  }
  printf("総数 %d 個\n", rear );
  print_answer( rear );
}

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

戻る


●eight2.c

/*
 * eigth2.c : 8 パズルの解法(最長手数の局面を求める)
 *
 */

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

#define TRUE  1
#define FALSE 0
#define SIZE  9
#define NIL   (-1)

/* 状態数 (9! / 2) */
#define MAX_STATE 181440

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

/* 二分探索木 */
typedef struct node {
  char board[SIZE];
  int  right;
  int  left;
} NODE;

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

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

int count = 0;

/* 二分探索木への登録 */
int insert_tree( int i )
{
  int r, n = 0, *np = &n;
  while( *np != NIL ){
    r = memcmp( state[i].board, state[*np].board, SIZE );
    count++;
    if( r == 0 ){
      return FALSE;      /* 登録済み */
    } else if( r < 0 ){
      np = &(state[*np].left);
    } else {
      np = &(state[*np].right);
    }
  }
  /* 登録する */
  *np = i;
  state[i].left = NIL;
  state[i].right = NIL;
  return TRUE;
}

/* 結果を出力 */
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].board[i] );
    }
    printf("\n");
  }
  printf("最長手数 %d 手、総数 %d 個\n", m, c );
}

/* 探索 */
int search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0].board, init_state, SIZE );
  state[0].right = NIL;
  state[0].left = NIL;
  space_position[0] = 8;
  move[0] = 0;
  move_piece[0] = NIL;

  while( front < rear ){
    int s = space_position[front];
    int n;
    for( i = 0; (n = adjacent[s][i]) != -1; i++ ){
      /* 動かした駒は元に戻さない */
      if( move_piece[front] != state[front].board[n] ){
	/* 状態をコピー */
	memcpy( state[rear].board, state[front].board, SIZE );
	/* 移動 */
	move_piece[rear] = state[rear].board[n];
	state[rear].board[s] = state[rear].board[n];
	state[rear].board[n] = 0;
	if( insert_tree( rear ) ){
	  /* 登録 */
	  space_position[rear] = n;
	  move[rear] = move[front] + 1;
	  rear++;
	}
      }
    }
    front++;
  }
  printf("総数 %d 個\n", rear );
  print_answer( rear );
}

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

戻る


●eight3.c

/*
 * eigth3.c : 8 パズルの解法(最長手数の局面を求める)
 *
 */

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

#define TRUE  1
#define FALSE 0
#define SIZE  9
#define NIL   (-1)

/* 素数が良い */
#define HASH_SIZE 19997

/* 状態数 (9! / 2) */
#define MAX_STATE 181440

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

/* 連結リスト */
typedef struct {
  char board[SIZE];
  int  next;
} CELL;

/* ハッシュ表 */
int hash_table[HASH_SIZE];

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

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

/* ハッシュ関数 */
int hash_value( int n )
{
  int i, value = 0;
  for( i = 0; i < SIZE; i++ ){
    value = value * 10 + state[n].board[i];
  }
  return value % HASH_SIZE;
}

int count = 0;

/* ハッシュ表への登録 */
int insert_hash( int i )
{
  /* ハッシュ表のチェック */
  int h = hash_value( i );
  int n = hash_table[h];
  /* 探索 */
  while( n != NIL ){
    count++;
    if( memcmp( state[i].board, state[n].board, SIZE ) == 0 ){
      return FALSE;      /* 登録済み */
    }
    n = state[n].next;
  }
  /* 先頭に追加 */
  state[i].next = hash_table[h];
  hash_table[h] = i;
  return TRUE;
}

/* 結果を出力 */
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].board[i] );
    }
    printf("\n");
  }
  printf("最長手数 %d 手、総数 %d 個\n", m, c );
}

/* 探索 */
int search( void )
{
  int front = 0, rear = 1, i;
  /* 初期化 */
  memcpy( state[0].board, init_state, SIZE );
  space_position[0] = 8;
  move[0] = 0;
  move_piece[0] = NIL;
  /* ハッシュ表への登録 */
  insert_hash( 0 );

  while( front < rear ){
    int s = space_position[front];
    int n;
    for( i = 0; (n = adjacent[s][i]) != -1; i++ ){
      /* 動かした駒は元に戻さない */
      if( move_piece[front] != state[front].board[n] ){
	/* 状態をコピー */
	memcpy( state[rear].board, state[front].board, SIZE );
	/* 移動 */
	move_piece[rear] = state[rear].board[n];
	state[rear].board[s] = state[rear].board[n];
	state[rear].board[n] = 0;
	if( insert_hash( rear ) ){
	  /* 登録 */
	  space_position[rear] = n;
	  move[rear] = move[front] + 1;
	  rear++;
	}
      }
    }
    front++;
  }
  printf("総数 %d 個\n", rear );
  print_answer( rear );
}

int main()
{
  int i, start, end;
  /* ハッシュ表の初期化 */
  for( i = 0; i < HASH_SIZE; i++ ){
    hash_table[i] = NIL;
  }
  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 ]