アニメ『残響のテロル』(2014)
プルトニウムを強奪した青年二人によるテロの話ですが、この青年頭が良いです。ぞくぞくするシーンの中に、追う側と追われる側で、チェスを指すシーンがあります。チェスボードを見ながらのチェスではなく、マス番号のみが交わされる、頭の中だけで行われるブラインドチェスです。そりゃあもう賢いのなんのって。
てなわけで、私も、ブラインドチェスが指せるようになりたいです。ぜったい。
しかし、チェスでは少々敷居が高いので、覚えやすいオセロにしておきます。オセロでボードを見ずに、石を置いた場所だけでも覚える訓練にしてみようかと思います。
まずは普通に石を置けるような仕組みを作らねばなりません。オセロボードが見える形で、交互に石を置くコマンドを作ってみます。
解説を混ぜながらソースを見ていきましょう。
~$ cat -n reversi.c
1 #include <stdio.h>
2
3 #define Z ' '
4 #define _ '_'
5 #define Q 'Q'
6 #define X 'X'
7
8 char bd[10][10]={
9 Z, '1','2','3','4','5','6','7','8', Z ,
10
11 Z, _ , _ , _ , _ , _ , _ , _ , _ , '1',
12 Z, _ , _ , _ , _ , _ , _ , _ , _ , '2',
13 Z, _ , _ , _ , _ , _ , _ , _ , _ , '3',
14 Z, _ , _ , _ , Q , X , _ , _ , _ , '4',
15 Z, _ , _ , _ , X , Q , _ , _ , _ , '5',
16 Z, _ , _ , _ , _ , _ , _ , _ , _ , '6',
17 Z, _ , _ , _ , _ , _ , _ , _ , _ , '7',
18 Z, _ , _ , _ , _ , _ , _ , _ , _ , '8',
19
20 Z, Z , Z , Z , Z , Z , Z , Z , Z , Z ,
21 };
ボードの絵を作るために一文字のdefine定義をしています。
オセロボードは8x8なんですが、判定を楽にするために、10x10の空間にして、さらにそれを以下のソースでprintfの表示にも利用します。
22
23 void disp()
24 {
25 int x,y;
26 for(y = 0; y < 9; y++){
27 for(x = 0; x < 10; x++){
28 printf("%c",bd[y][x]);
29 printf("|");
30 }
31 printf("\n");
32 }
33 }
34
次のソースでは、いきなりプロトタイプ宣言していますが、再帰呼出しするためです。
石が置けるのは、隣接の石が反転できる場合のみですので、方向を指定して、その一番奥の石が自分の色であることを確認しなければなりません。
以下のcheck関数ではreturnの値が0の場合は、石が置けないパターンとなります。
35 int check(int x, int y, int xx, int yy, char bw, int first);
36
37 int check(int x, int y, int xx, int yy, char bw, int first)
38 {
39 int my_x = x + xx;
40 int my_y = y + yy;
41
42 if(bd[my_y][my_x] == bw)
43 if(first == 1)
44 return 0;
45 else
46 return 1;
47
48 switch(bd[my_y][my_x]){
49 case _:
50 case Z:
51 return 0;
52 }
53
54 if(!check(my_x,my_y, xx,yy, bw, 0) )
55 return 0;
56
57 bd[my_y][my_x] = bw;
58 return 1;
59 }
60
では本体です。for(;;)で無限ループしますので、実際このオセロは終わりがありません。あくまでも脳トレなので、気にしません。
74行目のfor文は、石を置いた隣のマスのチェックを行うため8方向で回しています。
置くのに失敗した場合は、79行目でターンの変更をしないようにしています。
61 int main(int argc, char* argv[])
62 {
63 int i;
64 int xx[]={-1,-1, 0, 1, 1, 1, 0, -1};
65 int yy[]={ 0,-1,-1,-1, 0, 1, 1, 1};
66 int x,y,turn=0,t;
67
68 for(;;){
69 disp();
70 printf("You are %s. X=? Y=?", turn==0 ?"BLACK(Q)":"WHITE(X)");
71 scanf("%d,%d",&x,&y);
72 if(x>8 || y>8 || x<1 || y<1 )continue;
73 t = turn==0?'Q':'X';
74 for(i=0;i<8;i++)
75 if(check(x,y, xx[i],yy[i], t, 1)){
76 bd[y][x] = t;
77 break;
78 }
79 if(i==8)continue;
80
81 turn = 1 - turn;
82 }
83
84 return 0;
85 }
動かしてみましょう。
~$ ./reversi |1|2|3|4|5|6|7|8| | |_|_|_|_|_|_|_|_|1| |_|_|_|_|_|_|_|_|2| |_|_|_|_|_|_|_|_|3| |_|_|_|Q|X|_|_|_|4| |_|_|_|X|Q|_|_|_|5| |_|_|_|_|_|_|_|_|6| |_|_|_|_|_|_|_|_|7| |_|_|_|_|_|_|_|_|8| You are BLACK(Q). X=? Y=?4,6 |1|2|3|4|5|6|7|8| | |_|_|_|_|_|_|_|_|1| |_|_|_|_|_|_|_|_|2| |_|_|_|_|_|_|_|_|3| |_|_|_|Q|X|_|_|_|4| |_|_|_|Q|Q|_|_|_|5| |_|_|_|Q|_|_|_|_|6| |_|_|_|_|_|_|_|_|7| |_|_|_|_|_|_|_|_|8| You are WHITE(X). X=? Y=?
さて、脳内オセロのトレーニングなので、ボードを非表示にして実行してみます。
69行目のdisp()をコメントアウトするだけでよいです。
68 for(;;){
69 // disp();
70 printf("You are %s. X=? Y=?", turn==0 ?"BLACK(Q)":"WHITE(X)");
うまくオセロできるでしょうか。
~$ ./reversi You are BLACK(Q). X=? Y=?4,6 You are WHITE(X). X=? Y=?5,6 You are BLACK(Q). X=? Y=?3,7 You are BLACK(Q). X=? Y=?3,6 You are BLACK(Q). X=? Y=?5,3 You are BLACK(Q). X=? Y=?6,3 You are WHITE(X). X=? Y=?6,4 You are WHITE(X). X=? Y=?5,4 You are WHITE(X). X=? Y=?
まともに、オセロができる気はしませんでしたが、ものすごーく頭を使いますので、1分ぐらい考えただけですが、かなり頭が良くなった気がします。これは絶対、最近気になり始めているボケ防止になります。
※ソースはgithubから落とせます。
takk@deb83:~$ git clone https://github.com/takkete/scrap.git takk@deb83:~$ cd scrap takk@deb83:~/scrap$ gcc reversi.c takk@deb83:~/scrap$ ./a.out


コメント
[…] 「脳内オセロで脳トレ」で作成した脳トレ用のコマンドラインオセロですが、試してみると使い勝手が悪かったので、いろいろ手直ししようと思います。 ついでにバグも修正します。 […]