M.Hiroi's Home Page
http://www.geocities.jp/m_hiroi/

Puzzle DE Programming

ペグ・ソリテア : トライトライ

[ Home | Puzzle ]

●プログラムリスト1

/*
 * trytry.c : ペグ・ソリテア「トライトライ」
 *
 *            Copyright (C) 2002 Makoto Hiroi
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define TRUE  1
#define FALSE 0

#define SIZE     25
#define MAX_JUMP 23

/* 跳び先表 */
const char jump_table[][SIZE] = {
  { 2,  5,  3,  7, -1},                                 /* 0 */
  { 3,  6,  4,  8, -1},                                 /* 1 */
  { 3,  4,  5,  9,  6, 11, -1},                         /* 2 */
  { 6, 10,  7, 12, -1},                                 /* 3 */
  { 3,  2,  7, 11,  8, 13, -1},                         /* 4 */
  { 2,  0,  6,  7,  9, 14, 10, 16, -1},                 /* 5 */
  { 3,  1,  7,  8, 10, 15, 11, 17, -1},                 /* 6 */
  { 3,  0,  6,  5, 11, 16, 12, 18, -1},                 /* 7 */
  { 4,  1,  7,  6, 12, 17, 13, 19, -1},                 /* 8 */
  { 5,  2, 10, 11, 15, 21, -1},                         /* 9 */
  { 6,  3, 11, 12, 15, 20, 16, 22, -1},                 /* 10 */
  { 6,  2,  7,  4, 10,  9, 12, 13, 16, 21, 17, 23, -1}, /* 11 */
  { 7,  3, 11, 10, 17, 22, 18, 24, -1},                 /* 12 */
  { 8,  4, 12, 11, 18, 23, -1},                         /* 13 */
  { 9,  5, 15, 16, -1},                                 /* 14 */
  {10,  6, 16, 17, -1},                                 /* 15 */
  {10,  5, 11,  7, 15, 14, 17, 18, -1},                 /* 16 */
  {11,  6, 12,  8, 16, 15, 18, 19, -1},                 /* 17 */
  {12,  7, 17, 16, -1},                                 /* 18 */
  {13,  8, 18, 17, -1},                                 /* 19 */
  {15, 10, 21, 22, -1},                                 /* 20 */
  {15,  9, 16, 11, 22, 23, -1},                         /* 21 */
  {16, 10, 17, 12, 21, 20, 23, 24, -1},                 /* 22 */
  {17, 11, 18, 13, 22, 21, -1},                         /* 23 */
  {18, 12, 23, 22, -1},                                 /* 24 */
};

/* corner */
const char corner[SIZE] = {
         1,  1,
       0,  0,  0,
     0,  0,  0,  0,
   0,  0,  0,  0,  0,
 1,  0,  0,  0,  0,  1,
   1,  0,  0,  0,  1,
};

/* edge */
const char edge[SIZE] = {
         0,  0,
       1,  0,  2,
     1,  0,  0,  2,
   1,  0,  0,  0,  2,
 0,  0,  0,  0,  0,  0,
   0,  3,  3,  3,  0,
};

/* 初期状態 */
const char init_data[SIZE] = {
         1,  1,
       1,  1,  1,
     1,  1,  1,  1,
   1,  1,  0,  1,  1,
 1,  1,  1,  1,  1,  1,
   1,  1,  1,  1,  1,
};

/* 盤面 */
char board[SIZE];

/* 跳び手順を格納 */
char move[MAX_JUMP][2];

/* コーナーのペグ数 */
int lower_value = 6;

/* 計測用 */
int start;

/* 辺の下限値 */
const char edge_value[8] = {
  0, /* 000 */
  0, /* 001 */
  0, /* 010 */
  1, /* 011 */
  0, /* 100 */
  0, /* 101 */
  1, /* 110 */
  1, /* 111 */
};

/* 辺の下限値を求めるマクロ */
#define GET_EDGE_VALUE(a,b,c)  edge_value[(board[(a)]<<2) + (board[(b)]<<1) + board[(c)]]

/* 下限値の計算 */
int get_lower_value( int prev )
{
  int  low = lower_value - corner[prev];
  int  eg  = edge[prev];
  /* 辺のチェック */
  if( eg != 1 ) low += GET_EDGE_VALUE(  2,  5,  9 );
  if( eg != 2 ) low += GET_EDGE_VALUE(  4,  8, 13 );
  if( eg != 3 ) low += GET_EDGE_VALUE( 21, 22, 23 );
  return low;
}

/* ペグを動かす */
void move_piece( int n, int from, int del, int to )
{
  board[from] = 0;
  board[del] = 0;
  board[to] = 1;
  move[n][0] = from;
  move[n][1] = to;
  /* corner check (corner は from か to しかない)*/
  if( corner[from] ){
    lower_value--;
  } else if( corner[to] ){
    lower_value++;
  }
}

/* ペグを元に戻す */
void back_piece( int from, int del, int to )
{
  board[from] = 1;
  board[del] = 1;
  board[to] = 0;
  /* corner check (corner は from か to しかない)*/
  if( corner[from] ){
    lower_value++;
  } else if( corner[to] ){
    lower_value--;
  }
}

/* 手順を表示 */
void print_move( void )
{
  int i, j;
  for( i = 0, j = 1; i < MAX_JUMP; i++, j++ ){
    printf("(%d, %d", move[i][0], move[i][1] );
    for( ; j < MAX_JUMP; i++, j++ ){
      if( move[i][1] != move[j][0] ) break;
      printf(", %d", move[j][1] );
    }
    printf(")");
  }
  printf("\n時間 %d\n", clock() - start );
}

/* 手順の探索(反復深化+下限値枝刈り法) */
void search_move( int n, int jc, int limit )
{
  int prev = move[n - 1][1];
  if( (jc + get_lower_value( prev )) > limit ) return;
  if( n == MAX_JUMP ){
    print_move(); exit( 0 );
  } else {
    int from, del, to, i;
    for( from = 0; from < SIZE; from++ ){
      if( !board[from] ) continue;        /* ペグが無い */
      i = 0;
      while( (del = jump_table[from][i++]) != -1 ){
        to = jump_table[from][i++];
        if( board[del] && !board[to] ){
          /* 跳び越せる */
          move_piece( n, from, del, to );
          search_move( n + 1, (prev == from ? jc : jc + 1), limit );
          back_piece( from, del, to );
        }
      }
    }
  }
}

int main()
{
  int limit;
  /* 初期化 */
  start = clock();
  memcpy( board, init_data, SIZE );
  /* 初手は [2, 11] に決め打ち */
  move_piece( 0, 2, 6, 11 );
  /* 初期状態の下限値は 9 */
  for( limit = 9; limit <= MAX_JUMP; limit++ ){
    printf("・・・手数 %d を探索中・・・\n", limit );
    search_move( 1, 1, limit );
  }
  return 0;
}

戻る


●プログラムリスト2

/*
 * trytry.c : ペグ・ソリテア「トライトライ」中央補償型の解
 *
 *            Copyright (C) 2002 Makoto Hiroi
 */

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

#define TRUE  1
#define FALSE 0

#define SIZE     25
#define MAX_JUMP 23
#define HOLE     11

/* 跳び先表 */
const char jump_table[][SIZE] = {
  { 2,  5,  3,  7, -1},                                 /* 0 */
  { 3,  6,  4,  8, -1},                                 /* 1 */
  { 3,  4,  5,  9,  6, 11, -1},                         /* 2 */
  { 6, 10,  7, 12, -1},                                 /* 3 */
  { 3,  2,  7, 11,  8, 13, -1},                         /* 4 */
  { 2,  0,  6,  7,  9, 14, 10, 16, -1},                 /* 5 */
  { 3,  1,  7,  8, 10, 15, 11, 17, -1},                 /* 6 */
  { 3,  0,  6,  5, 11, 16, 12, 18, -1},                 /* 7 */
  { 4,  1,  7,  6, 12, 17, 13, 19, -1},                 /* 8 */
  { 5,  2, 10, 11, 15, 21, -1},                         /* 9 */
  { 6,  3, 11, 12, 15, 20, 16, 22, -1},                 /* 10 */
  { 6,  2,  7,  4, 10,  9, 12, 13, 16, 21, 17, 23, -1}, /* 11 */
  { 7,  3, 11, 10, 17, 22, 18, 24, -1},                 /* 12 */
  { 8,  4, 12, 11, 18, 23, -1},                         /* 13 */
  { 9,  5, 15, 16, -1},                                 /* 14 */
  {10,  6, 16, 17, -1},                                 /* 15 */
  {10,  5, 11,  7, 15, 14, 17, 18, -1},                 /* 16 */
  {11,  6, 12,  8, 16, 15, 18, 19, -1},                 /* 17 */
  {12,  7, 17, 16, -1},                                 /* 18 */
  {13,  8, 18, 17, -1},                                 /* 19 */
  {15, 10, 21, 22, -1},                                 /* 20 */
  {15,  9, 16, 11, 22, 23, -1},                         /* 21 */
  {16, 10, 17, 12, 21, 20, 23, 24, -1},                 /* 22 */
  {17, 11, 18, 13, 22, 21, -1},                         /* 23 */
  {18, 12, 23, 22, -1},                                 /* 24 */
 };

/* corner */
const char corner[SIZE] = {
         1,  1,
       0,  0,  0,
     0,  0,  0,  0,
   0,  0,  0,  0,  0,
 1,  0,  0,  0,  0,  1,
   1,  0,  0,  0,  1,
};

/* edge */
const char edge[SIZE] = {
         0,  0,
       1,  0,  2,
     1,  0,  0,  2,
   1,  0,  0,  0,  2,
 0,  0,  0,  0,  0,  0,
   0,  3,  3,  3,  0,
};

/* Group */
const char group[SIZE] = {
         0,  1,
       3,  2,  3,
     0,  1,  0,  1,
   3,  2,  3,  2,  3,
 0,  1,  0,  1,  0,  1,
   2,  3,  2,  3,  2
};

/* 初期状態 */
const char init_data[SIZE] = {
         1,  1,
       1,  1,  1,
     1,  1,  1,  1,
   1,  1,  0,  1,  1,
 1,  1,  1,  1,  1,  1,
   1,  1,  1,  1,  1,
};

/* 盤面 */
char board[SIZE];

/* 跳び手順を格納 */
char move[MAX_JUMP][2];

/* コーナーのペグ数 */
int lower_value = 6;

/* Group ごとのペグの個数 */
int rest_peg[4] = { 6, 6, 6, 6 };

/* 計測用 */
int start;

/* 辺の下限値 */
const char edge_value[8] = {
  0, /* 000 */
  0, /* 001 */
  0, /* 010 */
  1, /* 011 */
  0, /* 100 */
  0, /* 101 */
  1, /* 110 */
  1, /* 111 */
};

/* 辺の下限値を求めるマクロ */
#define GET_EDGE_VALUE(a,b,c)  edge_value[(board[(a)]<<2) + (board[(b)]<<1) + board[(c)]]

/* 下限値の計算 */
int get_lower_value( int prev )
{
  int  low = lower_value - corner[prev];
  int  eg  = edge[prev];
  /* 辺のチェック */
  if( eg != 1 ) low += GET_EDGE_VALUE(  2,  5,  9 );
  if( eg != 2 ) low += GET_EDGE_VALUE(  4,  8, 13 );
  if( eg != 3 ) low += GET_EDGE_VALUE( 21, 22, 23 );
  return low;
}

/* ペグを動かす */
void move_piece( int n, int from, int del, int to )
{
  board[from] = 0;
  board[del] = 0;
  board[to] = 1;
  move[n][0] = from;
  move[n][1] = to;
  rest_peg[ group[from] ]--;
  rest_peg[ group[del] ]--;
  rest_peg[ group[to] ]++;
  /* corner check (corner は from か to しかない)*/
  if( corner[from] ){
    lower_value--;
  } else if( corner[to] ){
    lower_value++;
  }
}

/* ペグを元に戻す */
void back_piece( int from, int del, int to )
{
  board[from] = 1;
  board[del] = 1;
  board[to] = 0;
  rest_peg[ group[from] ]++;
  rest_peg[ group[del] ]++;
  rest_peg[ group[to] ]--;
  /* corner check (corner は from か to しかない)*/
  if( corner[from] ){
    lower_value++;
  } else if( corner[to] ){
    lower_value--;
  }
}

/* 手順を表示 */
void print_move( void )
{
  int i, j;
  for( i = 0, j = 1; i < MAX_JUMP; i++, j++ ){
    printf("(%d, %d", move[i][0], move[i][1] );
    for( ; j < MAX_JUMP; i++, j++ ){
      if( move[i][1] != move[j][0] ) break;
      printf(", %d", move[j][1] );
    }
    printf(")");
  }
  printf("\n時間 %d\n", clock() - start );
}

/* 手順の探索 */
void search_move( int n, int jc, int limit )
{
  int prev = move[n - 1][1];
  if( (jc + get_lower_value( prev )) > limit ) return;

  if( n == MAX_JUMP && board[HOLE] ){
    print_move(); exit( 0 );
  } else {
    int from, del, to, i;
    for( from = 0; from < SIZE; from++ ){
      if( !board[from] ) continue;        /* ペグが無い */
      i = 0;
      while( (del = jump_table[from][i++]) != -1 ){
        to = jump_table[from][i++];
        if( board[del] && !board[to] ){
          /* 跳び越せる */
          move_piece( n, from, del, to );
          if( prev == from ){
            search_move( n + 1, jc, limit );
          } else {
            if( jc < limit - 2 ||
                (jc == limit - 2 && group[from] != 3) ||
                (jc == limit - 1 && group[from] == 3 && rest_peg[3] == 1)){
              search_move( n + 1, jc + 1, limit );
            }
          }
          back_piece( from, del, to );
        }
      }
    }
  }
}

int main()
{
  int limit;
  /* 初期化 */
  start = clock();
  memcpy( board, init_data, SIZE );
  /* 初手は [2, 11] に決め打ち */
  move_piece( 0, 2, 6, 11 );
  /* 初期状態の下限値は 9 */
  for( limit = 9; limit <= MAX_JUMP; limit++ ){
    printf("・・・手数 %d を探索中・・・\n", limit );
    search_move( 1, 1, limit );
  }
  return 0;
}

戻る


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

[ Home | Puzzle ]