人間 VS コンピュータでオセロ対局を行うプログラムです。
7行のコード中に、なんとAI(人工知能)まで組み込まれています!
#include <stdio.h>
int p,t,a,d,c,v,i,m[90]={0},s,r[]={-10,-9,-8,-1,1,8,9,10};void k(){if(m[p]==0)
for(i=0;i<8;i++){for(c=0,v=p+r[i];m[v]==3-t;v+=r[i])c++;if(c&&m[v]==t){a+=c;v=
p;if(d)do m[v]=t,v+=r[i];while(m[v]!=t);}}}char*h="・○●\n";int main(){for(i=
1,m[41]=m[49]=2;i<10;m[i++*9]=3)m[40]=m[50]=t=s=1;for(;;a=d=0){for(p=9;p<82;++
p)k(),printf("%.2s",&h[m[p]*2]);if(a)for(d=a=s=p=8;a==8;k())t-2?(scanf("%d %d"
,&p,&i),p+=i*9):++p;else if(s)s=0,printf("pass");else break;t=3-t;}return 0;}
【プログラムの使い方】
・人間は○のコマを使います。
・コマを置く場所は、座標で指定します。⇒ X座標(半角スペース)Y座標(半角スペース)(Enterキー)
・エラーチェックはしていないので悪しからず。
オセロAI(7行プログラミング)の実行結果
実行結果は以下の通りです。
開始時
対局開始時の様子↓
途中経過
筆者 VS AIプログラムで、対局中↓
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・○●・・・
・・・●○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
3 5
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・●●●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
3 3
・・・・・・・・
・・・・・・・・
・・○・・・・・
・・○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・○・・・・・
・●●●●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
4 3
・・・・・・・・
・・・・・・・・
・・○○・・・・
・●●○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・・●・・・・・
・・●●・・・・
・●●○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
3 1
・・○・・・・・
・・○・・・・・
・・○●・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
・●○・・・・・
・・●・・・・・
・・○●・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
1 1
○○○・・・・・
・・●・・・・・
・・○●・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○・・・・・
・・●●・・・・
・・●●・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
4 1
○○○○・・・・
・・●○・・・・
・・●○・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○○●・・・
・・●●・・・・
・・●○・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
6 1
○○○○○○・・
・・●●・・・・
・・●○・・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○○○○・・
・・●●・・・・
・・●●●・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
2 2
○○○○○○・・
・○●●・・・・
・・○●●・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○○○○・・
●●●●・・・・
・・○●●・・・
・●○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
1 3
○○○○○○・・
○○●●・・・・
○・○●●・・・
・○○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○○○○・・
○○●●・・・・
○●●●●・・・
・○○○●・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
5 2
○○○○○○・・
○○○○○・・・
○●●○○・・・
・○○○○・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
○○○○○○・・
○○○○○・・・
○●●●●●・・
・○○○○・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
7 3
○○○○○○・・
○○○○○・・・
○○○○○○○・
・○○○○・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
pass
○○○○○○・・
○○○○○・・・
○○○○○○○・
・○○○○・・・
・・○○○・・・
・・・・・・・・
・・・・・・・・
・・・・・・・・
終了時:
筆者の圧勝^^;)
オセロAIプログラムの解説
以下のコードが、冒頭コードの最適化されていないバージョンです。
1 : #include <stdio.h>
2 :
3 : int put, turn, all, done, pass, count, cur, i,
4 :
5 : // 盤状態:横9*縦10で、使用は8*8
6 : // 0:無し 1:1player 2:2player 3:改行
7 : // y*9+xというイメージ。0行目と9行目は番兵
8 : map[90] = {0},
9 :
10 : // 盤を走査する場合、縦横斜め方向に向かうために足されるべき数
11 : dir[]={-10, -9, -8, -1, 1, 8, 9, 10};
12 :
13 :
14 : void check()
15 : // putに駒を置いた場合ひっくり返せる枚数をallに足す
16 : {
17 : if(map[put] == 0)
18 : for (i=0; i<8; i++)
19 : // 8方向走査
20 : {
21 : // dir[i]の方向の相手のコマの数を確認
22 : for(count = 0, cur = put+dir[i]; map[cur] == 3-turn; cur += dir[i])
23 : count++;
24 :
25 : if(count && map[cur] == turn)
26 : // 1枚以上存在し、その上端が自分のコマだったら
27 : {
28 : all += count;
29 : cur = put;
30 :
31 : if(done)
32 : // doneがtrueの場合は、実際にひっくり返す
33 : do
34 : map[cur] = turn, cur += dir[i];
35 : while (map[cur] != turn);
36 : }
37 : }
38 : }
39 :
40 :
41 : // mapに対応するオセロ駒&改行
42 : char *h="・○●\n";
43 :
44 : int main()
45 : {
46 : // 初期化
47 : for(i=1, map[41] = map[49] = 2; i<10; map[i++*9] = 3)
48 : map[40] = map[50] = turn = pass = 1;
49 :
50 : for (;; all = done = 0) // ループのたびにallとdoneを初期化(セミコロンを1つ削除するため)
51 : {
52 : // 盤の表示。今回のデータ構造だとこれで表示できる
53 : // ついでにdone=0でcheckを呼び、何枚駒を置けるのかチェック
54 : for(put = 9; put<82; ++put)
55 : check(), printf("%.2s",&h[map[put]*2]);
56 :
57 : if(all)
58 : // 1枚でも駒が置けた場合はcomは左上から走査、人は置けるまで繰り返す
59 : // 置けた(=allの値が変わった)らturn終了
60 : for(done = all = pass = put = 8; all==8; check())
61 : turn - 2 ? (scanf("%d %d",&put,&i), put+=i*9): ++put;
62 :
63 : else if(pass)
64 : // 駒を置けない。s=0にしてフラグを立てる
65 : pass=0,printf("pass");
66 :
67 : else
68 : // 両者とも駒を置けないので終了
69 : break;
70 :
71 :
72 : // turn交代
73 : turn = 3 - turn;
74 : }
75 :
76 : return 0;
77 : }
プログラミング入門サイトではない、あえて「トリッキーなコード」を求めて このサイトへお越しになった方々ぐらいだと、
・・・ソースコード中のコメントで 挙動をご理解いただけますよね?? ^^;)
私としては、
マップを一次配列にして、(8行目)
走査方向をあらかじめ配列に固定しておき、(11行目)
マスの全方向の走査を、ループでスマートに行う(18~37行目)
部分に、ほほぉ~と感心しました。
(私だったら このような場合、マップを二次元配列にしてプログラミングするからですw)
# この技は、オセロだけではなく、ブロックゲーム全般(ex テトリスなど)にも応用できそうな気がします。
また、73行目のturn交代部分では、ターンフラグを 1 ⇔ 2 と切り替える際、こちらでご紹介した技が使われています♪
最後に一言。 このオセロプログラムのAIは、と に か く 弱 い です。(← おそらく幼稚園児並??)
しかし、人間 VS AIのオセロ対局プログラムは、すでにAIが必勝するアルゴリズムが発見されており、ここでオセロAIの強さをあれこれ論じるのはナンセンス。
このプログラムがゲームとして成り立つかどうか?? はさほど重要ではなく、
たった7行のコードにAIまで組み込んだ匠の技を、いかにして盗みとるのかが大事だよな~~と、独り思ってみたりします^^;)
ひょっとしたら参考になるかもしれないページ : オセロ対局シュミレーションプログラミング