Download : sample-001.c ( SJIS 版 )
#
# adddate.m4 (20141128) created by /home/kurino/bin/MkAddDateM4.sh
#
/*
* 2014/11/28 sample-001.c
*/
/*
* フラグ
*
* 利用方法
* コンパイル
* cc -Ic:\usr\c\include -o BASENAME.exe sample-001.c
* 実行
* BASENAME
*/
#include <stdio.h>
/*
* trump
* トランプの番号から、その名前を表示する
*/
void trump ( int number ) {
if ( number == 1 ) { /* 番号が 1 なら */
printf ( "エース\n" );
} else {
printf ( "範囲外です\n" );
}
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
trump ( 1 );
trump ( 20 );
return 0;
}
C:\usr\c>sample-001 C:\usr\c>
v11
/*
* board.c
*/
#include <stdio.h>
/* 表示の部分 */
/*
print_board : 与えらたボードデータを表示する
<<ポイント>>
配列の引数には特殊事情がある : 後回し
*/
void print_board ( char board[8][8] ) {
int tate; /* 縦の添字 */ /* 追加(Copy) */
int yoko; /* 横の添字 */
/* 表示機能 (移動) */
/* ボードの内容を出力する */
/* 8x8 の内容を全て出力(標準出力)すればよい */
/* 配列の出力 -> for 文でやればよい */
/* 二次元配列なので、二重ループになる */
/*
A B C D E F G H
\yoko 0 1 2 3 4 5 6 7
tate 1 0 +---->
2 1 |
3 2 v
4 3
5 4
6 5
7 6
8 7
*/
printf ( " A B C D E F G H\n" );
printf ( " ┏━┳━┳━┳━┳━┳━┳━┳━┓\n" );
for ( tate = 0; tate < 8; tate++ ) {
printf ( "%d ┃", tate + 1 ); /* 左の、この行の枠 */
for ( yoko = 0; yoko < 8; yoko++ ) {
if ( board[tate][yoko] == ' ') { /* 空き */
printf ( " " );
} else if ( board[tate][yoko] == 'o') { /* 白 */
printf ( "◯" );
} else /* if board[tate][yoko] == 'x') */ { /* 黒 */
printf ( "●" );
}
printf ( "┃" ); /* コマとコマの間の枠 */
}
printf ( "\n" ); /* 改行 */
if ( tate < 8 - 1 ) { /* 最後は、これを使わない */
printf ( " ┣━╋━╋━╋━╋━╋━╋━╋━┫\n" );
} else { /* 最後の行に使うのはこれ */
printf ( " ┗━┻━┻━┻━┻━┻━┻━┻━┛\n" );
}
}
}
/*
* 初期化
*/
void init_board( char board[8][8] ) {
int tate; /* 縦の添字 */
int yoko; /* 横の添字 */
/* ゲーム盤の初期化 */
/* とりあえず、全部 ' ' にして、後から真ん中の4つを置く */
/* とりあえず、全部空白 */
for ( tate = 0; tate < 8; tate++ ) {
for ( yoko = 0; yoko < 8; yoko++ ) {
board[tate][yoko] = ' '; /* 全ての場所を空白に */
}
}
/* 真ん中の 4 つだけ特別処理 */
board[3][3] = 'o'; /* D4 なので白 */
board[4][4] = 'o'; /* E5 なので白 */
board[3][4] = '*'; /* D5 なので黒 */
board[4][3] = '*'; /* E4 なので黒 */
}
/*
* othello v10 (2014/11/14) の main.c
*/
#include <stdio.h>
/*
* main
*/
int main(int argc, char *argv[]) {
char board[8][8]; /* ゲームボード */
char yoko; /* 横の記号 'A' 〜 'F' */
char tate; /* 縦の記号 '1' 〜 '8' */
char color; /* 色の記号 '*' : 黒 / 'o' : 白 */
init_board ( board ); /* 引数に配列名しか指定しない */
print_board ( board ); /* 引数に配列名しか指定しない */
while ( 0 < 1 ) {
printf ( "次の一手> " );
/* ここで入力をする */
/* キーボードから 「A2*<改行>」とされた事を想定 */
yoko = getchar(); /* 横の指定の一文字 'A' を入力 */
if ( yoko == 'Z' ) { /* 'Z' が入ったら.. */
printf ( "プログラムを終了します...\n" );
return 0; /* プログラムを終了 */
}
tate = getchar(); /* 縦の指定の一文字 '2' を入力 */
color = getchar(); /* 色の記号 '*' を入力 */
getchar(); /* 改行を読み飛ばす */
printf ( "着手 (%c,%c) %c ", yoko, tate, color );
if ( check_sandwich_all_direct ( board, yoko, tate, color ) ) {
printf ( "置く事ができます。\n" );
} else {
printf ( "置く事ができません。\n" );
}
/* その結果が反映されているかどうかを確認する */
print_board ( board );
}
return 0;
}
/*
* オセロ盤プログラム (version 10 : 2014/11/14)
*
* 機能
* 初期化の部分
* 表示の部分 : 位置を表す記号 1 〜 8, A 〜 F
* 入力の部分(コマを置いてみたい..)
* 入力の指示はキーボード
* ゲームをしてみたい
* 繰返し入力をする
* 繰返しは while で実現できるが
* いつまで繰り返すか ?
* -> ルールでは、両方パスするまで
* とりあえず、サボって
* 無限に繰り返す事にする
* ( 終了は 'Z' を入れる )
* v8 に向けて
* 着手禁止の所にはうてないようにしたい
* 「着手禁止の所」
* 既にコマがある
* 相手のコマをひっくりかえせない
* 挟んだコマを自動的にコマをひっくりかえして欲い
* ->
* コマを引っくり返す
* 自分のコマで、相手のコマを挟む
* イメージ : 黒で白を挟む
* *oooo* -> ******
* ^ ^
* 元々 打つ手
* 上記の例は打つ手の左の状況
* この他に全部で 8 方向あるので、
* 他の 7 方向も考える
* 取り敢えず、右横方向だけを考える
*
* 右方向の着手チェック
*
*/
#include <stdio.h>
/* ボードを作る */
/* ボードは、8x8 の要素からなる */
/* ボードの一つの要素には 空、黒、白のいずかが入る */
/* 空 ' ' , 白 'o', 黒 '*' -> 一文字 */
/*
'A2' に黒 -> put_board_black ( 'A', '2' )
-> board[1][0] = '*';
*/
char get_board ( char board[8][8], char yoko, char tate ) {
return board[tate-'1'][yoko-'A'];
}
void put_board ( char board[8][8], char yoko, char tate, char color ) {
board[tate-'1'][yoko-'A'] = color;
/* 本当は、ここで tate, yoko, color が正しい値かを
チェックする必要がある (後回し)
*/
}
void put_board_black ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, '*' );
/*
put_board_black ( 'A', '2' )
->
board['2'-'1']['A'-'A'] = '*';
->
board[1][0] = '*';
*/
}
void put_board_white ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, 'o' );
}
/*
* oposit ( char color )
* 自分の色を指定して、相手の色を返す
* '*' -> 'o'
* 'o' -> '*'
*/
char oposit ( char color ) {
/*
if ( color == '*' ) {
return 'o';
} else if ( color == 'o' ) {
return '*';
}
*/
return 'o' + '*' - color;
}
/*
横方向のチェックを行う
*/
int check_yoko ( char yoko ) {
if ( yoko <= 'F' ) {
if ( 'A' <= yoko ) {
return 1; /* 'A' <= yoko <= 'F' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
/*
横方向のチェックを行う
*/
int check_tate ( char tate ) {
if ( tate <= '8' ) {
if ( '1' <= tate ) {
return 1; /* '1' <= tate <= '8' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
int check_play ( char yoko, char tate ) {
if ( check_yoko ( yoko ) ) {
if ( check_tate ( tate ) ) {
return 1;
}
}
return 0;
}
int check_sandwich_play_direct_sub ( char board[8][8], char yoko, char \
tate, char color, char ocolor, int ydir, int tdir ) {
yoko = yoko + ydir;
tate = tate + tdir;
if ( check_play ( yoko, tate ) ) { /*右も左両方*/
if ( get_board ( board, yoko, tate ) == color ) {
return 1;
} else if ( get_board ( board, yoko, tate ) == ocolor ) {
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
}
}
return 0;
}
/*
* check_sandwich_play_direct ( char board[8][8], char yoko, char tate, char \
color )
*
* P : 現在のゲーム盤 (board) の状態で、(yoko,tate) に color のコマが置けるかどうか ?
* 置けたら 1 (0 以外 : C 言語の「真」) / 置けない場合は 0 (C 言語の「偽」)
*/
int check_sandwich_play_direct ( char board[8][8], char yoko, char tate, \
char color, int ydir, int tdir ) {
/* 「置ける」条件 */
if ( get_board ( board, yoko, tate ) == ' ' ) {
/* まず、そこに他のコマがない事を確認 */
yoko = yoko + ydir; /* 一つ横にずらす */
tate = tate + tdir; /* 一つ横にずらす */
if ( check_play ( yoko, tate ) ) { /* 盤外でない事を確認 */
char ocolor = oposit ( color ); /* 相手の色を入手 */
/* color == 'o' -> '*', color == '*' -> 'o' */
if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 一つ右が相手の色である事を確認 */
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
/* 後は Q に任せる */
}
}
}
return 0; /* どれかの条件が不成立なら、全体として不成立 (偽:0) を返す */
}
int check_sandwich_all_direct ( char board[8][8], char yoko, char tate, \
char color ) {
int ydir;
int tdir;
for ( ydir = -1; ydir <= 1; ydir++ ) {
for ( tdir = -1; tdir <= 1; tdir++ ) {
if ( tate * tate + yoko * yoko != 0 ) {
/* tate = yoko = 0 の時だけ不成立 */
if ( check_sandwich_play_direct ( board, yoko, tate, color, ydir, tdir ) \
) {
return 1;
}
}
}
}
return 0;
}
# # v11 の makefile # # - makefile の基本的な構造 # -- rule の集合 # -- rule の書き方 # 作りたい物 : 材料 # <TAB> 作り方 # # rule の意味 # 「作りたい物」が作りたければ「材料」を利用して、「作り方」を実行する # 材料がなければ、材料も作ろうとする !! # # - make コマンドの実行 # make で引数を指定しなければ、最初のルールを実行しようとする # 引数(作りたい物)が指定されると、指定された物を作ろうとする # <ポイント> # 既に、作りたいものが存在して、材料より新しいなら、何もしない # 作りたいものがないか、材料より古いならば、作り直す # 作り方をしらない物が材料に指定されていても、「それがあれば」よい # 材料がなく、作り方もしらないとエラーになる # # board.c 系列がふえた.. # othello.exe : othello.o main.o board.o cc -o othello.exe othello.o main.o board.o othello.o : othello.c cc -c othello.c main.o : main.c cc -c main.c board.o : board.c cc -c board.c clean : rm *.o *.exe makezip : zip v11.zip makefile main.c othello.c board.c
v12
/*
* board.c
*/
#include <stdio.h>
/* 表示の部分 */
/*
print_board : 与えらたボードデータを表示する
<<ポイント>>
配列の引数には特殊事情がある : 後回し
*/
void print_board ( char board[8][8] ) {
int tate; /* 縦の添字 */ /* 追加(Copy) */
int yoko; /* 横の添字 */
/* 表示機能 (移動) */
/* ボードの内容を出力する */
/* 8x8 の内容を全て出力(標準出力)すればよい */
/* 配列の出力 -> for 文でやればよい */
/* 二次元配列なので、二重ループになる */
/*
A B C D E F G H
\yoko 0 1 2 3 4 5 6 7
tate 1 0 +---->
2 1 |
3 2 v
4 3
5 4
6 5
7 6
8 7
*/
printf ( " A B C D E F G H\n" );
printf ( " ┏━┳━┳━┳━┳━┳━┳━┳━┓\n" );
for ( tate = 0; tate < 8; tate++ ) {
printf ( "%d ┃", tate + 1 ); /* 左の、この行の枠 */
for ( yoko = 0; yoko < 8; yoko++ ) {
if ( board[tate][yoko] == ' ') { /* 空き */
printf ( " " );
} else if ( board[tate][yoko] == 'o') { /* 白 */
printf ( "◯" );
} else /* if board[tate][yoko] == 'x') */ { /* 黒 */
printf ( "●" );
}
printf ( "┃" ); /* コマとコマの間の枠 */
}
printf ( "\n" ); /* 改行 */
if ( tate < 8 - 1 ) { /* 最後は、これを使わない */
printf ( " ┣━╋━╋━╋━╋━╋━╋━╋━┫\n" );
} else { /* 最後の行に使うのはこれ */
printf ( " ┗━┻━┻━┻━┻━┻━┻━┻━┛\n" );
}
}
}
/*
* 初期化
*/
void init_board( char board[8][8] ) {
int tate; /* 縦の添字 */
int yoko; /* 横の添字 */
/* ゲーム盤の初期化 */
/* とりあえず、全部 ' ' にして、後から真ん中の4つを置く */
/* とりあえず、全部空白 */
for ( tate = 0; tate < 8; tate++ ) {
for ( yoko = 0; yoko < 8; yoko++ ) {
board[tate][yoko] = ' '; /* 全ての場所を空白に */
}
}
/* 真ん中の 4 つだけ特別処理 */
board[3][3] = 'o'; /* D4 なので白 */
board[4][4] = 'o'; /* E5 なので白 */
board[3][4] = '*'; /* D5 なので黒 */
board[4][3] = '*'; /* E4 なので黒 */
}
/*
* othello v10 (2014/11/14) の main.c
*/
#include <stdio.h>
/*
* main
*/
int main(int argc, char *argv[]) {
char board[8][8]; /* ゲームボード */
char yoko; /* 横の記号 'A' 〜 'F' */
char tate; /* 縦の記号 '1' 〜 '8' */
char color; /* 色の記号 '*' : 黒 / 'o' : 白 */
init_board ( board ); /* 引数に配列名しか指定しない */
print_board ( board ); /* 引数に配列名しか指定しない */
while ( 0 < 1 ) {
printf ( "次の一手> " );
/* ここで入力をする */
if ( color == '* ' ) { /* 人間の手順 */
/* キーボードから 「A2*<改行>」とされた事を想定 */
yoko = getchar(); /* 横の指定の一文字 'A' を入力 */
if ( yoko == 'Z' ) { /* 'Z' が入ったら.. */
printf ( "プログラムを終了します...\n" );
return 0; /* プログラムを終了 */
}
tate = getchar(); /* 縦の指定の一文字 '2' を入力 */
getchar(); /* 改行を読み飛ばす */
} else { /* コンピュータ */
char result[2]; /* 置く場所を保存する配列 */
if ( computer ( result, board, color ) == 1 ) {
yoko = result[0]; /* 打つ結果を、変数に保存 */
tate = result[1]; /* 打つ結果を、変数に保存 */
/* 配列名を関数に渡すと、関数の中で、配列の要素の値を変更できる */
} else {
printf ( "うてません\n" );
return 0; /* プログラムを終了 */
}
}
printf ( "着手 (%c,%c) %c ", yoko, tate, color );
if ( check_sandwich_all_direct ( board, yoko, tate, color ) ) {
printf ( "置く事ができます。\n" );
/* (v12) 挟んだコマを実際に引っくり返す */
turn_sandwich_all_direct ( board, yoko, tate, color );
/* (v12) そこにコマを置く */
put_board ( board, yoko, tate, color );
} else {
printf ( "置く事ができません。\n" );
}
/* その結果が反映されているかどうかを確認する */
print_board ( board );
}
return 0;
}
/*
* オセロ盤プログラム (version 11 : 2014/11/28)
*
* 機能
* 初期化の部分
* 表示の部分 : 位置を表す記号 1 〜 8, A 〜 F
* 入力の部分(コマを置いてみたい..)
* 入力の指示はキーボード
* ゲームをしてみたい
* 繰返し入力をする
* 繰返しは while で実現できるが
* いつまで繰り返すか ?
* -> ルールでは、両方パスするまで
* とりあえず、サボって
* 無限に繰り返す事にする
* ( 終了は 'Z' を入れる )
* v10 -> v11
* v10 では、8 方向のチェックをした
* 着手禁止のチェックができるようになった
* v11
* 着手できるなら、自動的に挟んだコマをひっくりかえしたい
* 基本はチェックのプログラムが、ほぼ、ひっくりかえしのプログラムと同等
* 「天下り」ですが、チェックの関数を変更してひっくりかえし関数を作る
*/
#include <stdio.h>
/* ボードを作る */
/* ボードは、8x8 の要素からなる */
/* ボードの一つの要素には 空、黒、白のいずかが入る */
/* 空 ' ' , 白 'o', 黒 '*' -> 一文字 */
/*
'A2' に黒 -> put_board_black ( 'A', '2' )
-> board[1][0] = '*';
*/
char get_board ( char board[8][8], char yoko, char tate ) {
return board[tate-'1'][yoko-'A'];
}
void put_board ( char board[8][8], char yoko, char tate, char color ) {
board[tate-'1'][yoko-'A'] = color;
/* 本当は、ここで tate, yoko, color が正しい値かを
チェックする必要がある (後回し)
*/
}
void put_board_black ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, '*' );
/*
put_board_black ( 'A', '2' )
->
board['2'-'1']['A'-'A'] = '*';
->
board[1][0] = '*';
*/
}
void put_board_white ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, 'o' );
}
/*
* oposit ( char color )
* 自分の色を指定して、相手の色を返す
* '*' -> 'o'
* 'o' -> '*'
*/
char oposit ( char color ) {
/*
if ( color == '*' ) {
return 'o';
} else if ( color == 'o' ) {
return '*';
}
*/
return 'o' + '*' - color;
}
/*
横方向のチェックを行う
*/
int check_yoko ( char yoko ) {
if ( yoko <= 'F' ) {
if ( 'A' <= yoko ) {
return 1; /* 'A' <= yoko <= 'F' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
/*
横方向のチェックを行う
*/
int check_tate ( char tate ) {
if ( tate <= '8' ) {
if ( '1' <= tate ) {
return 1; /* '1' <= tate <= '8' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
int check_play ( char yoko, char tate ) {
if ( check_yoko ( yoko ) ) {
if ( check_tate ( tate ) ) {
return 1;
}
}
return 0;
}
int check_sandwich_play_direct_sub ( char board[8][8], char yoko, char \
tate, char color, char ocolor, int ydir, int tdir ) {
yoko = yoko + ydir;
tate = tate + tdir;
if ( check_play ( yoko, tate ) ) { /*右も左両方*/
if ( get_board ( board, yoko, tate ) == color ) {
return 1;
} else if ( get_board ( board, yoko, tate ) == ocolor ) {
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
}
}
return 0;
}
/*
* check_sandwich_play_direct ( char board[8][8], char yoko, char tate, char \
color )
*
* P : 現在のゲーム盤 (board) の状態で、(yoko,tate) に color のコマが置けるかどうか ?
* 置けたら 1 (0 以外 : C 言語の「真」) / 置けない場合は 0 (C 言語の「偽」)
*/
int check_sandwich_play_direct ( char board[8][8], char yoko, char tate, \
char color, int ydir, int tdir ) {
/* 「置ける」条件 */
if ( get_board ( board, yoko, tate ) == ' ' ) {
/* まず、そこに他のコマがない事を確認 */
yoko = yoko + ydir; /* 一つ横にずらす */
tate = tate + tdir; /* 一つ横にずらす */
if ( check_play ( yoko, tate ) ) { /* 盤外でない事を確認 */
char ocolor = oposit ( color ); /* 相手の色を入手 */
/* color == 'o' -> '*', color == '*' -> 'o' */
if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 一つ右が相手の色である事を確認 */
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
/* 後は Q に任せる */
}
}
}
return 0; /* どれかの条件が不成立なら、全体として不成立 (偽:0) を返す */
}
int check_sandwich_all_direct ( char board[8][8], char yoko, char tate, \
char color ) {
int ydir;
int tdir;
for ( ydir = -1; ydir <= 1; ydir++ ) {
for ( tdir = -1; tdir <= 1; tdir++ ) {
if ( tate * tate + yoko * yoko != 0 ) {
/* tate = yoko = 0 の時だけ不成立 */
if ( check_sandwich_play_direct ( board, yoko, tate, color, ydir, tdir ) \
) {
return 1;
}
}
}
}
return 0;
}
/* v12:2014/11/28 追加部分 */
/* 以下の三つの関数を追加 */
/* 関数名の check -> turn に書き換えた */
/* 変更部分:
チェックの結果、挟んでいる事がわかったら、
現在着目している場所の「コマを引っくり返す」という手続きを挿入
*/
/* check から turn に変更する */
/*
check の仕組
いまみている所が敵のコマなら、一つ先を調べる
ココから始めて 右にみてゆく
↓
oxxxxxxxo
^
ココ : みている所が相手のコマなので左をみる
最初にみた時点では、ひっくりかえしてよいかどうかはわからない
右をみる(再帰呼出しをする)と結果がわかります
結果がわかったら、その結果をつかって、ひっくりかえすかどうかをきめる
*/
int turn_sandwich_play_direct_sub ( char board[8][8], char yoko, char tate, \
char color, char ocolor, int ydir, int tdir ) {
yoko = yoko + ydir;
tate = tate + tdir;
/* 今みている所 */
if ( check_play ( yoko, tate ) ) { /*右も左両方*/
/* その場所は盤内 */
if ( get_board ( board, yoko, tate ) == color ) {
return 1;
} else if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 相手のコマがあった */
/* まだ引っくり返す事ができない */
/*
return turn_sandwich_play_direct_sub ( board, yoko, tate, color, ocolor, \
ydir, tdir );
v11: return 文一つを複数の文に変更
*/
int result; /* ひっくりかえせるかどうかの結果を保持 */
result = turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
/* 結果を、二度(コマを引っくり返すかどうか/結果として返す)
利用するので、結果を変数に保存する
(もういちど、関数をよびだしてもよいが無駄だったり、余計だったりする)
*/
/* check で結果を返す所で、
結果を返すだけでなく、結果を利用して、
もう一仕事(コマを引っ繰り返す) */
if ( result == 1 ) {
/* ココでは、ひっくりかえして良いことわかる */
put_board ( board, yoko, tate, color );
/* 自分の色のコマに変更する : 引っくり返す */
}
return result; /* 結果を返す */
}
}
return 0;
}
int turn_sandwich_play_direct ( char board[8][8], char yoko, char tate, \
char color, int ydir, int tdir ) {
/* 「置ける」条件 */
if ( get_board ( board, yoko, tate ) == ' ' ) {
/* まず、そこに他のコマがない事を確認 */
yoko = yoko + ydir; /* 一つ横にずらす */
tate = tate + tdir; /* 一つ横にずらす */
if ( check_play ( yoko, tate ) ) { /* 盤外でない事を確認 */
char ocolor = oposit ( color ); /* 相手の色を入手 */
/* color == 'o' -> '*', color == '*' -> 'o' */
if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 一つ右が相手の色である事を確認 */
/*
return turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
を以下のように変更する
*/
int result; /* ひっくりかえせるかどうかの結果を保持 */
result = turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
if ( result == 1 ) {
put_board ( board, yoko, tate, color );
}
return result;
}
}
}
return 0; /* どれかの条件が不成立なら、全体として不成立 (偽:0) を返す */
}
int turn_sandwich_all_direct ( char board[8][8], char yoko, char tate, char \
color ) {
int ydir;
int tdir;
for ( ydir = -1; ydir <= 1; ydir++ ) {
for ( tdir = -1; tdir <= 1; tdir++ ) {
if ( tate * tate + yoko * yoko != 0 ) {
/* tate = yoko = 0 の時だけ不成立 */
turn_sandwich_play_direct ( board, yoko, tate, color, ydir, tdir );
}
}
}
return 0;
}
# # v11 の makefile # # - makefile の基本的な構造 # -- rule の集合 # -- rule の書き方 # 作りたい物 : 材料 # <TAB> 作り方 # # rule の意味 # 「作りたい物」が作りたければ「材料」を利用して、「作り方」を実行する # 材料がなければ、材料も作ろうとする !! # # - make コマンドの実行 # make で引数を指定しなければ、最初のルールを実行しようとする # 引数(作りたい物)が指定されると、指定された物を作ろうとする # <ポイント> # 既に、作りたいものが存在して、材料より新しいなら、何もしない # 作りたいものがないか、材料より古いならば、作り直す # 作り方をしらない物が材料に指定されていても、「それがあれば」よい # 材料がなく、作り方もしらないとエラーになる # # board.c 系列がふえた.. # othello.exe : othello.o main.o board.o cc -o othello.exe othello.o main.o board.o othello.o : othello.c cc -c othello.c main.o : main.c cc -c main.c board.o : board.c cc -c board.c clean : rm *.o *.exe makezip : zip v11.zip makefile main.c othello.c board.c
v13
/*
* board.c
*/
#include <stdio.h>
/* 表示の部分 */
/*
print_board : 与えらたボードデータを表示する
<<ポイント>>
配列の引数には特殊事情がある : 後回し
*/
void print_board ( char board[8][8] ) {
int tate; /* 縦の添字 */ /* 追加(Copy) */
int yoko; /* 横の添字 */
/* 表示機能 (移動) */
/* ボードの内容を出力する */
/* 8x8 の内容を全て出力(標準出力)すればよい */
/* 配列の出力 -> for 文でやればよい */
/* 二次元配列なので、二重ループになる */
/*
A B C D E F G H
\yoko 0 1 2 3 4 5 6 7
tate 1 0 +---->
2 1 |
3 2 v
4 3
5 4
6 5
7 6
8 7
*/
printf ( " A B C D E F G H\n" );
printf ( " ┏━┳━┳━┳━┳━┳━┳━┳━┓\n" );
for ( tate = 0; tate < 8; tate++ ) {
printf ( "%d ┃", tate + 1 ); /* 左の、この行の枠 */
for ( yoko = 0; yoko < 8; yoko++ ) {
if ( board[tate][yoko] == ' ') { /* 空き */
printf ( " " );
} else if ( board[tate][yoko] == 'o') { /* 白 */
printf ( "◯" );
} else /* if board[tate][yoko] == 'x') */ { /* 黒 */
printf ( "●" );
}
printf ( "┃" ); /* コマとコマの間の枠 */
}
printf ( "\n" ); /* 改行 */
if ( tate < 8 - 1 ) { /* 最後は、これを使わない */
printf ( " ┣━╋━╋━╋━╋━╋━╋━╋━┫\n" );
} else { /* 最後の行に使うのはこれ */
printf ( " ┗━┻━┻━┻━┻━┻━┻━┻━┛\n" );
}
}
}
/*
* 初期化
*/
void init_board( char board[8][8] ) {
int tate; /* 縦の添字 */
int yoko; /* 横の添字 */
/* ゲーム盤の初期化 */
/* とりあえず、全部 ' ' にして、後から真ん中の4つを置く */
/* とりあえず、全部空白 */
for ( tate = 0; tate < 8; tate++ ) {
for ( yoko = 0; yoko < 8; yoko++ ) {
board[tate][yoko] = ' '; /* 全ての場所を空白に */
}
}
/* 真ん中の 4 つだけ特別処理 */
board[3][3] = 'o'; /* D4 なので白 */
board[4][4] = 'o'; /* E5 なので白 */
board[3][4] = '*'; /* D5 なので黒 */
board[4][3] = '*'; /* E4 なので黒 */
}
/*
computer.c
コンピュータが人間の相手をしてくれる
かしこさ
右上から、順番に調べて、うてる場所に打つ
結果としては、
返り値は
1 : うてる
0 : うてない
うつ場所は
result[2] という配列に保存
result[0] には yoko の場所
result[1] には tate の場所
*/
int computer ( char result[2], char board[8][8], char color ) {
int yoko;
int tate;
/* 左上から、左から右、上から下に、すべての場所を調べる */
for ( yoko = 'A'; yoko <= 'F'; yoko++ ) {
for ( tate = '1'; tate <= '8'; tate++ ) {
if ( check_sandwich_all_direct ( board, yoko, tate, color ) == 1 ) {
/* この場所に置く事ができる */
result[0] = yoko;
result[1] = tate;
return 1; /* 置く場所がみつかった */
}
}
}
return 0; /* 置く場所が見付からなかった */
}
/*
* othello v10 (2014/11/14) の main.c
*/
#include <stdio.h>
/*
* main
*/
int main(int argc, char *argv[]) {
char board[8][8]; /* ゲームボード */
char yoko; /* 横の記号 'A' 〜 'F' */
char tate; /* 縦の記号 '1' 〜 '8' */
char color; /* 色の記号 '*' : 黒 / 'o' : 白 */
init_board ( board ); /* 引数に配列名しか指定しない */
print_board ( board ); /* 引数に配列名しか指定しない */
color = '*';
while ( 0 < 1 ) {
printf ( "次の一手> " );
/* ここで入力をする */
if ( color == '*' ) { /* 人間の手順 */
/* キーボードから 「A2*<改行>」とされた事を想定 */
yoko = getchar(); /* 横の指定の一文字 'A' を入力 */
if ( yoko == 'Z' ) { /* 'Z' が入ったら.. */
printf ( "プログラムを終了します...\n" );
return 0; /* プログラムを終了 */
}
tate = getchar(); /* 縦の指定の一文字 '2' を入力 */
getchar(); /* 改行を読み飛ばす */
} else { /* コンピュータ */
char result[2]; /* 置く場所を保存する配列 */
if ( computer ( result, board, color ) == 1 ) {
yoko = result[0]; /* 打つ結果を、変数に保存 */
tate = result[1]; /* 打つ結果を、変数に保存 */
/* 配列名を関数に渡すと、関数の中で、配列の要素の値を変更できる */
printf ( "\n" );
} else {
printf ( "うてません\n" );
return 0; /* プログラムを終了 */
}
}
printf ( "着手 (%c,%c) %c ", yoko, tate, color );
if ( check_sandwich_all_direct ( board, yoko, tate, color ) ) {
printf ( "置く事ができます。\n" );
/* (v12) 挟んだコマを実際に引っくり返す */
turn_sandwich_all_direct ( board, yoko, tate, color );
/* (v12) そこにコマを置く */
put_board ( board, yoko, tate, color );
color = oposit ( color );
} else {
printf ( "置く事ができません。\n" );
}
/* その結果が反映されているかどうかを確認する */
print_board ( board );
}
return 0;
}
/*
* オセロ盤プログラム (version 11 : 2014/11/28)
*
* 機能
* 初期化の部分
* 表示の部分 : 位置を表す記号 1 〜 8, A 〜 F
* 入力の部分(コマを置いてみたい..)
* 入力の指示はキーボード
* ゲームをしてみたい
* 繰返し入力をする
* 繰返しは while で実現できるが
* いつまで繰り返すか ?
* -> ルールでは、両方パスするまで
* とりあえず、サボって
* 無限に繰り返す事にする
* ( 終了は 'Z' を入れる )
* v10 -> v11
* v10 では、8 方向のチェックをした
* 着手禁止のチェックができるようになった
* v11
* 着手できるなら、自動的に挟んだコマをひっくりかえしたい
* 基本はチェックのプログラムが、ほぼ、ひっくりかえしのプログラムと同等
* 「天下り」ですが、チェックの関数を変更してひっくりかえし関数を作る
*/
#include <stdio.h>
/* ボードを作る */
/* ボードは、8x8 の要素からなる */
/* ボードの一つの要素には 空、黒、白のいずかが入る */
/* 空 ' ' , 白 'o', 黒 '*' -> 一文字 */
/*
'A2' に黒 -> put_board_black ( 'A', '2' )
-> board[1][0] = '*';
*/
char get_board ( char board[8][8], char yoko, char tate ) {
return board[tate-'1'][yoko-'A'];
}
void put_board ( char board[8][8], char yoko, char tate, char color ) {
board[tate-'1'][yoko-'A'] = color;
/* 本当は、ここで tate, yoko, color が正しい値かを
チェックする必要がある (後回し)
*/
}
void put_board_black ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, '*' );
/*
put_board_black ( 'A', '2' )
->
board['2'-'1']['A'-'A'] = '*';
->
board[1][0] = '*';
*/
}
void put_board_white ( char board[8][8], char yoko, char tate ) {
put_board ( board, yoko, tate, 'o' );
}
/*
* oposit ( char color )
* 自分の色を指定して、相手の色を返す
* '*' -> 'o'
* 'o' -> '*'
*/
char oposit ( char color ) {
/*
if ( color == '*' ) {
return 'o';
} else if ( color == 'o' ) {
return '*';
}
*/
return 'o' + '*' - color;
}
/*
横方向のチェックを行う
*/
int check_yoko ( char yoko ) {
if ( yoko <= 'F' ) {
if ( 'A' <= yoko ) {
return 1; /* 'A' <= yoko <= 'F' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
/*
横方向のチェックを行う
*/
int check_tate ( char tate ) {
if ( tate <= '8' ) {
if ( '1' <= tate ) {
return 1; /* '1' <= tate <= '8' なので OK */
}
}
return 0; /* その他の場合は、駄目 */
}
int check_play ( char yoko, char tate ) {
if ( check_yoko ( yoko ) ) {
if ( check_tate ( tate ) ) {
return 1;
}
}
return 0;
}
int check_sandwich_play_direct_sub ( char board[8][8], char yoko, char \
tate, char color, char ocolor, int ydir, int tdir ) {
yoko = yoko + ydir;
tate = tate + tdir;
if ( check_play ( yoko, tate ) ) { /*右も左両方*/
if ( get_board ( board, yoko, tate ) == color ) {
return 1;
} else if ( get_board ( board, yoko, tate ) == ocolor ) {
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
}
}
return 0;
}
/*
* check_sandwich_play_direct ( char board[8][8], char yoko, char tate, char \
color )
*
* P : 現在のゲーム盤 (board) の状態で、(yoko,tate) に color のコマが置けるかどうか ?
* 置けたら 1 (0 以外 : C 言語の「真」) / 置けない場合は 0 (C 言語の「偽」)
*/
int check_sandwich_play_direct ( char board[8][8], char yoko, char tate, \
char color, int ydir, int tdir ) {
/* 「置ける」条件 */
if ( get_board ( board, yoko, tate ) == ' ' ) {
/* まず、そこに他のコマがない事を確認 */
yoko = yoko + ydir; /* 一つ横にずらす */
tate = tate + tdir; /* 一つ横にずらす */
if ( check_play ( yoko, tate ) ) { /* 盤外でない事を確認 */
char ocolor = oposit ( color ); /* 相手の色を入手 */
/* color == 'o' -> '*', color == '*' -> 'o' */
if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 一つ右が相手の色である事を確認 */
return check_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
/* 後は Q に任せる */
}
}
}
return 0; /* どれかの条件が不成立なら、全体として不成立 (偽:0) を返す */
}
int check_sandwich_all_direct ( char board[8][8], char yoko, char tate, \
char color ) {
int ydir;
int tdir;
for ( ydir = -1; ydir <= 1; ydir++ ) {
for ( tdir = -1; tdir <= 1; tdir++ ) {
if ( ydir != 0 || tdir != 0 ) {
/* ydir == ydir == 0 の時だけ不成立 */
if ( check_sandwich_play_direct ( board, yoko, tate, color, ydir, tdir ) \
) {
return 1;
}
}
}
}
return 0;
}
/* v12:2014/11/28 追加部分 */
/* 以下の三つの関数を追加 */
/* 関数名の check -> turn に書き換えた */
/* 変更部分:
チェックの結果、挟んでいる事がわかったら、
現在着目している場所の「コマを引っくり返す」という手続きを挿入
*/
/* check から turn に変更する */
/*
check の仕組
いまみている所が敵のコマなら、一つ先を調べる
ココから始めて 右にみてゆく
↓
oxxxxxxxo
^
ココ : みている所が相手のコマなので左をみる
最初にみた時点では、ひっくりかえしてよいかどうかはわからない
右をみる(再帰呼出しをする)と結果がわかります
結果がわかったら、その結果をつかって、ひっくりかえすかどうかをきめる
*/
int turn_sandwich_play_direct_sub ( char board[8][8], char yoko, char tate, \
char color, char ocolor, int ydir, int tdir ) {
yoko = yoko + ydir;
tate = tate + tdir;
/* 今みている所 */
if ( check_play ( yoko, tate ) ) { /*右も左両方*/
/* その場所は盤内 */
if ( get_board ( board, yoko, tate ) == color ) {
return 1;
} else if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 相手のコマがあった */
/* まだ引っくり返す事ができない */
/*
return turn_sandwich_play_direct_sub ( board, yoko, tate, color, ocolor, \
ydir, tdir );
v11: return 文一つを複数の文に変更
*/
int result; /* ひっくりかえせるかどうかの結果を保持 */
result = turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
/* 結果を、二度(コマを引っくり返すかどうか/結果として返す)
利用するので、結果を変数に保存する
(もういちど、関数をよびだしてもよいが無駄だったり、余計だったりする)
*/
/* check で結果を返す所で、
結果を返すだけでなく、結果を利用して、
もう一仕事(コマを引っ繰り返す) */
if ( result == 1 ) {
/* ココでは、ひっくりかえして良いことわかる */
put_board ( board, yoko, tate, color );
/* 自分の色のコマに変更する : 引っくり返す */
}
return result; /* 結果を返す */
}
}
return 0;
}
int turn_sandwich_play_direct ( char board[8][8], char yoko, char tate, \
char color, int ydir, int tdir ) {
/* 「置ける」条件 */
if ( get_board ( board, yoko, tate ) == ' ' ) {
/* まず、そこに他のコマがない事を確認 */
yoko = yoko + ydir; /* 一つ横にずらす */
tate = tate + tdir; /* 一つ横にずらす */
if ( check_play ( yoko, tate ) ) { /* 盤外でない事を確認 */
char ocolor = oposit ( color ); /* 相手の色を入手 */
/* color == 'o' -> '*', color == '*' -> 'o' */
if ( get_board ( board, yoko, tate ) == ocolor ) {
/* 一つ右が相手の色である事を確認 */
/*
return turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
を以下のように変更する
*/
int result; /* ひっくりかえせるかどうかの結果を保持 */
result = turn_sandwich_play_direct_sub ( board, yoko, tate, color, \
ocolor, ydir, tdir );
if ( result == 1 ) {
put_board ( board, yoko, tate, color );
}
return result;
}
}
}
return 0; /* どれかの条件が不成立なら、全体として不成立 (偽:0) を返す */
}
int turn_sandwich_all_direct ( char board[8][8], char yoko, char tate, char \
color ) {
int ydir;
int tdir;
for ( ydir = -1; ydir <= 1; ydir++ ) {
for ( tdir = -1; tdir <= 1; tdir++ ) {
if ( tate * tate + yoko * yoko != 0 ) {
/* tate = yoko = 0 の時だけ不成立 */
turn_sandwich_play_direct ( board, yoko, tate, color, ydir, tdir );
}
}
}
return 0;
}
# # v11 の makefile # # - makefile の基本的な構造 # -- rule の集合 # -- rule の書き方 # 作りたい物 : 材料 # <TAB> 作り方 # # rule の意味 # 「作りたい物」が作りたければ「材料」を利用して、「作り方」を実行する # 材料がなければ、材料も作ろうとする !! # # - make コマンドの実行 # make で引数を指定しなければ、最初のルールを実行しようとする # 引数(作りたい物)が指定されると、指定された物を作ろうとする # <ポイント> # 既に、作りたいものが存在して、材料より新しいなら、何もしない # 作りたいものがないか、材料より古いならば、作り直す # 作り方をしらない物が材料に指定されていても、「それがあれば」よい # 材料がなく、作り方もしらないとエラーになる # # board.c 系列がふえた.. # computer.c がふえた # othello.exe : othello.o main.o board.o computer.o cc -o othello.exe othello.o main.o board.o computer.o othello.o : othello.c cc -c othello.c main.o : main.c cc -c main.c board.o : board.c cc -c board.c computer.o : computer.c cc -c computer.c clean : rm *.o *.exe makezip : zip v11.zip makefile main.c othello.c board.c computer.c