アニメ『3月のライオン』
若き天才ってカッコいいですねえ。17歳ですか。心を閉ざす主人公が、3姉妹や周囲の人たちから暖かく接してもらい次第に心が開いていく様子に癒やされます。三姉妹の家はすごく癒やされます。特に猫。猫たちはいっつもお腹すいてるんですね。
「GUIプログラムからCUIプログラムを使う(標準入出力)」で作ったオセロのGUIフロントエンドを、将棋でも使えるように変更してみます。
shogi.tclではなく、gameboard.tclとしたのは、マス目がある他のゲームにも対応するためです。
takk@deb83:~/scrap$ cp reversi.tcl gameboard.tcl
新しいGUIフロントエンドは、最初に初期化コマンドを受け取ることで、ボードのマス数と色を決めることにします。
初期化コマンドの書式は、
“INIT,桁数,行数,色”
で、
オセロの場合は、
“INIT,8,8,green”
将棋の場合は、
“INIT,9,9,yellow”
としました。
初期化コマンドの解析処理がこちらです。
28 gets $pipe str 29 set arr [split $str ","] 30 set cmd [lindex $arr 0] 31 if { $cmd == "INIT" } { 32 set xmax [lindex $arr 1] 33 set ymax [lindex $arr 2] 34 set color [lindex $arr 3] 35 }
マスのボタンを生成するfor文のネストが固定で8となっていた箇所は、初期化コマンドで受けた桁数行数によって
回すように変更ということになります。
38 for {set i 1} {$i <= $xmax} {incr i} { 39 for {set j 1} {$j <= $ymax} {incr j} {
また、コマンドで、オセロの石だけでなく、将棋の駒も処理できるように、
各コマンドを増やしました。
13 if {$bw == "B"} { .b$xy configure -text "●" -fg black } 14 if {$bw == "W"} { .b$xy configure -text "●" -fg white } 15 if {$bw == "f"} { .b$xy configure -text "歩" -fg black } 16 if {$bw == "o"} { .b$xy configure -text "王" -fg black } 17 if {$bw == "a"} { .b$xy configure -text "金" -fg black } 18 if {$bw == "g"} { .b$xy configure -text "銀" -fg black } 19 if {$bw == "u"} { .b$xy configure -text "桂" -fg black } 20 if {$bw == "s"} { .b$xy configure -text "香" -fg black } 21 if {$bw == "t"} { .b$xy configure -text "飛" -fg black } 22 if {$bw == "x"} { .b$xy configure -text "角" -fg black }
最終的にこうなりました。
takk@deb83:~/scrap$ cat -n gameboard.tcl 1 proc update_board { pipe } { 2 while {[gets $pipe str] >= 0} { 3 set first_char [string range $str 0 0] 4 5 if { $first_char == "Y" } { ;# Y in YOU 6 break 7 } 8 9 set arr [split $str ","] 10 set xy [lindex $arr 0] 11 set bw [lindex $arr 1] 12 13 if {$bw == "B"} { .b$xy configure -text "●" -fg black } 14 if {$bw == "W"} { .b$xy configure -text "●" -fg white } 15 if {$bw == "f"} { .b$xy configure -text "歩" -fg black } 16 if {$bw == "o"} { .b$xy configure -text "王" -fg black } 17 if {$bw == "a"} { .b$xy configure -text "金" -fg black } 18 if {$bw == "g"} { .b$xy configure -text "銀" -fg black } 19 if {$bw == "u"} { .b$xy configure -text "桂" -fg black } 20 if {$bw == "s"} { .b$xy configure -text "香" -fg black } 21 if {$bw == "t"} { .b$xy configure -text "飛" -fg black } 22 if {$bw == "x"} { .b$xy configure -text "角" -fg black } 23 } 24 } 25 26 set pipe [open "| ./a.out" r+] 27 28 gets $pipe str 29 set arr [split $str ","] 30 set cmd [lindex $arr 0] 31 if { $cmd == "INIT" } { 32 set xmax [lindex $arr 1] 33 set ymax [lindex $arr 2] 34 set color [lindex $arr 3] 35 } 36 37 set turnsw 0 38 for {set i 1} {$i <= $xmax} {incr i} { 39 for {set j 1} {$j <= $ymax} {incr j} { 40 button .b$i$j -font {FreeMono 40 bold} -bg $color -activebackground yellow -activeforeground red 41 grid .b$i$j -in . -row $j -column $i -sticky nsew 42 grid columnconfigure . all -weight 1 -minsize 60 43 grid rowconfigure . all -weight 1 -minsize 60 44 45 bind .b$i$j <Button> { 46 set x [string range %W 2 2] 47 set y [string range %W 3 3] 48 puts $pipe "$x,$y\n";flush $pipe 49 50 update_board $pipe 51 52 set turnsw [expr 1 - $turnsw] 53 } 54 } 55 } 56 57 update_board $pipe
次はオセロ用エンジンをコピーして将棋用エンジンを作ります。将棋以外にも使うので単純にgame.cとしました。
takk@deb83:~/scrap$ cp reversi.c game.c
今回は将棋ロジックは含めず、並べて表示するところまでのソースとします。
まず配列。将棋の9×9に対応するため拡張します。関連するfor文も本定数に置き換えます。
4 #define XMAX 9 5 #define YMAX 9 6 char bd[YMAX+2][XMAX+2];
将棋の駒を布陣します。GUIフロントエンドはオセロと共通なので、コマンド名がかぶらないように、
オセロはBとWというように大文字を使い、将棋は小文字にしています。
59 printf("INIT,9,9,yellow\n"); 60 for(i=1;i<=9;i++){ 61 bd[7][i]='f'; 62 } 63 bd[8][8]='t'; 64 bd[8][2]='x'; 65 bd[9][1]='s'; 66 bd[9][2]='u'; 67 bd[9][3]='g'; 68 bd[9][4]='a'; 69 bd[9][5]='o'; 70 bd[9][6]='a'; 71 bd[9][7]='g'; 72 bd[9][8]='u'; 73 bd[9][9]='s';
角がxに飛車はt、金はaにしました。
全ソースはこのとおりです。
1 #include <stdio.h> 2 #include <string.h> 3 4 #define XMAX 9 5 #define YMAX 9 6 char bd[YMAX+2][XMAX+2]; 7 8 void disp() 9 { 10 int x,y; 11 for(y = 1; y <= YMAX; y++) 12 for(x = 1; x <= XMAX; x++) 13 if(bd[y][x] != 0 ) 14 printf("%d%d,%c\n",x,y,bd[y][x]); 15 } 16 17 int check(int x, int y, int xx, int yy, char bw, int first); 18 19 int check(int x, int y, int xx, int yy, char bw, int first) 20 { 21 int my_x = x + xx; 22 int my_y = y + yy; 23 24 if(bd[my_y][my_x] == bw) 25 if(first == 1) 26 return 0; 27 else 28 return 1; 29 30 switch(bd[my_y][my_x]){ 31 case 0: 32 return 0; 33 } 34 35 if(!check(my_x,my_y, xx,yy, bw, 0) ) 36 return 0; 37 38 bd[my_y][my_x] = bw; 39 return 1; 40 } 41 42 int main(int argc, char* argv[]) 43 { 44 int i; 45 char disc; 46 int xx[]={-1,-1, 0, 1, 1, 1, 0, -1}; 47 int yy[]={ 0,-1,-1,-1, 0, 1, 1, 1}; 48 int x,y,turn=0,t,turnend_flag; 49 char c; 50 51 memset(bd,0,sizeof(bd)); 52 53 #ifdef REVERSI 54 printf("INIT,8,8,green\n"); 55 bd[4][4]='W'; bd[5][4]='B'; 56 bd[4][5]='B'; bd[5][5]='W'; 57 58 #else 59 printf("INIT,9,9,yellow\n"); 60 for(i=1;i<=9;i++){ 61 bd[i][7]='f'; 62 } 63 bd[8][8]='t'; 64 bd[8][2]='x'; 65 bd[9][1]='s'; 66 bd[9][2]='u'; 67 bd[9][3]='g'; 68 bd[9][4]='a'; 69 bd[9][5]='o'; 70 bd[9][6]='a'; 71 bd[9][7]='g'; 72 bd[9][8]='u'; 73 bd[9][9]='s'; 74 #endif 75 fflush(stdout); 76 77 for(;;){ 78 disp(); 79 disc = turn==0?'B':'W'; 80 printf("YOU=%c\n",disc); 81 fflush(stdout); 82 x=0;y=0; 83 scanf("%d,%d",&x,&y); 84 if(x>XMAX || y>YMAX || x<1 || y<1 )continue; 85 turnend_flag = 0; 86 if(bd[y][x] == 0) 87 for(i=0;i<8;i++) 88 if(check(x,y, xx[i],yy[i], disc, 1)){ 89 bd[y][x] = disc; 90 turnend_flag = 1; 91 } 92 if(turnend_flag) 93 turn = 1 - turn; 94 } 95 96 return 0; 97 }
将棋盤を表示してみましょう。
takk@deb83:~$ git clone https://github.com/takkete/scrap.git takk@deb83:~/scrap$ gcc game.c takk@deb83:~/scrap$ wish gameboard.tcl
このように表示されます。エンジン次第で、いろんなゲームに変わりますね。
コメント
[…] ← オセロを将棋にすり替える […]