C言語で制作したオセロゲームのソースコード【保存版】

## はじめに
この記事は下記の記事を一度ご覧になってからの閲覧を推奨しています。
[C言語で制作したオセロゲームの概要【保存版】](https://qiita.com/red-0803/items/1e0a0a97970754098645)

## 各関数の引数、返り値、機能
```c++
int
count_whiteStones(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS])
```
• 引数 : 盤面全体を示す配列の先頭アドレス
• 返り値 : 白石の数
• 機能 : 盤面上の白石の数のカウントする
<br/>

```c++
int
display_situation(int win, int white, int black)
```
• 引数 : ウィンド識別子
        白石の数
        黒石の数
• 返り値 : 0
• 機能 : 盤面上の戦況を表示する
<br/>

```c++
int
isBoundary(int status)
```
• 引数 : 石の有無
        石の色
        境界となる空き要素か
• 返り値 : 石があれば0, なければ1
• 機能 : 石を置こうとしている要素は，空白でかつ境界かを判定し、そうでなければ
適切な文章を印字する
<br/>

```c++
int
lookAround_directions(int win, 
		              struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
		              struct element *element,
		              int stone)
```
• 引数 : ウィンド識別子
        盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : 相手の石を挟んでいる方向の数
• 機能 : element に置かれた石の周りの方向を調べる
<br/>

```c++
int
canTurnOver(int win, 
	        struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
	        struct element *element,
	        int way,
	        int stone) 
```
• 引数 : ウィンド識別子
        盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        挟めるかを調べる方向(上が0 で，時計回りに7 までの8 方向)
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : 獲得できれば1, できなければ0
• 機能 : 指定された方向でelement 上の石を獲得できるかを調べる
<br/>

```c++
int
doesAnyOtherPinch(int win,
		          struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
		          struct element *element,
		          int stone)
```
• 引数 : ウィンド識別子
        盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : 候補要素が相手を挟んでいれば1, 候補要素がなければ0
• 機能 : 候補要素があればその要素が相手を挟んでいるのか判断する
<br/>

```c++
int
doesCandidatePinch(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
		           struct element *candidate, 
		           int stone)
```
• 引数 : 盤面全体を示す配列の先頭アドレス
        要素が相手を挟むかどうか
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : すべての候補者が相手を挟んでいなければ0, 挟んでいれば1
• 機能 : 候補要素が相手の石を挟めるかを調べる
<br/>

```c++
int
isPinching(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
	       struct element *element,
	       int way,
	       int stone)
```
• 引数 : 盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        挟めるかを調べる方向(上が0 で，時計回りに7 までの8 方向)
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : 隣接する要素を挟んでいなければ0, 挟んでいれば1, 相手の色の石ならisPinching
• 機能 : 指定された方向で相手の石を挟んでいるかを調べる
<br/>

```c++
int
place_stone(int win,
	        struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
	        struct element *element,
	        int stone)
```
• 引数 : 盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        自分の石(この色の石でelement にある石を挟むめるか調べる)
• 返り値 : 0
• 機能 : 指定された要素に石を置く
<br/>

```c++
struct element *
get_adjacent(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
	         struct element *element,
	         int way)
```
• 引数 : 盤面全体を示す配列の先頭アドレス
        石を置こうとしている要素のアドレス
        挟めるかを調べる方向(上が0 で，時計回りに7 までの8 方向)
• 返り値 : 盤の内側なら隣接要素のアドレス，盤外ならNULL
• 機能 : 指定された要素の隣の要素
<br/>

```c++
int initialize_element(int win, struct element *element)
```
• 引数 : ウィンド識別子
        石を置こうとしている要素のアドレス
• 返り値 : 0
• 機能 : 要素の初期化を行う
<br/>

```c++
int paint_element(int win, struct element *element, int color)
```
• 引数 : ウィンド識別子
        石を置こうとしている要素のアドレス
        石の色
• 返り値 : 0
• 機能 : 指定された要素の石に色を塗る
<br/>

```c++
int
display_message(int win,
		        char *message)
```
• 引数 : ウィンド識別子
         盤面上に表示するメッセージの文字列
• 返り値 : 0
• 機能 : 盤面上に劣勢である側に応援メッセージを表示する

## ソースコード

```c++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <eggx.h>

#define ELEMENT_SIZE (100)
#define NUM_OF_ELEMENTS (8)
#define FIELD_SIZE (ELEMENT_SIZE * NUM_OF_ELEMENTS)
#define MESSAGE_SIZE (50)
#define MAX_MESSAGE (64)
#define BIG_LOSS (3)
#define ROTATE_DIRECTION (1)

#define BLACK (0)
#define WHITE (1)
#define GREEN (3)

#define VACANT (0x00)
#define WHITE_STONE (0x01)
#define BLACK_STONE (0x02)
#define STONE_BITS (0x03)
#define BOUNDARY_BIT (0x04)
#define STONE_INVERSION (STONE_BITS)
#define NUM_OF_DIRECTIONS (8)
#define MAX_MARGINE (NUM_OF_ELEMENTS * NUM_OF_ELEMENTS)

struct location {
 int row;
 int column;
};

struct element {
 struct location location;
 int status;
};

int count_whiteStones(struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS]);
int display_situation(int, int, int);
int isBoundary(int);
int lookAround_directions(int, struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int);
int canTurnOver(int, struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int way, int);
int doesAnyOtherPinch(int, struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int);
int doesCandidatePinch(struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int);
int isPinching(struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int, int);
int place_stone(int, struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int);
struct element *get_adjacent(struct element [NUM_OF_ELEMENTS][NUM_OF_ELEMENTS], struct element *, int);
int initialize_element(int, struct element *);
int paint_element(int, struct element *, int);
int display_message(int, char *);

int
main()
{
   struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS];
   int win;
   int row, column, position;
   int stone;
   struct element *element;
   int availables;
   int white_stones;
   int black_stones;
   char buffer[MAX_MESSAGE];

   win = gopen(FIELD_SIZE,FIELD_SIZE + MESSAGE_SIZE);
   layer(win, 0,1);
   gsetbgcolor(win,"GREEN") ;
   gclr(win) ;

   for(row = 0; row < NUM_OF_ELEMENTS; row++) {
     for(column = 0; column < NUM_OF_ELEMENTS; column++) {
        element = mesh[row] + column;
        element->status = VACANT;
        element->location.row = row;
        element->location.column = column;
        initialize_element(win, element);
     }
   }


   column = NUM_OF_ELEMENTS/2 - 1;
   row = NUM_OF_ELEMENTS/2 - 1;
   element = &mesh[row][column];
   place_stone(win,mesh,element,WHITE_STONE);

   column++;
   element = &mesh[row][column];
   place_stone(win,mesh,element,BLACK_STONE);

   row++;
   element = &mesh[row][column];
   place_stone(win,mesh,element,WHITE_STONE);

   column--;
   element = &mesh[row][column];
   place_stone(win,mesh,element,BLACK_STONE);

   availables = NUM_OF_ELEMENTS * NUM_OF_ELEMENTS - 4;
   white_stones = 2;
   black_stones = 2;
   display_situation(win, white_stones, black_stones);


   stone = BLACK_STONE;
   while(availables > 0) {
     if(stone == BLACK_STONE)
        printf("次は黒です．");
     else
        printf("次は白です．");
     printf("どこに置きますか? ");
     fgets(buffer, MAX_MESSAGE - 1, stdin);
     position = atoi(buffer);
     row = position / 10;
     column = position % 10;
     if((row < 0) || (row > NUM_OF_ELEMENTS -1) ||
         (column < 0) || (column > NUM_OF_ELEMENTS - 1)) {
        printf("そのようなマスはありません．\n");
        continue;
     }

     element = &mesh[row][column];
     if(isBoundary(element->status) == 0) {
        printf("ここには置けません．\n");
        continue;
     }

     if(doesAnyOtherPinch(win, mesh, element, stone) == 0){
       if(doesCandidatePinch(mesh, element, stone) == 0) {
       printf("置けるマスがありません．パスします．\n");
       stone ^= STONE_INVERSION;
       continue;
       }
     }
     if(doesCandidatePinch(mesh, element, stone) == 0) {
       printf("この位置には置けません．得点できるマスが他にあります．\n");
       continue;
     }
     lookAround_directions(win, mesh, element, stone);

     place_stone(win,mesh,element,stone);
     availables--;

     white_stones = count_whiteStones(mesh);
     black_stones = NUM_OF_ELEMENTS * NUM_OF_ELEMENTS - availables - white_stones;

     display_situation(win, white_stones, black_stones);

     if(white_stones==0){
       printf("黒の勝ちです．\n");
       break;
     }
     if(black_stones==0){
       printf("白の勝ちです．\n");
       break;
     }
     stone ^= STONE_INVERSION;
   }
   printf("黒は%d,白は%dによって",black_stones, white_stones);
   if(black_stones == white_stones){
     printf("引き分けです");
   }else if(black_stones<white_stones){
     printf("白の勝利です");
   }else{
     printf("黒の勝利です");
   }
   printf("終了です．盤面を消します[OK]");
   fgets(buffer, MAX_MESSAGE -1, stdin);

   gclose(win);
   return 0;
}

int
count_whiteStones(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS])
{
 int count = 0;
 int i, j;

 for(i = 0; i < NUM_OF_ELEMENTS; i++)
   for(j = 0; j < NUM_OF_ELEMENTS; j++)
     if(mesh[i][j].status & WHITE_STONE)
        count++;
 return count;
}

int
display_situation(int win, int white, int black)
{
 char message[MAX_MESSAGE * 2];
 char situation[MAX_MESSAGE];


 sprintf(situation, "white: %d,   black: %d   ", white, black);
 strcpy(message, situation);
 display_message(win, message);

 return 0;
}

int
isBoundary(int status)
{
 if((status & STONE_BITS) > 0) {
   printf("そのマスには石が置かれています\n");
   return 0;
 } else if((status & BOUNDARY_BIT) == 0) {
   printf("離れたマスです\n");
   return 0;
 } else
   return 1;
}

int
lookAround_directions(int win,
                      struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
                      struct element *element,
                      int stone)
{
 int way;
 int adjacent_stone;
 struct element *adjacent;
 int result = 0;


 for(way = 0; way < NUM_OF_DIRECTIONS; way++) {

   adjacent = get_adjacent(mesh, element, way);
   if(adjacent == NULL) continue;

   adjacent_stone = adjacent->status & STONE_BITS;
   if(adjacent_stone == VACANT)
     continue;
   else if(adjacent_stone ^ stone) {
     if(canTurnOver(win, mesh, adjacent, way, stone) == 1) {
        place_stone(win,mesh,adjacent, stone);
        result++;
     }
   }
 }

 return result;
}

int
canTurnOver(int win,
            struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
            struct element *element,
            int way,
            int stone)
{
 struct element *adjacent;

 adjacent = get_adjacent(mesh, element, way);
 if(adjacent == NULL)
   return 0;

 if((adjacent->status & STONE_BITS) == VACANT) {
   return 0;
 } else if((adjacent->status & STONE_BITS) == stone) {
   place_stone(win, mesh, element, stone);
   return 1;
 } else {
   if(canTurnOver(win, mesh, adjacent, way, stone)) {
     place_stone(win, mesh, element, stone);
     return 1;
   } else
     return 0;
 }
}

int
doesAnyOtherPinch(int win,
                  struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
                  struct element *element,
                  int stone)
{
 int i, j;
 struct element *candidate;
 for(i = 0; i < NUM_OF_ELEMENTS; i++) {
   for(j = 0; j < NUM_OF_ELEMENTS; j++) {
     if((i == element->location.row) && (j == element->location.column))
        continue;
     candidate = &mesh[i][j];
     if(candidate->status & BOUNDARY_BIT) {
        if(doesCandidatePinch(mesh, candidate, stone) == 1)
          return 1;
     }
   }
 }
 return 0;
}

int
doesCandidatePinch(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
                   struct element *candidate,
                   int stone)
{
 int way;
 int adjacent_stone;
 struct element *adjacent;

 for(way = 0; way < NUM_OF_DIRECTIONS; way++) {
   adjacent = get_adjacent(mesh, candidate, way);
   if(adjacent == NULL) continue;

   adjacent_stone = adjacent->status & STONE_BITS;
   if(adjacent_stone == VACANT)
     continue;
   if((adjacent->status & STONE_BITS) ^ stone) {
     if(isPinching(mesh, adjacent, way, stone) == 1) {
        return 1;
     }
   }
 }

 return 0;
}

int
isPinching(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
           struct element *element,
           int way,
           int stone)
{
 struct element *adjacent;

 adjacent = get_adjacent(mesh, element, way);
 if(adjacent == NULL)
   return 0;

 if((adjacent->status & STONE_BITS) == VACANT) {
   return 0;
 } else if((adjacent->status & STONE_BITS) == stone) {
   return 1;
 } else {
   return isPinching(mesh, adjacent, way, stone);
 }
}

int
place_stone(int win,
            struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
            struct element *element,
            int stone)
{
 int way;
 struct element *adjacent;
 int color;

 element->status = stone;

 if(stone == WHITE_STONE)
   color = WHITE;
 else
   color = BLACK;
 paint_element(win, element, color);

 for(way = 0; way < NUM_OF_DIRECTIONS; way++) {
   adjacent = get_adjacent(mesh, element, way);
   if(adjacent == NULL) continue;

   if(adjacent->status == VACANT)
     adjacent->status = BOUNDARY_BIT;
 }

 return 0;
}

struct element *
get_adjacent(struct element mesh[NUM_OF_ELEMENTS][NUM_OF_ELEMENTS],
             struct element *element,
             int way)
{
 struct element *adjacent;
 int row, column;
 int row_vector=0, column_vector=0;

 switch(way) {
 case 0: row_vector = 1; column_vector = 0; break;
 case 1: row_vector = 1; column_vector = 1; break;
 case 2: row_vector = 0; column_vector = 1; break;
 case 3: row_vector = -1; column_vector = 1; break;
 case 4: row_vector = -1; column_vector = 0;  break;
 case 5: row_vector = -1; column_vector = -1; break;
 case 6: row_vector = 0; column_vector = -1; break;
 case 7: row_vector = 1; column_vector = -1; break;
 default: break;
 }

 row = element->location.row + row_vector;
 column = element->location.column + column_vector;

 if((row < 0) || (row > NUM_OF_ELEMENTS - 1))
   return (struct element *)NULL;
 if((column < 0) || (column > NUM_OF_ELEMENTS - 1))
   return (struct element *)NULL;

 adjacent = mesh[row] + column;
 return adjacent;
}

int initialize_element(int win, struct element *element)
{
 float x, y;
 float edge=0;
 int row = element->location.row;
 int column = element->location.column;

 x = column * (float)ELEMENT_SIZE;
 y = row * (float)ELEMENT_SIZE;

 newpen(win, BLACK);
 edge = (float)ELEMENT_SIZE;
 drawrect(win,x,y, edge, edge);

 drawstr(win, x+1, y+1, 8, 0.0, "%d%d",row, column);

 return 0;
}

int paint_element(int win, struct element *element, int color)
{
 float x, y;
 float center_x=0, center_y=0;
 float edge=(float )ELEMENT_SIZE;
 float radian;
 float start_angle = 0.0;
 float end_angle = 0.0;
 int row = element->location.row;
 int column = element->location.column;

 x = column * (float)ELEMENT_SIZE;
 y = row * (float)ELEMENT_SIZE;

 newpen(win, color);
 center_x = x + edge/2.0; center_y = y + edge/2.0;
 radian = edge/2.0 - 1;
 start_angle = 0.0; end_angle = 360.0;
 fillarc(win, center_x, center_y, radian, radian,
          start_angle, end_angle, ROTATE_DIRECTION);

 return 0;
}

int
display_message(int win,
                char *message)
{
 float x, y;

 x = 0;
 y = (float)ELEMENT_SIZE * NUM_OF_ELEMENTS;

 newpen(win, GREEN);
 fillrect(win, x, y, ELEMENT_SIZE * NUM_OF_ELEMENTS, MESSAGE_SIZE);

 newpen(win, BLACK);
 drawrect(win, x, y, ELEMENT_SIZE * NUM_OF_ELEMENTS, MESSAGE_SIZE);

 x += (float)ELEMENT_SIZE / 2;
 y += (float)MESSAGE_SIZE / 3;
 drawstr(win, x, y, 16, 0.0, "%s", message);

 copylayer(win, 1, 0);

 return 0;
}

```

## コンパイルと実行
```
HOME=/Users/ホームの名前

All:ファイル名

ファイル名:ファイル名.c
	gcc -g -Wall ファイル名.c -o ファイル名 -I$(HOME)/eggx -L$(HOME)/eggx -leggx -lX11 -lm -L/opt/X11/lib
```
コンパイルは上記のようなMakefileを作成しておくと便利です。日本語のところをご自身のものに書き換えてください。
このファイルを置く場所はc言語のファイルと同じ場所にです。
![コンパイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327727/e2b550c2-a609-53ff-d8ae-71ba3f3c5ba0.png)
Makefileを制作しておくと"make"と入力するだけでコンパイルできます。
![実行.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327727/2067db60-5274-03ed-d6fc-95e09ea3c8be.png)
実行は"./ファイル名"で実行可能です。

## 最後に
コードはご自由にご利用ください。
ただ、そのままのコードを第三者に公開することはご遠慮ください。

質問などはしていただければ、可能な範囲で答えます。