コード:
#include "DxLib.h" // DxLib
#include <iostream> // cerr
#include <array> // array
#include <vector> // vector
#include <functional> // function
#include <memory> // unique_ptr
#include <crtdbg.h> // _CrtSetDbgFlag
// DXライブラリ簡易ラップクラス
struct DxLibApp final
{
DxLibApp(const char* pWindowText = nullptr) try
: windowWidth_(384)
, windowHeight_(384)
, colorBitDepth_(32)
{
if (pWindowText != nullptr){
DxLib::SetWindowText(pWindowText);
}
SetGraphMode(windowWidth_, windowHeight_, colorBitDepth_);
ChangeWindowMode(TRUE);
if (DxLib_Init() == -1){
throw "DXライブラリの初期化に失敗しました。";
}
SetDrawScreen(DX_SCREEN_BACK);
}
catch (char* errStr) {
std::cerr << errStr << std::endl;
}
~DxLibApp(){
DxLib_End();
}
static bool ProcessLoop(){
return (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0);
}
int windowWidth_; // ウィンドウ横幅
int windowHeight_; // ウィンドウ縦幅
int colorBitDepth_; // カラービット数
};
// 簡易入力クラス
struct InputKey final
{
InputKey()
: keyBuffer_()
, backKeyBuffer_()
{}
~InputKey(){}
inline int Update() {
std::copy(keyBuffer_.begin(), keyBuffer_.end(), backKeyBuffer_.begin());
return GetHitKeyStateAll(&keyBuffer_.front());
}
inline bool IsPress(const int keyCode) const {
return keyBuffer_[keyCode] ? true : false;
}
inline bool IsDown(const int keyCode) const {
return (keyBuffer_[keyCode] && !backKeyBuffer_[keyCode]);
}
inline bool IsUp(const int keyCode) const {
return (!keyBuffer_[keyCode] && backKeyBuffer_[keyCode]);
}
private:
typedef std::array<char, 256> KeyStateBuffer;
KeyStateBuffer keyBuffer_;
KeyStateBuffer backKeyBuffer_;
};
// 色定義
struct Color final
{
// Color型の内容
union {
unsigned long value;
std::array<unsigned char, 4> d;
struct {
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;
};
};
// コンパイル時定数
template <unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255>
struct GetColor_RGBA final {
enum : unsigned long {
value = static_cast<unsigned long>(((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff))
};
};
static const unsigned int White = GetColor_RGBA<255, 255, 255>::value;
// アサート
static_assert(sizeof(unsigned long) == (sizeof(unsigned char) * 4), "Color型が正常に動作しない環境です。");
};
// グローバル変数
static DxLibApp app("シーン変更");
static InputKey inputKey;
// シーン列挙
enum eScene : unsigned int
{
Scene_Top, // トップ画面
Scene_Game, // ゲーム画面
Scene_Count // シーン数
};
// Taskインターフェース
struct ITask {
enum CommonResult : int
{
Result_OK = 0,
Result_Faile = -1
};
virtual int Init() = 0; // 初期処理
virtual int End() = 0; // 終了処理
virtual int Update() = 0; // 更新処理
virtual int Draw() = 0; // 描画処理
};
// Sceneインターフェース
struct IScene : public ITask
{
IScene(){}
virtual ~IScene(){}
virtual void ChangeScene(eScene scene) = 0;
};
// Sceneアブストラクト
// (規定の動作を実装するクラス 必要に応じて継承して使う)
struct BaseScene : public IScene
{
BaseScene(){}
virtual ~BaseScene(){}
virtual int Init() override {
return CommonResult::Result_OK;
}
virtual int End() override {
return CommonResult::Result_OK;
}
};
// シーンコントローラ
struct SceneController final : public IScene
{
SceneController()
: sceneIndex_(0)
, sceneArrayList_()
{}
~SceneController(){}
// Topシーン
// (※ インナーが嫌だったら、適当にファイル分割して外に出す)
struct TopScene final : public IScene
{
TopScene()
: pSceneController_(nullptr)
{}
TopScene(SceneController* pSceneController)
: pSceneController_(pSceneController)
{}
~TopScene(){}
int Init() override {
return CommonResult::Result_OK;
}
int End() override {
return CommonResult::Result_OK;
}
int Update() override {
if (inputKey.IsDown(KEY_INPUT_Z)){
this->ChangeScene(eScene::Scene_Game);
}
return CommonResult::Result_OK;
}
int Draw() override {
DrawString(0, 0, "トップシーン\n(Zキーでゲームシーンに変更)", Color::White);
return CommonResult::Result_OK;
}
void ChangeScene(eScene scene) override {
pSceneController_->ChangeScene(scene);
}
private:
SceneController* pSceneController_;
};
// ゲームシーン
// (※ インナーが嫌だったら、適当にファイル分割して外に出す)
struct GameScene final : public IScene
{
GameScene()
: GameScene(nullptr)
{}
GameScene(SceneController* pSceneController)
: pSceneController_(pSceneController)
, board()
, msg()
, msg_wait()
, think({{
std::bind(&GameScene::think1, this, std::placeholders::_1),
std::bind(&GameScene::think2, this, std::placeholders::_1)
}})
, pieces()
, back()
, status(2)
, turn(1)
{
}
~GameScene(){}
int Init() override {
DxLib::LoadDivGraph("piece.png", 2, 2, 1, 48, 48, &pieces.front());
back = DxLib::LoadGraph("back.png");
board[3][3] = board[4][4] = 1;
board[4][3] = board[3][4] = 2;
setMsg(turn, 0);
return CommonResult::Result_OK;
}
int End() override {
DxLib::InitGraph();
return CommonResult::Result_OK;
}
int Update() override {
if (inputKey.IsDown(KEY_INPUT_Z)){
this->ChangeScene(eScene::Scene_Top);
}
switch (status) {
case 1:
if (isPass(turn)) {
setMsg(turn, 1);
status = 3;
}
else {
if (think[turn - 1](turn)) {
turn = 3 - turn; status = 2;
setMsg(turn, 0);
}
}
if (checkResult()) status = 4;
break;
case 2:
if (msg_wait > 0) msg_wait--;
else status = 1;
break;
case 3:
if (msg_wait > 0) msg_wait--;
else {
turn = 3 - turn; status = 2;
setMsg(turn, 0);
}
break;
}
return CommonResult::Result_OK;
}
int Draw() override {
DrawGraph(0, 0, back, FALSE);
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) {
if (board[y][x]) DrawGraph(x * 48, y * 48, pieces[board[y][x] - 1], TRUE);
}
if (status > 1) {
int mw = DxLib::GetDrawStringWidth(msg.c_str(), msg.size());
DxLib::DrawBox(192 - mw / 2 - 30, 172, 192 + mw / 2 + 30, 208, Color::GetColor_RGBA<200, 180, 150>::value, TRUE);
DrawString(192 - mw / 2, 182, msg.c_str(), Color::White);
}
return CommonResult::Result_OK;
}
void ChangeScene(eScene scene) override {
pSceneController_->ChangeScene(scene);
}
private:
// 指定した位置にコマを置く
int putPiece(int x, int y, int turn, bool put_flag) {
int sum = 0;
if (board[y][x] > 0) return 0;
for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) {
int wx[8], wy[8];
for (int wn = 0;; wn++) {
int kx = x + dx * (wn + 1); int ky = y + dy * (wn + 1);
if (kx < 0 || kx > 7 || ky < 0 || ky > 7 || board[ky][kx] == 0) break;
if (board[ky][kx] == turn) {
if (put_flag) for (int i = 0; i < wn; i++) board[wy[i]][wx[i]] = turn;
sum += wn;
break;
}
wx[wn] = kx; wy[wn] = ky;
}
}
if (sum > 0 && put_flag) board[y][x] = turn;
return sum;
}
// パスチェック
bool isPass(int turn) {
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) {
if (putPiece(x, y, turn, false)) return false;
}
return true;
}
// 思考ルーチン1 プレイヤー
bool think1(int turn) {
static bool mouse_flag = false;
if (DxLib::GetMouseInput() & MOUSE_INPUT_LEFT) {
if (!mouse_flag) {
mouse_flag = true;
int mx, my;
DxLib::GetMousePoint(&mx, &my);
if (putPiece(mx / 48, my / 48, turn, true)) return true;
}
}
else mouse_flag = false;
return false;
}
// 思考ルーチン2 最も多く取れるところに置く
bool think2(int turn) {
int max = 0, wx, wy;
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) {
int num = putPiece(x, y, turn, false);
if (max < num || (max == num && GetRand(1) == 0)) {
max = num; wx = x; wy = y;
}
}
putPiece(wx, wy, turn, true);
return true;
}
// 思考ルーチン3 優先順位の高いところに置く
bool think3(int turn) {
static const int priority[8][8] = {
{ 0, 6, 2, 1, 1, 2, 6, 0 },
{ 6, 6, 5, 4, 4, 5, 6, 6 },
{ 2, 5, 2, 3, 3, 2, 5, 2 },
{ 1, 4, 3, 3, 3, 3, 4, 1 },
{ 1, 4, 3, 3, 3, 3, 4, 1 },
{ 2, 5, 2, 3, 3, 2, 5, 2 },
{ 6, 6, 5, 4, 4, 5, 6, 6 },
{ 0, 6, 2, 1, 1, 2, 6, 0 },
};
int max = 0, wx, wy;
for (int p = 0; p <= 6 && max == 0; p++) {
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) {
if (priority[y][x] != p) continue;
int num = putPiece(x, y, turn, false);
if (max < num || (max == num && GetRand(1) == 0)) {
max = num; wx = x; wy = y;
}
}
}
putPiece(wx, wy, turn, true);
return true;
}
// メッセージセット
// turn ... 1:BLACK 2:WHITE 3:DRAW
// type ... 0:TURN 1:PASS 2:WIN!
void setMsg(int turn, int type) {
std::string turn_str[] = { "黒", "白", "DRAW" };
std::string type_str[] = { "ターン", "パス", "勝利!" };
msg = turn_str[turn - 1];
if (turn != 3) msg += " " + type_str[type];
msg_wait = 50;
}
// 勝敗チェック
int checkResult() {
int pnum[2] = {};
int result = 0;
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) {
if (board[y][x] > 0) pnum[board[y][x] - 1]++;
}
if (isPass(1) && isPass(2)) {
if (pnum[0] > pnum[1]) result = 1;
else if (pnum[0] < pnum[1]) result = 2;
else result = 3;
}
if (result) setMsg(result, 2);
return result;
}
private:
SceneController* pSceneController_;
template <unsigned int size>
struct Board {
typedef std::array<std::array<int, size>, size> Type;
};
Board<8>::Type board; // 盤のデータ(0:なし 1:黒コマ 2:白コマ)
std::string msg;
int msg_wait;
std::array<std::function<bool(int)>, 2> think;
std::array<int, 2> pieces;
int back;
int status; // 1:プレイ中 2:TURNメッセージ中 3:パスメッセージ中 4:終了
int turn; // 1:黒ターン 2:白ターン
};
int Init() override
{
// シーン登録
sceneArrayList_.clear();
sceneArrayList_.emplace_back(new (std::nothrow) TopScene(this));
sceneArrayList_.emplace_back(new (std::nothrow) GameScene(this));
// シーンの作成に失敗していたらfalseを戻す
for (auto it = sceneArrayList_.begin(); it != sceneArrayList_.end(); ++it) {
if (!(*it)){
return CommonResult::Result_Faile;
}
}
sceneIndex_ = eScene::Scene_Top;
return sceneArrayList_[sceneIndex_]->Init();
}
int End() override {
return sceneArrayList_[sceneIndex_]->End();
}
int Update() override {
return sceneArrayList_[sceneIndex_]->Update();
}
int Draw() override {
return sceneArrayList_[sceneIndex_]->Draw();
}
void ChangeScene(eScene scene) {
// 現在のシーンを終了し、変更後のシーンの初期化
sceneArrayList_[sceneIndex_]->End();
sceneIndex_ = scene;
sceneArrayList_[sceneIndex_]->Init();
}
private:
unsigned int sceneIndex_;
std::vector<std::unique_ptr<IScene>> sceneArrayList_;
};
// エントリーポイント
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// メモリリーク検出
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
SceneController sceneController;
if (sceneController.Init() != ITask::CommonResult::Result_OK){
return -1;
}
while (DxLibApp::ProcessLoop() && inputKey.Update() == 0)
{
sceneController.Update();
sceneController.Draw();
}
if (sceneController.End() != ITask::CommonResult::Result_OK){
return -1;
}
return 0;
}