▶ 実 行
▶ 実行
クリア
最強のマルバツゲーム
by 雪乃☆雫
#---宣言----- 定数 ゲーム画面=描画中キャンバス。 定数 マス幅=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,1]。 変数 [人間,COM]=[先攻,後攻]。 変数 プレイヤー=空配列。 変数 レベル=2。 定数 キャラ=["パコ","ナコ","なでしこ君"] 変数 次着手=空。 #----------------------------------------------- #テスト用 盤面=[-1,0,-1,-1,-1,0,1,1,0]。 //盤面でテスト。 #----------------------------------------------- ゲーム開始。 #---イベント----- ゲーム画面をマウス押した時には もし、ゲーム中がいいえならば、戻る。 もし、手番がCOMならば、戻る。 列=(マウスX/マス幅)を整数変換。 行=(マウスY/マス幅)を整数変換。 番号=行*3+列。 番号へ打つ。 ここまで。 #---関数---------- ●ゲーム開始 人間=2の乱数。COM=(人間+1)%2。//先攻後攻決め 対戦相手選択。 初期化。 もし、COMが先攻ならば、COM着手。 ここまで。 ●対戦相手選択 「レベル選択。数字を入力して下さい。{改行}未入力の場合はレベル2になります。{改行}0、よわい / 1、ふつう / 2、つよい」を尋ねる。 レベルはそれを整数変換。。 もし、(レベルが0以上)かつ(レベルが2以下)でなければ、レベルは2。 「レベル{レベル}。{キャラ[レベル]}がお相手します。」を言う。 ここまで。 ●初期化 画面描画。 番号を0から8まで繰り返す。局面[番号]=アキ。。。 手数=0。手番=0。ゲーム中は、はい。 プレイヤー[人間]=「あなた」。プレイヤー[COM]=キャラ[レベル]。 「先攻は{プレイヤー[先攻]}です。後攻は{プレイヤー[後攻]}です。」と言う。 ここまで。 ●新規ゲーム 人間=(人間+1)%2。COM=(COM+1)%2。//先攻後攻入れ替え 初期化。 もし、COMが先攻ならば、COM着手。 ここまで。 #描画 ●画面描画 全描画クリア。 4に線太さ設定。黒色に線色設定。 2回 [マス幅*回数,0]から[マス幅*回数,マス幅*3]へ線描画。 [0,マス幅*回数]から[マス幅*3,マス幅*回数]へ線描画。 ここまで。 ここまで。 ●(番号に記号を)マルバツ描画 定数 [マル中点,マル半径,バツ始点,バツ終点,文字x,文字y,記号太さ,文字サイズ]=[50,30,20,80,15,75,10,72] x=番号を3で割った余りにマス幅を掛ける。 y=番号を3で割って、それの整数部分にマス幅を掛ける。 「#DD3344」に線色設定。空に塗り色設定。記号太さに線太さ設定。 もし、記号がマルならば、 [x+マル中点,y+マル中点]にマル半径の円描画。 違えば、もし、記号がバツならば、 [x+バツ始点,y+バツ始点]から[x+バツ終点,y+バツ終点]まで線描画。 [x+バツ始点,y+バツ終点]から[x+バツ終点,y+バツ始点]まで線描画。 違えば、 文字サイズに描画フォント設定。 [x+文字x,y+文字y]に記号を文字描画。 ここまで。 ここまで。 ●(番号へ)打つ もし、局面[番号]がアキでなければ、戻る。 局面[番号]に手番を代入。 番号に手番をマルバツ描画。 0.1秒後には //chromeで描画より先にダイアログが上がっちゃうの防ぐため 局面の勝敗判定して結果に代入。 もし、結果が継続ならば、 手数=手数+1。手番=手数%2。 もし、手番がCOMならば、 COM着手。 ここまで。 違えば、 結果で終局。 ここまで。 ここまで。 ここまで。 #勝敗判定 ●(局面の)勝敗判定 パターンを反復 変数[a,b,c]=対象。 もし、(局面[a]≠アキ)かつ(局面[a]=局面[b])かつ(局面[a]=局面[c])ならば、局面[a]で戻る。 ここまで。 もし、手数が8以上ならば、 引き分けで戻る。 違えば、 継続で戻る。 ここまで。 ここまで。 ●(結果で)終局 もし、結果が引き分けならば、 「引き分け。」を言う。 違えばもし、結果>引き分けならば、 「{プレイヤー[結果]}の勝ち。」を言う。 ここまで。 ゲーム中は、いいえ。 「続ける?」で二択。 もし、それがはいならば、新規ゲーム。 ここまで。 #コンピューターが打つ ●COM着手 レベルで条件分岐。 0ならば、レベル0。。。 1ならば、レベル1。。。 2ならば、レベル2。。。 ここまで。 ここまで。 #空いてる所へランダムに打つ ●レベル0 着手可能マス=局面の着手可能マス確認。 着手可能マス[(着手可能マスの要素数)の乱数]へ打つ。 ここまで。 #同じ記号が2つあったら止める ●レベル1 パターンを反復 変数[a,b,c]=対象。 もし、(局面[b]≠アキ)かつ(局面[b]=局面[c])かつ(局面[a]=アキ)ならば、 aへ打って戻る。 違えば、もし、(局面[a]≠アキ)かつ(局面[a]=局面[c])かつ(局面[b]=アキ)ならば、 bへ打って戻る。 違えば、もし、(局面[a]≠アキ)かつ(局面[a]=局面[b])かつ(局面[c]=アキ)ならば、 cへ打って戻る。 ここまで。 ここまで。 レベル0。 ここまで。 ●レベル2 # 一手目が遅いので定石で打たせる 四隅=[0,2,6,8]。中央=4。 もし、手数=0ならば、 四隅[4の乱数]へ打つ。 # 先手一手目なら4隅のどれかを取る。 違えば、もし、手数=1ならば、 もし、局面[中央]=アキならば、中央へ打つ。 # 後手一手目は中央が空いていれば中央を取る。 違えば、四隅[4の乱数]へ打つ。 # 先手が中央を打っていた場合は4隅のどれかを取る。 違えば、 # ミニマックス法 手数で局面の良手探索。 次着手へ打つ。 ここまで。 ここまで。 ●(局面の)着手可能マス確認 着手可能マスは空配列。 局面を反復 もし、対象がアキならば、着手可能マスに対象キーを配列追加。 ここまで。 着手可能マスで戻る。 ここまで。 ●(深さと勝敗で)得点計算 勝敗で条件分岐。 COMならば、10-深さで戻る。。。 人間ならば、深さ-10で戻る。。。 引き分けならば、0で戻る。。。 ここまで ここまで。 ●(仮手数で盤面の)良手探索 着手リスト=空配列。得点リスト=空配列。仮手番=仮手数%2。深さ=仮手数-手数。 着手可能マス=盤面の着手可能マス確認。 もし、手数=8ならば、次着手=着手可能マス。 # ゲームが終わる場合、COM側から見た得点を返す 結果=盤面の勝敗判定。 もし、結果が継続でなければ、深さと結果で得点計算して戻る。 # そうでない場合、選択可能なそれぞれの手に置いたと仮定した仮盤面を作成 着手可能マスを反復 着手候補=対象。仮盤面=盤面を配列複製。 仮盤面[対象]=仮手番。 得点=仮手数+1で仮盤面の良手探索。 # 再帰 得点リストに得点を配列追加。 # その状態のミニマックスの結果を追加する 着手リストに着手候補を配列追加。 ここまで。 もし、得点リスト=空ならば、戻る。 # COMの番であれば、得点リストから最大点数を返す もし、仮手番=COMならば、 番号=得点リストから(得点リストの配列最大値)を配列検索。 次着手=着手リスト[番号] 得点リスト[番号]で戻る。 # 人間の番であれば、得点リストから最小点数を返す 違えば、 番号=得点リストから(得点リストの配列最小値)を配列検索。 次着手=着手リスト[番号] 得点リスト[番号]で戻る。 ここまで。 ここまで。 #----------------------------------------------- #テスト用 ●(盤面で|盤面を)盤面描画 画面描画。 数を0から8まで繰り返す 価=盤面[数] もし、価がアキでなければ、 数に価をマルバツ描画。 ここまで。 ここまで。 ここまで。 ●(盤面で)テスト 画面描画。 手数=0。 盤面を反復 もし、対象がアキでなければ、手数=手数+1。 ここまで。 手番=手数%2。COM=手番。人間=(手番+1)%2。 盤面で盤面描画。 手数で盤面の良手探索。 次着手に「⭐」をマルバツ描画。 ここまで。
b8ce75b37ee0cb6528a6c592477d4971
868