ホームに戻る
 C言語でリバーシ(AI対戦版)

bcc32用のC言語で書いたコンソールで動くリバーシです。
AI同士で対戦できるようにしました。
試合数とAIの使用できる制限時間を設定できます。
制限時間は1手が制限時間以上になるとその試合は負けになります。
以下の例は AI_1 をランダム、 AI_2 を盤面優先度で書いています。

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

// 試合数
#define MATCH 100

// 制限時間(ミリ秒)
#define TIME_LIMIT 10

// 経過を表示する 1 しない 0
#define PRINT 0

// 白は後手、黒は先手
#define SIRO 1  // ●
#define KURO 2  // ○

// AI の名前
#define AI1_NAME "ai_1"
#define AI2_NAME "ai_2"

int get_k(int y, int x);
int check_k(int k, int y, int x);

// AI1のアルゴリズム
void ai1(int k, int *py, int *px){
  // k は自分のコマであり if(k == KURO) で確認できます。
  // コマ情報は get_k(y, x) で得ることができます。
  // 何も置いていない:0 白いコマ:SIRO 黒いコマ:KURO
  // コマが置けるかを if(check_k(k, y, x) == 1) でチェックし、
  // 置く位置が決まったら *py と *px に値をセット
  
  int count = 0;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(check_k(k, y, x) == 1){
        count++;
      }
    }
  }
  
  int c = 0;
  int t = rand() % count;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(check_k(k, y, x) == 1){
        if(t == c){
          *py = y;
          *px = x;
        }
        c++;
      }
    }
  }
}

// AI2のアルゴリズム
void ai2(int k, int *py, int *px){
  // k は自分のコマであり if(k == KURO) で確認できます。
  // コマ情報は get_k(y, x) で得ることができます。
  // 何も置いていない:0 白いコマ:SIRO 黒いコマ:KURO
  // コマが置けるかを if(check_k(k, y, x) == 1) でチェックし、
  // 置く位置が決まったら *py と *px に値をセット
  
  static int d[8][8] = {
    {5, 1, 4, 4, 4, 4, 1, 5},
    {1, 1, 2, 2, 2, 2, 1, 1},
    {4, 2, 3, 3, 3, 3, 2, 4},
    {4, 2, 3, 0, 0, 3, 2, 4},
    {4, 2, 3, 0, 0, 3, 2, 4},
    {4, 2, 3, 3, 3, 3, 2, 4},
    {1, 1, 4, 4, 4, 4, 1, 1},
    {5, 1, 2, 2, 2, 2, 1, 5}
  };
  
  int mx = 0;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(check_k(k, y, x) == 1){
        if(mx < d[y][x]){
          mx = d[y][x];
        }
      }
    }
  }
  
  int count = 0;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(check_k(k, y, x) == 1){
        if(d[y][x] == mx){
          count++;
        }
      }
    }
  }
  
  int c = 0;
  int t = rand() % count;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(check_k(k, y, x) == 1){
        if(d[y][x] == mx){
          if(t == c){
            *py = y;
            *px = x;
          }
          c++;
        }
      }
    }
  }
}

// 盤の初期状態 白を 1 黒を 2 とする
static int map_array[10][10] = {
  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1,  0,  0,  0,  1,  2,  0,  0,  0, -1},
  {-1,  0,  0,  0,  2,  1,  0,  0,  0, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
};

// 8方向のリスト
static int dir[8][2] = {
  {-1, -1},
  {-1,  0},
  {-1,  1},
  { 0, -1},
  { 0,  1},
  { 1, -1},
  { 1,  0},
  { 1,  1}
};

static void init_map(int map[10][10]);
static void set_map(int map[10][10]);
static int get(int map[10][10], int y, int x);
static void put(int map[10][10], int k, int y, int x);
static void print_map(int map[10][10]);
static int check_dir(int map[10][10], int k, int y,int x, int dy, int dx, int flag);
static int check_koma(int map[10][10], int k, int y, int x);
static int count_enable_point(int map[10][10], int k);
static int count_point(int map[10][10], int k);
static void put_dir(int map[10][10], int k, int y, int x, int dy, int dx);
static void put_koma(int map[10][10], int k, int y, int x);
static int select_first_player();
static void input_point(int k, int *py, int *px);
static void no_point(int k);
static int jibun_turn(int map[10][10], int k);
static int teki_turn(int map[10][10], int k);
static void play_game(int map[10][10]);

// map を初期状態にセット
void init_map(int map[10][10]){
  for(int y = 0; y < 10; y++){
    for(int x = 0; x < 10; x++){
      map[y][x] = map_array[y][x];
    }
  }
}

static int (*map_c)[10];

void set_map(int map[10][10]){
  map_c = map;
}

int get_k(int y, int x){
  return get(map_c, y, x);
}

// 盤の y 座標 x 座標の値を得る
int get(int map[10][10], int y, int x){
  return map[y + 1][x + 1];
}

// 盤の y 座標 x 座標に値を入れる
void put(int map[10][10], int k, int y, int x){
  map[y + 1][x + 1] = k;
}

// 盤を表示
void print_map(int map[10][10],int f){
  static char *c = "ABCDEFGH";
  static char *r = "123456789";
  
  if(f == KURO){
    if(PRINT == 1)printf("○:%s ●:%s\n", AI1_NAME, AI2_NAME);
  }
  else if(f == SIRO){
    if(PRINT == 1)printf("○:%s ●:%s\n", AI2_NAME, AI1_NAME);
  }
  
  printf(" %s\n", c);
  
  for(int y = 0; y < 8; y++){
    printf("%c%c", r[y * 2], r[y * 2 + 1]);
    for(int x = 0; x < 8; x++){
      if(get(map, y, x) == 0){
        printf("・");
      }
      else if(get(map, y, x) == SIRO){
        printf("●");
      }
      else if(get(map, y, x) == KURO){
        printf("○");
      }
    }
    printf("\n");
  }

  get_char();
}

// dy, dx 方向を再帰で探索し、コマが置けるかチェック
int check_dir(int map[10][10], int k, int y, int x, int dy, int dx, int flag){
  if(get(map, y, x) == 0 || get(map, y, x) == -1){
    return 0;
  }
  
  // 反するコマがあれば flag = 1 し、その後自分のコマに出会えば可能
  
  if(k == SIRO){
    if(get(map, y, x) == KURO){
      flag = 1;
    }
    else if(get(map, y, x) == SIRO){
      return flag;
    }
  }
  else if(k == KURO){
    if(get(map, y, x) == SIRO){
      flag = 1;
    }
    else if(get(map, y, x) == KURO){
      return flag;
    }
  }
  
  return check_dir(map, k, y + dy, x + dx, dy, dx, flag);
}

int check_k(int k, int y, int x){
  return check_koma(map_c, k, y, x);
}

// 現在のコマと8方向を探索し、コマが置けるかチェック
int check_koma(int map[10][10], int k, int y, int x){
  int result = 0;
  
  if(get(map, y, x) != 0){
    return 0;
  }
  
  for(int i = 0; i < 8; i++){
    result |= check_dir(map, k, y + dir[i][0], x + dir[i][1], dir[i][0], dir[i][1], 0);
  }
  
  return result;
}

// 盤の中に k のコマが置ける箇所がいくつあるか数える
int count_enable_point(int map[10][10], int k){
  int count = 0;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      count += check_koma(map, k, y, x);
    }
  }
  
  return count;
}

// 盤の中に k のコマはいくつあるか数える
int count_point(int map[10][10], int k){
  int count = 0;
  
  for(int y = 0; y < 8; y++){
    for(int x = 0; x < 8; x++){
      if(get(map, y, x) == k){
        count++;
      }
    }
  }
  
  return count;
}

// dy, dx 方向を再帰で探索しコマを裏返していく
void put_dir(int map[10][10], int k, int y, int x, int dy, int dx){
  if(k == SIRO){
    if(get(map, y, x) == KURO){
      put(map, SIRO, y, x);
    }
    else if(get(map, y, x) == SIRO){
      return;
    }
  }
  else if(k == KURO){
    if(get(map, y, x) == SIRO){
      put(map, KURO, y, x);
    }
    else if(get(map, y, x) == KURO){
      return;
    }
  }
  
  put_dir(map, k, y + dy, x + dx, dy, dx);
}

// コマを置いて、8方向を探索しコマを裏返す
void put_koma(int map[10][10], int k, int y, int x){
  if(get(map, y, x) != 0){
    return;
  }
  
  put(map, k, y, x);
  
  for(int i = 0; i < 8; i++){
    int result = check_dir(map, k, y + dir[i][0], x + dir[i][1], dir[i][0], dir[i][1], 0);
    
    if(result == 1){
      put_dir(map, k, y + dir[i][0], x + dir[i][1], dir[i][0], dir[i][1]);
    }
  }
}

// 敵ターン
int turn(int map[10][10], int k, void (*ai)(int, int *, int *)){
  if(count_enable_point(map, k) == 0){
    return -1;
  }
  else{
    int y, x;
    for(;;){
      LARGE_INTEGER nFreq, nBefore, nAfter;
      DWORD dwTime;
      
      memset(&nFreq,   0x00, sizeof nFreq);
      memset(&nBefore, 0x00, sizeof nBefore);
      memset(&nAfter,  0x00, sizeof nAfter);
      dwTime = 0;
      
      QueryPerformanceFrequency(&nFreq);
      QueryPerformanceCounter(&nBefore);  
      
      ai(k, &y, &x);
      
      QueryPerformanceCounter(&nAfter);
      
      dwTime = (DWORD)((nAfter.QuadPart - nBefore.QuadPart) * 1000 / nFreq.QuadPart);
      
      if(dwTime >= TIME_LIMIT){
        if(PRINT == 1)printf("タイムアップ: %dミリ秒\n", dwTime);
        return -2;
      }
      
      if(check_koma(map, k, y, x) == 1){
        put_koma(map, k, y, x);
        break;
      }
    }
  }
  
  return 1;
}

// ゲーム1回の流れ
int play_game(int map[10][10], int f){
  void (*sente_ai)(int, int *, int *);
  void (*gote_ai)(int, int *, int *);
  
  if(f == KURO){
    sente_ai = ai1;
    gote_ai = ai2;
  }
  else if(f == SIRO){
    sente_ai = ai2;
    gote_ai = ai1;
  }
  
  if(PRINT == 1)print_map(map, f);
  
  int pass_count = 0; // パスした回数をカウント
  
  for(;;){
    int res1 = turn(map, KURO, sente_ai);
    
    if(res1 == -1){
      pass_count++;
    }
    else if(res1 == -2){
      if(f == KURO){
        printf("時間切れ:%s の勝ち %s の負け。\n", AI2_NAME, AI1_NAME);
        return -2;
      }
      else if(f == SIRO){
        printf("時間切れ:%s の勝ち %s の負け。\n", AI1_NAME, AI2_NAME);
        return 2;
      }
    }
    else{
      pass_count = 0;
    }
    
    if(PRINT == 1)print_map(map, f);
    
    if(pass_count == 2 || count_point(map, 0) == 0){
      break;
    }
    
    int res2 = turn(map, SIRO, gote_ai);
    
    if(res2 == -1){
      pass_count++;
    }
    else if(res2 == -2){
      if(f == SIRO){
        printf("                                %s の勝ち(時間切れ)。\n", AI2_NAME);
        return -2;
      }
      else if(f == KURO){
     printf("%s の勝ち(時間切れ)。\n", AI1_NAME);
        return 2;
      }
    }
    else{
      pass_count = 0;
    }
    
    if(PRINT == 1)print_map(map, f);
    
    if(pass_count == 2 || count_point(map, 0) == 0){
      break;
    }
  }
  
  int siro = count_point(map, SIRO);
  int kuro = count_point(map, KURO);
  
  if(PRINT == 1)printf("○:%d ●:%d ", kuro, siro);
  
  if ((f == SIRO && siro > kuro) || (f == KURO && siro < kuro)){
    printf("%s の勝ち。\n", AI1_NAME);
    return 1;
  }
  else if((f == SIRO && siro < kuro) || (f == KURO && siro > kuro)){
    printf("                                %s の勝ち。\n", AI2_NAME);
    return -1;
  }
  else{
    printf("                    引き分け。\n");
    return 0;
  }
}

int main(){
  int map[10][10];

  srand((unsigned)time(NULL));
  
  set_map(map);
  
  int ai1_point = 0;
  int ai2_point = 0;
  int ai1_time_up = 0;
  int ai2_time_up = 0;
  int draw = 0;
  
  for(int i = 0; i < MATCH; i++){
    init_map(map);
    
    printf("%03d回:", i+1);
    
    int res = play_game(map, i % 2 + 1);
    if(res == 2){
      ai1_point++;
      ai2_time_up++;
    }
    else if(res == 1){
      ai1_point++;
    }
    else if(res == -1){
      ai2_point++;
    }
    else if(res == -2){
      ai2_point++;
      ai1_time_up++;
    }
    else{
      draw++;
    }
  }
  
  printf("\n%s %d勝 %s %d勝 引き分け %d\n", AI1_NAME, ai1_point, AI2_NAME, ai2_point, draw);
  printf("タイムアップ:%s %d回 %s %d回\n", AI1_NAME, ai1_time_up, AI2_NAME, ai2_time_up);
  
  return 0;
}

inserted by FC2 system