TOP >> マニアックなプログラミング
トリッキーコードネット トリッキーなコード

【7行プログラミング/ショートコーディング】人間 VS コンピュータ(AI) オセロ対局 (C言語)

人間 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行プログラミング)の実行結果

実行結果は以下の通りです。

開始時

対局開始時の様子↓ C言語オセロAIプログラミング

途中経過

筆者 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 ○○○○○○・・ ○○○○○・・・ ○○○○○○○・ ・○○○○・・・ ・・○○○・・・ ・・・・・・・・ ・・・・・・・・ ・・・・・・・・

終了時:

筆者の圧勝^^;) C言語オセロAIプログラミング

オセロ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まで組み込んだ匠の技を、いかにして盗みとるのかが大事だよな~~と、独り思ってみたりします^^;)
ひょっとしたら参考になるかもしれないページ : オセロ対局シュミレーションプログラミング
トリッキーコードネット の TOPへ HOTNEWS の 総合TOPへ