ホームに戻る
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;
}