1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

日本語プログラミング言語「なでしこ」Advent Calendar 2021

Day 7

なでしこさんでマルバツゲームを作るよ! ② ~人対人で遊べるようにする~

Last updated at Posted at 2021-12-06

#マウスで交互に打てるようにする
 前回は、ただ3×3の格子を表示しただけでした。
 マルバツゲーム的に言えば、ノートに線引いただけというw
 一応⭕や❌も表示してみましたが、これもほんとにただ表示しただけでしたが、今回はまずマウスでマスをクリックして⭕❌を表示していけるようにします。

マウスイベント

 ゲーム画面をマウスでクリックして、マルバツを表示させたいんですが、クリックはマウスを「押して離したとき」に発生するイベントで、その要素上なら押したときと離したときの場所がずれててもOKなもんで、クリックした時では、イベントが発生した位置を取ることが出来ず、どのマスがクリックされたのかが分かりません。
 ので、マウス押した時を使います。

どのマスを押したか

 マウスXマウスYを取得して、どのマス上で押されたのか調べます。
 取得したマウスXマウスYそれぞれをマス幅で割ったら、列と行が分かるって寸法です。

どのマスを押したか.nako3
定数 ゲーム画面=描画中キャンバス。
定数 マス幅=100。
ゲーム画面をマウス押した時には
    列=(マウスX/マス幅)の整数部分。
    行=(マウスY/マス幅)の整数部分。
    番号=行*3+列。
    番号を言う。#テスト用
ここまで。

 できました☆

描画と手番交代

 マルバツゲームは、リバーシみたいに石が引っくり返ったり、将棋のように駒を動かしたりというのが一切無いので、深く考えず前回のマルバツ描画を呼び出して⭕か❌かを描画すればいいと思う。
 マスの番号は分かりました。
 マルバツゲームはパスが無いので、マルかバツかは単純にイベントが実行されるたびに手番を入れ替えて、それを描画してやれば良さげ。

描画と手番交代.nako3
定数 [マル,バツ]=[0,1]。
変数 [手数,手番]=[0,0]。

#(実際にはマウス押した時のイベント内)
番号に手番をマルバツ描画。
手数=手数+1。手番=手数%2。

 一般に先手がマルで後手がバツなので、マルは0、バツは1としています。(でもなんか海外では逆が主流らしい?!)

局面を記録

 でも、空いているマス以外をクリックした場合は描画しないようにしとかないと、同じトコに何度も上書きできてしまうので、画面に直接描くのとは別に現在の状態を覚えとかなきゃなりません。
 局面という配列を用意して、何も入ってない時(アキ)は-1とゆうことにします。
 最初に全てのマスをアキで初期化して、マルバツ描画するのと同時にそれを局面にも書き込んでおいて、アキじゃないマスが押された時には何もしないで戻るようにする。
 こんなかんじ?

人対人.nako3
#---宣言-----
定数 ゲーム画面=描画中キャンバス。
定数 マス幅=100。
定数 [アキ,マル,バツ]=[-1,0,1]。
変数 [手数,手番]=[0,0]。
変数 局面=空配列。
#-----------------------------------------------
画面描画。

# 初期化
番号を0から8まで繰り返す。
    局面[番号]=アキ。
ここまで。

#---イベント-----
ゲーム画面をマウス押した時には
    列=(マウスX/マス幅)の整数部分。
    行=(マウスY/マス幅)の整数部分。
    番号=行*3+列。

    もし、局面[番号]がアキでなければ、戻る。
    局面[番号]に手番を代入。
    番号に手番をマルバツ描画。
    手数=手数+1。手番=手数%2。
ここまで。

#---関数-----
●画面描画
    4に線太さ設定。黒色に線色設定。
    2回
        [マス幅*回数,0]から[マス幅*回数,マス幅*3]へ線描画。
        [0,マス幅*回数]から[マス幅*3,マス幅*回数]へ線描画。
    ここまで。
ここまで。

●(番号に記号を)マルバツ描画
    定数 [マル中点,マル半径,バツ始点,バツ終点,記号太さ]=[50,30,20,80,10]
    x=番号を3で割った余りにマス幅を掛ける。
    y=番号を3で割って、それの整数部分にマス幅を掛ける。
    「#DD3344」に線色設定。空に塗り色設定。記号太さに線太さ設定。
    もし、記号がマルならば、
        [x+マル中点,y+マル中点]にマル半径の円描画。
    違えば、もし、記号がバツならば、
        [x+バツ始点,y+バツ始点]から[x+バツ終点,y+バツ終点]まで線描画。
        [x+バツ始点,y+バツ終点]から[x+バツ終点,y+バツ始点]まで線描画。
    ここまで。
ここまで。

 できました!
 これでマス目上にマウスで交互に⭕❌を置いていけるので、ノートでやってたマルバツゲームが紙をムダにしないで出来るようになりました(スマホでも出来ますからね☆)
 まだ続きがあるので貯蔵庫にアップはしていませんが、これはこのままエディタに貼っ付けたら動きます。

勝敗判定と終局処理

 マルバツゲームの勝ったか負けたかくらい、分かりますけれどね。
 現状では、勝負が付いても全てのマスが埋まるまで、打ち続けることが出来ちゃいます。まあ、紙でやる場合と一緒ですよね。
 でも折角プログラムなんだから、勝負が付いたかどうか判定して教えて欲しいし、それ以上は打てないようにしたい。

勝敗判定

 どうすればいいですかねー? と、無い知恵を絞った結果、タテヨコナナメ、ようするに同じ記号が並んだら勝敗の付く全てのパターンを配列にしておいて、それを反復して、全部が同じ記号(アキ以外)になっているかどうかチェックする的な?
 タブンなんかもっと賢そうな手立てがありそうですけど・・・;
 こんな感じ?

勝敗判定.nako3
定数 パターン=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]。
定数 [引き分け,継続]=[-1,-2]
●勝敗判定
    パターンを反復
        変数[a,b,c]=対象。
        もし、(局面[a]≠アキ)かつ(局面[a]=局面[b])かつ(局面[a]=局面[c])ならば、局面[a]で戻る。#全部同じ記号(マル(0)かバツ(1))なので、その手番の側が勝ち。
    ここまで。
    もし、手数が8以上ならば、
        引き分けで戻る。#勝者が出ずに8マス全て埋まっている。
    違えば、
        継続で戻る。
    ここまで。
ここまで。

終局

 勝敗判定の結果が継続以外なら、どっちが勝ったかあるいは引き分けか言って、ついでにフラグを立ててマウス押しても何もしないで戻るようにしたら完成?
 chromeではなぜか描画より優先して言うのダイアログが上がっちゃうようで、最後の一手が表示されないまま終局のメッセージが出てしまうので、ちょっとウェイト入れました。

人対人(勝敗判定).nako3
#---宣言-----
定数 ゲーム画面=描画中キャンバス。
定数 マス幅=100。
定数 [アキ,マル,バツ]=[-1,0,1]
変数 [手数,手番]=[0,0]。
変数 局面=空配列。

#勝敗判定
定数 パターン=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]。
定数 [引き分け,継続]=[-1,-2]
定数 マルバツ=["⭕","❌"]
変数 ゲーム中=はい。
#-----------------------------------------------

画面描画。
番号を0から8まで繰り返す。局面[番号]=アキ。。。

#---イベント-----
ゲーム画面をマウス押した時には
    もし、ゲーム中がいいえならば、戻る。
    列=(マウスX/マス幅)の整数部分。
    行=(マウスY/マス幅)の整数部分。
    番号=行*3+列。

    もし、局面[番号]がアキでなければ、戻る。
    局面[番号]に手番を代入。
    番号に手番をマルバツ描画。

    0.1秒後には #chromeで描画より先にダイアログが上がっちゃうの防ぐため
        勝敗判定して結果に代入。
        もし、結果が継続ならば、
            手数=手数+1。手番=手数%2。
        違えば、
            結果で終局。
        ここまで。
    ここまで。
ここまで。

#---関数----------
#描画
●画面描画
    4に線太さ設定。黒色に線色設定。
    2回
        [マス幅*回数,0]から[マス幅*回数,マス幅*3]へ線描画。
        [0,マス幅*回数]から[マス幅*3,マス幅*回数]へ線描画。
    ここまで。
ここまで。

●(番号に記号を)マルバツ描画
    定数 [マル中点,マル半径,バツ始点,バツ終点,記号太さ]=[50,30,20,80,10]
    x=番号を3で割った余りにマス幅を掛ける。
    y=番号を3で割って、それの整数部分にマス幅を掛ける。
    「#DD3344」に線色設定。空に塗り色設定。記号太さに線太さ設定。
    もし、記号がマルならば、
        [x+マル中点,y+マル中点]にマル半径の円描画。
    違えば、もし、記号がバツならば、
        [x+バツ始点,y+バツ始点]から[x+バツ終点,y+バツ終点]まで線描画。
        [x+バツ始点,y+バツ終点]から[x+バツ終点,y+バツ始点]まで線描画。
    ここまで。
ここまで。

#勝敗判定
●勝敗判定
    パターンを反復
        変数[a,b,c]=対象。
        もし、(局面[a]≠アキ)かつ(局面[a]=局面[b])かつ(局面[a]=局面[c])ならば、局面[a]で戻る。#全部同じ記号(マル(0)かバツ(1))なので、その手番の側が勝ち。
    ここまで。
    もし、手数が8以上ならば、
        引き分けで戻る。#勝者が出ずに8マス全て埋まっている。
    違えば、
        継続で戻る。
    ここまで。
ここまで。

●(結果で)終局
    もし、結果が引き分けならば、
        「引き分け。」を言う。
    違えばもし、結果>引き分けならば、
        「{マルバツ[結果]}の勝ち。」を言う。
    ここまで。
    ゲーム中は、いいえ。
ここまで。

 できました!!

動作確認

つづきます

 勝敗を判定してくれるようになったとは言え、所詮は紙でやるのと同様、相手がいないとできないです。
 次は、コンピューターと遊べるようにします!

目次

  1. キャンバスにゲーム画面を描画
  2. 人対人で遊べるようにする
  3. 人対コンピューターで遊べるようにする
  4. ミニマックス法を学ぶ
  5. 最強のマルバツゲームできた☆
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?