diff --git a/Reversi.xcodeproj/project.pbxproj b/Reversi.xcodeproj/project.pbxproj index e848d38..ce15076 100755 --- a/Reversi.xcodeproj/project.pbxproj +++ b/Reversi.xcodeproj/project.pbxproj @@ -48,6 +48,8 @@ 5A6E83F52C81BD6300186022 /* draw.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A6E83E52C81BD6300186022 /* draw.png */; }; 5A6E83F62C81BD6300186022 /* icon_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A6E83E72C81BD6300186022 /* icon_256x256.png */; }; 5A6E83F72C81BD6300186022 /* blackb.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A6E83E42C81BD6300186022 /* blackb.png */; }; + 5AA651EF2CDE30BA005E7F17 /* thinking.png in Resources */ = {isa = PBXBuildFile; fileRef = 5AA651EC2CDE30BA005E7F17 /* thinking.png */; }; + 5AA651F12CDE310B005E7F17 /* win.png in Resources */ = {isa = PBXBuildFile; fileRef = 5AA651F02CDE310B005E7F17 /* win.png */; }; 5AD6D2BF2C81CCF000CC2850 /* reversi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5AD6D2BD2C81CCF000CC2850 /* reversi.cpp */; }; /* End PBXBuildFile section */ @@ -95,6 +97,8 @@ 5A6E83E92C81BD6300186022 /* null.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = null.png; sourceTree = ""; }; 5A6E83EB2C81BD6300186022 /* white.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = white.png; sourceTree = ""; }; 5A6E83EC2C81BD6300186022 /* whiteb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = whiteb.png; sourceTree = ""; }; + 5AA651EC2CDE30BA005E7F17 /* thinking.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thinking.png; sourceTree = ""; }; + 5AA651F02CDE310B005E7F17 /* win.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = win.png; sourceTree = ""; }; 5AD6D2BC2C81CCF000CC2850 /* reversi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = reversi.h; sourceTree = ""; }; 5AD6D2BD2C81CCF000CC2850 /* reversi.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = reversi.cpp; sourceTree = ""; }; 5AD6D2BE2C81CCF000CC2850 /* variables.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = variables.h; sourceTree = ""; }; @@ -217,6 +221,8 @@ 5A6E83E72C81BD6300186022 /* icon_256x256.png */, 5A6E83E82C81BD6300186022 /* lose.png */, 5A6E83E92C81BD6300186022 /* null.png */, + 5AA651EC2CDE30BA005E7F17 /* thinking.png */, + 5AA651F02CDE310B005E7F17 /* win.png */, 5A2671032CD8F9B500BBF6C7 /* nullb.png */, 5A6E83EB2C81BD6300186022 /* white.png */, 5A6E83EC2C81BD6300186022 /* whiteb.png */, @@ -291,6 +297,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5AA651F12CDE310B005E7F17 /* win.png in Resources */, 2C6906D82298140F00A427D0 /* engine in Resources */, 5A6E83EE2C81BD6300186022 /* lose.png in Resources */, 5A2671062CD8FB7000BBF6C7 /* title.png in Resources */, @@ -304,6 +311,7 @@ 5A6E83F62C81BD6300186022 /* icon_256x256.png in Resources */, 5A6E83F72C81BD6300186022 /* blackb.png in Resources */, 2C1778A31CE0B65500BB8AD0 /* icon.icns in Resources */, + 5AA651EF2CDE30BA005E7F17 /* thinking.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -439,6 +447,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; + GCC_FAST_MATH = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -446,6 +455,7 @@ "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_UNROLL_LOOPS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -478,6 +488,7 @@ ../../lib/macOS/opus, ../../lib/macOS/zlib, ); + LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -531,8 +542,11 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_FAST_MATH = YES; GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 3; GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_UNROLL_LOOPS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -565,6 +579,7 @@ ../../lib/macOS/opus, ../../lib/macOS/zlib, ); + LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = YES; diff --git a/assets/draw.png b/assets/draw.png index da67541..b6975ea 100644 Binary files a/assets/draw.png and b/assets/draw.png differ diff --git a/assets/hako.png b/assets/hako.png index a59aae9..8f08e18 100644 Binary files a/assets/hako.png and b/assets/hako.png differ diff --git a/assets/lose.png b/assets/lose.png index 37077a7..175c400 100644 Binary files a/assets/lose.png and b/assets/lose.png differ diff --git a/assets/thinking.png b/assets/thinking.png new file mode 100644 index 0000000..e561299 Binary files /dev/null and b/assets/thinking.png differ diff --git a/assets/win.png b/assets/win.png new file mode 100644 index 0000000..34324a5 Binary files /dev/null and b/assets/win.png differ diff --git a/src/Main.cpp b/src/Main.cpp index c11e7ed..edb97d1 100755 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -4,46 +4,48 @@ using namespace std; using App = SceneManager; -void DrawBoard(const Texture &null, const Texture &nullb, const Texture &black, const Texture &blackb, const Texture &white, const Texture &whiteb, const auto &stone_size, const auto &stone_edge) { +int stone_edge, stone_size; + +void DrawBoard() { uint64_t mask = 0x8000000000000000ULL; - uint64_t legalboard = makelegalboard(b.playerboard, b.opponentboard); +// uint64_t legalboard = makelegalboard(b.playerboard, b.opponentboard); for (int y = 0; y < 8; ++y) { for (int x = 0; x < 8; ++x) { if(nowTurn == BLACK_TURN) { if(b.playerboard & mask) { if(tmpy == y && tmpx == x) { - blackb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"blackb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - black.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"black").draw(stone_edge+stone_size*x, 10+stone_size*y); } } else if(b.opponentboard & mask) { if(tmpy == y && tmpx == x) { - whiteb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"whiteb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - white.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"white").draw(stone_edge+stone_size*x, 10+stone_size*y); } } else if((botplayer == WHITE_TURN && (legalboard & mask) != 0)) { - nullb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"nullb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - null.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"null").draw(stone_edge+stone_size*x, 10+stone_size*y); } } else { if(b.opponentboard & mask) { if(tmpy == y && tmpx == x) { - blackb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"blackb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - black.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"black").draw(stone_edge+stone_size*x, 10+stone_size*y); } } else if(b.playerboard & mask) { if(tmpy == y && tmpx == x) { - whiteb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"whiteb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - white.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"white").draw(stone_edge+stone_size*x, 10+stone_size*y); } } else if((botplayer == BLACK_TURN && (legalboard & mask) != 0)) { - nullb.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"nullb").draw(stone_edge+stone_size*x, 10+stone_size*y); } else { - null.draw(stone_edge+stone_size*x, 10+stone_size*y); + TextureAsset(U"null").draw(stone_edge+stone_size*x, 10+stone_size*y); } } mask >>=1; @@ -63,19 +65,24 @@ void Main() Font font{FontMethod::MSDF, 48}; Font result_font{FontMethod::MSDF, 20}; //画像読み込み - const Texture null(U"../assets/null.png"); - const Texture nullb(U"../assets/nullb.png"); - const Texture white(U"../assets/white.png"); - const Texture whiteb(U"../assets/whiteb.png"); - const Texture black(U"../assets/black.png"); - const Texture blackb(U"../assets/blackb.png"); - const Texture title(U"../assets/title.png"); + TextureAsset::Register(U"null", U"../assets/null.png"); + TextureAsset::Register(U"nullb", U"../assets/nullb.png"); + TextureAsset::Register(U"white", U"../assets/white.png"); + TextureAsset::Register(U"whiteb", U"../assets/whiteb.png"); + TextureAsset::Register(U"black", U"../assets/black.png"); + TextureAsset::Register(U"blackb", U"../assets/blackb.png"); + TextureAsset::Register(U"title", U"../assets/title.png"); + TextureAsset::Register(U"hako_default", U"../assets/hako.png"); + TextureAsset::Register(U"hako_thinking", U"../assets/thinking.png"); + TextureAsset::Register(U"hako_lose", U"../assets/lose.png"); + TextureAsset::Register(U"hako_win", U"../assets/win.png"); //サイズ取得 & 計算 - const auto stone_edge = (800-(null.width()*8))/2; - const auto stone_size = null.width(); - const auto title_size = title.width(); - const auto title_edge = (800-title.width())/2; + stone_edge = (800-(TextureAsset(U"null").width()*8))/2; + stone_size = TextureAsset(U"null").width(); + const auto title_size = TextureAsset(U"title").width(); + const auto title_edge = (800-TextureAsset(U"title").width())/2; Window::Resize(800, 700); + Window::SetTitle(U"オセロ"); //石の座標の配列 Array button_array(0); button_array.reserve(64); @@ -93,12 +100,23 @@ void Main() const Array player_turn = {U"白", U"黒"}; //ゲームが開始しているか int game_status = 0; + int winner = 0; //AIの実行結果 AsyncTask result; + //ハコくんのテキストBox + constexpr Rect hako_text_box(260, 475, 400, 100); + //ハコくんのテキスト + const String hako_text_default = U"君の番だよ!\n置く場所を選んでね!"; + const String hako_text_win = U"君の勝ち!"; + const String hako_text_lose = U"僕の勝ち!"; + const String hako_text_draw = U"引き分け!"; + + int black_stone_count = 0, white_stone_count = 0; + while (System::Update()) { if (game_status == 0) { - title.draw(title_edge, 0); + TextureAsset(U"title").draw(title_edge, 0); font(U"レベル").draw(25, 10, 455); font(U"プレイヤー").draw(25, 200, 455); if (SimpleGUI::RadioButtons(level_index, AI_level, Vec2(100, 455))) { @@ -113,8 +131,26 @@ void Main() reset(); } } else if (game_status == 1) { - if (isFinished()) game_status = 3; + if (isFinished()) { + game_status = 3; + if (nowTurn == BLACK_TURN) { + black_stone_count = __builtin_popcountll(b.playerboard); + white_stone_count = __builtin_popcountll(b.opponentboard); + } else { + white_stone_count = __builtin_popcountll(b.playerboard); + black_stone_count = __builtin_popcountll(b.opponentboard); + } + if ((botplayer == 0 && black_stone_count > white_stone_count) || (botplayer == 1 && white_stone_count > black_stone_count)) { + winner = 0; + } else if ((botplayer == 1 && black_stone_count > white_stone_count) || (botplayer == 0 && white_stone_count > black_stone_count)) { + winner = 1; + } else { + winner = 2; + } + } if (nowTurn == botplayer) { + TextureAsset(U"hako_thinking").draw(200, 475); + result_font(U"考え中...({:0>2}%)\n※時間がかかる場合があります"_fmt(think_percent)).draw(hako_text_box, Palette::White); if (!result.isValid()) { System::Sleep(200); result = Async(ai); @@ -124,6 +160,10 @@ void Main() swapboard(); } } + } else { + TextureAsset(U"hako_default").draw(200, 475); + result_font(hako_text_default).draw(hako_text_box, Palette::White); + } for (int i = 0; i < 64; ++i) { if (button_array[i].leftClicked() && button_array[i].mouseOver()) { @@ -145,14 +185,28 @@ void Main() game_status = 0; } } - DrawBoard(null, nullb, black, blackb, white, whiteb, stone_size, stone_edge); + DrawBoard(); } else { - if (nowTurn == BLACK_TURN) { - result_font(U"黒: {:0>2}, 白: {:0>2}"_fmt(__builtin_popcountll(b.playerboard),__builtin_popcountll(b.opponentboard))).drawAt(400, 550); - } else { - result_font(U"黒: {:0>2}, 白: {:0>2}"_fmt(__builtin_popcountll(b.opponentboard),__builtin_popcountll(b.playerboard))).drawAt(400, 550); + result_font(U"黒: {:0>2}, 白: {:0>2}"_fmt(black_stone_count, white_stone_count)).drawAt(400, 600); + result_font(U"勝者: {}"_fmt((black_stone_count > white_stone_count) ? U"黒" : (black_stone_count < white_stone_count) ? U"白" : U"引き分け")).drawAt(400, 625); + switch (winner) { + case 0: + TextureAsset(U"hako_lose").draw(200, 475); + result_font(hako_text_lose).draw(hako_text_box, Palette::White); + break; + case 1: + TextureAsset(U"hako_win").draw(200, 475); + result_font(hako_text_win).draw(hako_text_box, Palette::White); + break; + default: + TextureAsset(U"hako_draw").draw(200, 475); + result_font(hako_text_draw).draw(hako_text_box, Palette::White); + break; + } + if (SimpleGUI::Button(U"閉じる", Vec2{350, 650}, 100)) { + game_status = 0; } - DrawBoard(null, nullb, black, blackb, white, whiteb, stone_size, stone_edge); + DrawBoard(); } } if (result.isValid()) { diff --git a/src/reversi.cpp b/src/reversi.cpp index f8da793..6c9f3ef 100644 --- a/src/reversi.cpp +++ b/src/reversi.cpp @@ -18,6 +18,7 @@ void reset() { b.opponentboard = 0x0000001008000000ULL; // b.playerboard = 0x00141eae978bc0fe; // b.opponentboard = 0x2020e05068743e00; + legalboard = makelegalboard(b.playerboard, b.opponentboard); printf("DEPTH: %d\n", DEPTH); printf("Player: %d\n", botplayer); return; @@ -140,6 +141,7 @@ bool isFinished() { void swapboard() { swap(b.playerboard, b.opponentboard); nowTurn = 1-nowTurn; + legalboard = makelegalboard(b.playerboard, b.opponentboard); } inline int move_ordering_value(uint64_t &playerboard, uint64_t &opponentboard) { @@ -381,6 +383,7 @@ int ai() { int putable_count = __builtin_popcountll(legalboard); if (putable_count == 0) { swapboard(); + return 0; } visited_nodes = 0; int score = 0; diff --git a/src/reversi.h b/src/reversi.h index bba55fb..f6c6c91 100644 --- a/src/reversi.h +++ b/src/reversi.h @@ -35,7 +35,7 @@ extern char whitec; extern char blackc; extern char tmpx, tmpy; extern uint64_t tmpbit; -extern char think_percent; +extern int think_percent; extern char think_count; extern char botplayer; extern char nowTurn; diff --git a/src/variables.h b/src/variables.h index 3c1bb64..71821ac 100644 --- a/src/variables.h +++ b/src/variables.h @@ -20,7 +20,7 @@ char whitec; char blackc; char tmpx, tmpy; uint64_t tmpbit; -char think_percent; +int think_percent; char think_count; char botplayer; char nowTurn;