マルバツゲームでコードゴルフをやってみた

2024/11/13に公開

はじめに

マルバツゲームでコードゴルフをやりました(参加者3人).
勝ち点/コード長 が大きい方から順位が決まります.

コードゴルフというのはいかにコードを短く書くかというやつです.
https://ja.wikipedia.org/wiki/コードゴルフ

ルール

C言語のプログラムを1つ書く,このプログラムに求められる入出力は以下の通り

入力

以下のようなマルバツゲームの盤面が与えられる(末尾に改行を含む).(o:先手 x:後手)

xox
.o.
o..

出力

次の盤面を同様の形式で返す.例えば上の入力に対しては下のような出力が許される(末尾に改行を含めなければならない).

xox
.o.
ox.

実行環境

公平のためideoneで実行.

勝敗

先手である場合 o を,後手である場合 x を縦横斜めのいずれかに3つ揃えたら勝ち.invalidな出力をした場合負け.

順位の決め方

同じ相手と先後交代で2回戦う,総当たり戦を行う.同じプログラムで先手も後手も対応する必要がある.
それぞれの対戦について,勝ち:3点 引き分け:1点 負け:0点
最終的なスコアは,点数の合計/コード長で決める.

自分の戦略

勝ちが3点,引き分けが1点.
短いコードで,先手で引き分けを狙うことに全力を注ぎました.
先手で引き分け,後手で負けだと勝ち点では自分1点,相手4点です.相手よりコード長が\frac{1}{4}未満であれば実質勝ちです.

短いプログラムで引き分けるには,相手を誘導する必要があります.
相手のプログラムがある程度賢いならば,初手で隅を選ぶと,2手目に真ん中に置くでしょう.真ん中以外を選ぶと負ける手筋が存在するので,真ん中を選ばざるを得ません.

1手目(自分)

o..
...
...

2手目(相手)

o..
.x.
...

そこで,相手の2手目が真ん中であれば,最低でも引き分けるプログラムを考えました.

具体的には,下の図の順に探索し,空いているマスならそこに石を置く,というルールにしました.単純なルールですが,2手目に真ん中に置かれた時点で負けはありません.

169
425
378

コード

121Byteです.文字化けしているように見える場所は制御文字のDC2です.

a=11,c,d;main(b){char s[a];read(0,s,a);for(;a--;b+=s[a]);for(;s[d]!=46;d="-H$6	QZ"[c]/9,_c++);s[d]=111+b/69%2*9;puts(s);}

https://ideone.com/6sdO0p

配列外を参照している気もするけど動くからOKなのです.

for(;s[d]!=46;d="-H$6 QZ"[c]/9,_c++); の部分で先ほどの優先順位の順に探索しています.
後手番でも一応動くようにはなっています.先手番と後手番の判別は,文字の合計を69で割った値を2で割った余りで判断しています.

戦績

作戦通りに決まった試合のログを載せます.
vs 寿司まう
こちらが先手番 o です.

o..
...
...
o..
.x.
...
o..
.x.
o..
o..
xx.
o..
o..
xxo
o..
ox.
xxo
o..
ox.
xxo
oo.
ox.
xxo
oox
oxo
xxo
oox

というように,狙い通り引き分けです.

結果

駒上(筆者) 寿司まう 匿名A
駒上(筆者) 0勝1敗1分 2勝0敗0分
寿司まう 1勝0敗1分 2勝0敗0分
匿名A 0勝2敗0分 0勝2敗0分

勝敗は上のようになりました,

順位 名前 コード長 勝ち点 スコア
優勝 駒上 121バイト 7 0.0579
準優勝 寿司まう 717バイト 10 0.0139
第3位 匿名A 398バイト 0 0

勝ち点/コード長 が大きい方から順位が決まるので,優勝です.やったぜ.

おわりに

はじめてのコードゴルフ,色々参考にしました.
特に役立ったのは以下の記事です.
https://vipprog.net/wiki/?code+golf入門/C言語編.html
https://gist.github.com/lpha-z/d811a975b0acd5c17493

Discussion