ギガノトカップ

オセロ×オセロ

https://kamekame.mydns.jp/double_osero/entrance.html

C++

Python

JavaScript

オセロ×オセロ! 2色2対の盤面で繰り広げられるバトル!

Shinp

推しアイデア

なんと!!駒をひっくり返せれば隣の盤面の駒も一緒にひっくり返せます!お得!

作った背景

白黒二色の単純なゲームに戦略を加えるため

推し技術

C++のプログラムをWeb上で動作させる仕組み

プロジェクト詳細

1 概要

今までのオセロ体験を変える新感覚ゲーム

2 ゲームシステム

対CPUのソロプレイのみ対応しています

1.最初に盤面の大きさを決めます

2.画面遷移後に2枚のオセロ盤面が作られ image

3片方のオセロの駒をひっくり返すともう片方の駒もひっくり返ります。 image 4.この後、次の手をAIが置いてくれます

5.置ける駒がなくなれば終了し盤面の駒の数が多い方が勝利とします

おまけとして、プレイヤーがひっくり返した駒の合計をしたに表示しています、先に20枚ひっくり返した方が勝ち!みたいな遊び方もできます!

構造としては簡単ですが、お互いに影響しあうため先読みがかなり難しくなっています

戦略:

相変わらず、既存のオセロと同じように角をとると強いです 片方の盤面のみを進めると先読みしやすくなります 逆にめちゃくちゃに置くことで先読みを難しくし、運ゲーに持っていくこともできる

3 オセロAI(というか、アルゴリズム)

人が直前に打った盤面で探索開始、見つからなかったらもう一方の盤面で再度探索します。

 探索方法はminmax法を採用(それしかできないので)、「角>辺>中心>そのほか」の順でスコアを重みづけ、α-β刈りで探索回数を減らしています。

4 構成など技術面

今回のosero実行ファイルのクラス図 image

ブラウザーからosero実行ファイルを実行するまでの流れ image この方法であればC++でもWeb上で疑似的にですが動作させることができます。  ただ、通信環境が悪いとレスポンスが悪くなる上に、探索を行ってAIの手を作っているので盤面が大きくなると効率が落ちます  oseroゲームに関する盤面情報のやり取りはjsonファイル形式で行いました。

//osero実行ファイルに入力する形式 { "board": [ { "player": 1, "position": [0, 0] }, { "player": 2, "position": [0, 1] } ], //ここから下は任意入力 "move": [2, 3], "boardSize": 8, "flip": [ [2, 3], [2, 4] ] } //osero実行ファイルが出力する形式 { "board": [ { "player": 1, "position": [0, 0] }, { "player": 2, "position": [0, 1] } // ... 盤面上の全ての石 ], "flips": [ [2, 3], [2, 4] // ... 直近で裏返した石の座標(row, col) ], "endFlag": 0 }

デバッグ環境

  • c++ visual studio 2022
  • Flask-cors(python) visual studio codeとcurlコマンドでデバッグ
  • ブラウザ google chrome

5 おまけ

今回のハッカソン中よくわからないエラーが起きました。 以下の関数loadFromJsonForm()からJson形式で読み込むとエラーが発生した。

//JsonIO.cpp bool JsonIO::loadFromJsonForm() { Positions positions; //ここで読み取り std::string input( (std::istreambuf_iterator<char>(std::cin)), std::istreambuf_iterator<char>() ); json j = json::object();; std::cout << "Input JSON: " << input << std::endl; // デバッグ用に入力を表示 try { j = json::parse(input); } catch (const std::exception& e) { std::cerr << "Error reading JSON from stdin: " << e.what() << std::endl; return false; } ...
//実行結果 $ ./osero < sample.txt { "board": [ { "player": 1, "position": [0, 0] }, { "player": 2, "position": [0, 1] } ], "move": [2, 3], "boardSize": 8, "flip": [ [2, 3], [2, 4] ] } Error reading JSON from stdin: [json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON

このエラーはinputの中身がない事を警告しているのですが、実際にはinputにきちんとjson形式の文字列が入っていことがデバック画面で分かります。

原因はコンストラクタで読み取りを行っていたからっぽい

//JsonIO.cpp //JsonIOコンストラクタ JsonIO::JsonIO() { loadFromJsonForm(); }

面倒だと思わずにきちんとインスタンス化してから読み取りを行うとうまくいく

//main.cpp JsonIO json; json.loadFromJsonForm();
//実行結果 $ ./osero < sample.txt { "board": [ { "player": 1, "position": [0, 0] }, { "player": 2, "position": [0, 1] } ], "move": [2, 3], "boardSize": 8, "flip": [ [2, 3], [2, 4] ] }

Shinp

@9f503260c42ec010