ホームに戻る
 C言語でリバーシ

bcc32用のC言語で書いたコンソールで動くリバーシです。
敵アルゴリズムを変更しやすいように上のほうに書きました。
以下のソースの敵アルゴリズムは「置けるところにランダム」です。

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

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

int get(int map[10][10], int y, int x);
int check_koma(int map[10][10], int k, int y, int x);

// 敵のアルゴリズムの初期化
void init_teki_ai(int map[10][10]){
  srand((unsigned)time(NULL));
}

// 敵のアルゴリズム
void teki_ai(int map[10][10], int k, int *py, int *px){
  // k は自分のコマであり if(k == KURO) で確認できます。
  // コマ情報は get(map, y, x) で得ることができます。
  // 何も置いていない:0 白いコマ:SIRO 黒いコマ:KURO
  // コマが置けるかを if(check_koma(map, 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_koma(map, 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_koma(map, k, y, x) == 1){
        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 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 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];
    }
  }
}

// 盤の 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]){
  static char *c = "ABCDEFGH";
  static char *r = "123456789";
  
  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");
  }
}

// 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);
}

// 現在のコマと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 select_first_player(){
  int c;
  int first_player = 0;
  
  for(;;){
    printf(">");
    
    c = fgetc(stdin);
    
    if(c == '2'){
      first_player = SIRO;
    }
    else if(c == '1'){
      first_player = KURO;
    }
    
    for(;;){
      c = fgetc(stdin);
      
      if(c == '\n'){
        break;
      }
    }
    
    if(first_player != 0){
      break;
    }
  }
  
  return first_player;
}

// 位置の入力
void input_point(int k, int *py, int *px){
  int c;
  int cy, cx;
  
  for(;;){
    cx = -1;
    cy = -1;
    
    if(k == SIRO){
      printf("●>");
    }
    else if(k == KURO){
      printf("○>");
    }
    
    c = fgetc(stdin);
    
    if(c >= '1' && c <= '8'){
      cy = c - '1';
    }
    
    c = fgetc(stdin);
    
    if(c >= 'a' && c <= 'h'){
      cx = c - 'a';
    }
    
    if(c >= 'A' && c <= 'H'){
      cx = c - 'A';
    }
    
    for(;;){
      c = fgetc(stdin);
      
      if(c == '\n'){
        break;
      }
    }
    
    if(cx >= 0 && cx < 8 && cy >= 0 && cy < 8){
      break;
    }
  }
  
  *px = cx;
  *py = cy;
}

// 置く場所が無かった場合の処理
void no_point(int k){
  if(k == SIRO){
    printf("●を置く場所がありません。");
  }
  else if(k == KURO){
    printf("○を置く場所がありません。");
  }
  
  int c = getc(stdin);
  
  for(;;){
    if(c == '\n'){
      break;
    }
    
    c = fgetc(stdin);
  }
}

// 自分のターン
int jibun_turn(int map[10][10], int k){
  int x, y;
  
  if(count_enable_point(map, k) == 0){
    no_point(k);
    
    return -1;
  }
  else{
    for(;;){
      printf("どこに置きますか?(例:3d)\n");
      input_point(k, &y, &x);
      if(check_koma(map, k, y, x) == 1){
        put_koma(map, k, y, x);
        break;
      }
      else{
        printf("そこには置けません。\n");
        print_map(map);
      }
    }
  }
  
  return 1;
}

// 敵ターン
int teki_turn(int map[10][10], int k){
  if(count_enable_point(map, k) == 0){
    no_point(k);
    
    return -1;
  }
  else{
    int y, x;
    teki_ai(map, k, &y, &x);
    put_koma(map, k, y, x);
    if(k == SIRO){
      printf("●>%c%c\n", y + '1', x + 'a');
    }
    else if(k == KURO){
      printf("○>%c%c\n", y + '1', x + 'a');
    }
  }
  
  return 1;
}

// ゲーム1回の流れ
void play_game(int map[10][10]){
  int (*sente_turn)(int map[10][10], int k);
  int (*gote_turn)(int map[10][10], int k);
  
  printf("あなたは先手ですか?後手ですか?\n");
  printf("1:先手\n");
  printf("2:後手\n");
  
  // 先手、後手を入力で得る f = 1 先手 f = 2 後手
  int f = select_first_player();
  
  if(f == KURO){
    printf("あなたは先手○です。\n");
    sente_turn = jibun_turn;
    gote_turn = teki_turn;
  }
  else if(f == SIRO){
    printf("あなたは後手●です。\n");
    sente_turn = teki_turn;
    gote_turn = jibun_turn;
  }
  
  print_map(map);
  
  int pass_count = 0; // パスした回数をカウント
  
  for(;;){
    if(sente_turn(map, KURO) == -1){
      pass_count++;
    }
    else{
      pass_count = 0;
    }
    
    print_map(map);
    
    if(pass_count == 2 || count_point(map, 0) == 0){
      break;
    }
    
    if(gote_turn(map, SIRO) == -1){
      pass_count++;
    }
    else{
      pass_count = 0;
    }
    
    print_map(map);
    
    if(pass_count == 2 || count_point(map, 0) == 0){
      break;
    }
  }
  
  int siro = count_point(map, SIRO);
  int kuro = count_point(map, KURO);
  
  printf("○:%d ●:%d\n", kuro, siro);
  
  if ((f == SIRO && siro > kuro) || (f == KURO && siro < kuro)){
    printf("あなたの勝ち。\n");
  }
  else if((f == SIRO && siro < kuro) || (f == KURO && siro > kuro)){
    printf("あなたの負け。\n");
  }
  else{
    printf("引き分け。\n");
  }
}

int main(){
  int map[10][10];
  
  init_map(map);
  
  init_teki_ai(map);
  
  play_game(map);
  
  return 0;
}

inserted by FC2 system