Skip to content

Commit

Permalink
Add -Wswitch-enum
Browse files Browse the repository at this point in the history
  • Loading branch information
casavaca committed Jan 16, 2024
1 parent 2d45a05 commit e0443c5
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 58 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:-DDEBUG>)
target_link_libraries (${PROJECT_NAME} PRIVATE raylib raylib_cpp CLI11::CLI11)

if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-pedantic -Wimplicit-fallthrough -Wall -Wextra -Wno-unused-function -Wno-sign-compare -Werror>)
target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-pedantic -Wimplicit-fallthrough -Wswitch-enum -Wall -Wextra -Wno-unused-function -Wno-sign-compare -Werror>)
endif()

if (WIN32)
Expand Down
32 changes: 13 additions & 19 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ static constexpr TileType TxtMap(char c) {
case '.': return TILE_TARGET;
case '_': return TILE_NULL;
default:
assert(false);
UNREACHABLE();
return TILE_NULL;
}
}
Expand All @@ -30,6 +30,7 @@ bool Sokoban::LoadLevel(const Level& level) {
state = vector<vector<TileType>>(level.lines.size());
std::transform(level.lines.begin(), level.lines.end(), state.begin(), [](const string& s)->vector<TileType>{
// one liner in C++23 but we are just using C++17...
assert(s.find_first_not_of(" #$@*._") == s.npos);
vector<TileType> ret(s.size());
std::transform(s.begin(), s.end(), ret.begin(), TxtMap);
return ret;
Expand Down Expand Up @@ -72,14 +73,13 @@ void Sokoban::LoadDefaultLevels() {
}

// operators
Sokoban::Pos operator+(Sokoban::Pos a, Sokoban::Pos b) { return {a.row+b.row, a.col+b.col}; }
Sokoban::Pos operator-(Sokoban::Pos a, Sokoban::Pos b) { return {a.row-b.row, a.col-b.col}; }
Sokoban::Pos operator-(Sokoban::Pos a) { return {-a.row, -a.col }; }
static inline Sokoban::Pos operator+ (Sokoban::Pos a, Sokoban::Pos b) { return {a.row+b.row, a.col+b.col}; }
static inline Sokoban::Pos operator- (Sokoban::Pos a, Sokoban::Pos b) { return {a.row-b.row, a.col-b.col}; }
static inline Sokoban::Pos operator- (Sokoban::Pos a) { return {-a.row, -a.col }; }

TileType& operator|=(TileType& lhs, const TileType& rhs) { return lhs = static_cast<TileType>(lhs | rhs); }
TileType& operator|=(TileType& lhs, int rhs) { return lhs = static_cast<TileType>(lhs | rhs); }
TileType& operator&=(TileType& lhs, const TileType& rhs) { return lhs = static_cast<TileType>(lhs & rhs); }
TileType& operator&=(TileType& lhs, int rhs) { return lhs = static_cast<TileType>(lhs & rhs); }
static inline TileType& operator|=(TileType& lhs, const TileType& rhs) { return lhs = static_cast<TileType>(lhs | rhs); }
static inline TileType& operator|=(TileType& lhs, int rhs) { return lhs = static_cast<TileType>(lhs | rhs); }
static inline TileType& operator&=(TileType& lhs, int rhs) { return lhs = static_cast<TileType>(lhs & rhs); }

// .--------> x
// |
Expand Down Expand Up @@ -111,20 +111,16 @@ void Sokoban::Push(int dy, int dx) {
Pos newPos = playerPos + dp;
if (!InBound(newPos))
return;
switch (state[newPos.row][newPos.col]) {
case TILE_BOX:
case TILE_BOX_ON_TARGET: {
if (state[newPos.row][newPos.col] & TILE_BOX) {
if (!IsSpace(newPos + dp))
return SetPlayerPos(playerPos, dy,dx);
history.push({newPos, dp});
MoveBox(newPos, dp);
} [[fallthrough]];
case TILE_SPACE:
case TILE_TARGET: {
}
if (IsSpace(newPos)) {
ClearPlayerPos();
SetPlayerPos(newPos, dy, dx);
} break;
default:
} else {
SetPlayerPos(playerPos, dy, dx);
}
}
Expand Down Expand Up @@ -187,7 +183,7 @@ bool Sokoban::Accessible(Pos s, Pos t) {
accessCache.insert(s);
queue<Pos> q;
q.push(s);
while(q.size()) {
while (q.size()) {
auto n = q.front();
q.pop();
std::array<Pos,4> dps = {Pos{-1,0},{1,0},{0,-1},{0,1}};
Expand All @@ -213,8 +209,6 @@ void Sokoban::ProcessEvent(const std::vector<GameEvent>& events,
case GameEvent::EVENT_MOVE_RESTART: { Restart(); } break;
case GameEvent::EVENT_MOVE_REGRET: { Regret(); } break;
case GameEvent::EVENT_MOVE_CLICK: { Click(pos); } break; // + row, col
case GameEvent::EVENT_NULL:
default: break;
}
}

9 changes: 8 additions & 1 deletion src/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
#include <cassert>
#endif

#if defined(__GNUC__) || defined(__clang__)
#define UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
#define UNREACHABLE() __assume(0)
#else
#define UNREACHABLE() throw std::runtime_error("Unreachable code reached at " __FILE__ ":" __LINE__);
#endif

// Types
enum TileType : uint8_t {
// [ 0 0 0 0 0 0 0 0 ]
Expand Down Expand Up @@ -88,7 +96,6 @@ class Sokoban {
void Pull(Pos LastPlayerPos, Pos dp);
const TileType& Get(Pos p) const {return state[p.row][p.col]; }
TileType& Get(Pos p) {return state[p.row][p.col]; }
int GetSubtype(Pos p) const {return state[p.row][p.col] & 3; }
void MoveBox(Pos p, Pos dp);
bool IsBlocked(Pos p) const {return InBound(p) && (Get(p) & TILE_BLOCKED); }
bool IsBox (Pos p) const {return InBound(p) && (Get(p) & TILE_BOX); }
Expand Down
5 changes: 3 additions & 2 deletions src/game_event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
// In this case, we can mock Gui::processInput easily.

enum class GameEvent {
EVENT_NULL,

// control
EVENT_MOVE_UP,
EVENT_MOVE_DOWN,
Expand All @@ -40,8 +38,11 @@ enum class GameEvent {
EVENT_MOVE_RESTART,
EVENT_MOVE_REGRET,
EVENT_MOVE_CLICK, // + row, col
};

enum class GuiEvent {
// menu
EVENT_NULL,
EVENT_MENU_PAUSE,
EVENT_MENU_RESUME,
EVENT_MENU_RESTART,
Expand Down
51 changes: 23 additions & 28 deletions src/game_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,24 @@ Sokoban::Pos PixelToPos(Vector2 pos) {
return {nrow, ncol};
}

pair<vector<GameEvent>, GameEvent> CookInputEvent(const Sokoban& game) {
pair<vector<GameEvent>, GuiEvent> CookInputEvent(const Sokoban& game) {
static int lastKeyPressed = KEY_NULL;
bool leftButton = IsMouseButtonPressed(MOUSE_LEFT_BUTTON) ||
IsMouseButtonDown(MOUSE_LEFT_BUTTON);
bool rightButton = IsMouseButtonReleased(MOUSE_RIGHT_BUTTON);
std::vector<GameEvent> gameEvents;
GameEvent guiEvent = GameEvent::EVENT_NULL;
GuiEvent guiEvent = GuiEvent::EVENT_NULL;

if (IsKeyPressed(KEY_ESCAPE)) {
guiEvent = GameEvent::EVENT_MENU_PAUSE;
guiEvent = GuiEvent::EVENT_MENU_PAUSE;
}

if (GetGameScene() != MAIN_GAME_SCENE) {
return {{}, guiEvent};
}

if (game.LevelCompleted()) {
return {{}, GameEvent::EVENT_MENU_LEVEL_FINISHED};
return {{}, GuiEvent::EVENT_MENU_LEVEL_FINISHED};
}

// TODO: add option for keyboard layout / AWERTY?
Expand Down Expand Up @@ -137,21 +137,21 @@ struct MyGuiButton {
bool disabled;
const char* text;
int shortcutKey;
GameEvent event;
GuiEvent event;
};

GameEvent Draw(raylib::Window& window, const Sokoban& game) {
GuiEvent Draw(raylib::Window& window, const Sokoban& game) {

// TODO: get rid of the magic numbers.
Rectangle rects[] = {{ 45, 115, 425, 60 }, { 45, 215, 425, 60 }, { 45, 315, 425, 60 }};
int numRects = 0;

MyGuiButton nextLevelButton { false, "Next Level (SPACE)" , KEY_SPACE, GameEvent::EVENT_MENU_NEXT_LEVEL };
MyGuiButton noMoreLevelsButton { true, "All Level Completed", KEY_NULL, GameEvent::EVENT_NULL };
MyGuiButton startButton { false, "Start (SPACE)" , KEY_SPACE, GameEvent::EVENT_MENU_START };
MyGuiButton resumeButton { false, "Resume (SPACE)" , KEY_SPACE, GameEvent::EVENT_MENU_RESUME };
MyGuiButton restartButton { false, "Restart (R)" , KEY_R, GameEvent::EVENT_MENU_RESTART };
MyGuiButton quitButton { false, "Quit (Q)" , KEY_Q, GameEvent::EVENT_MENU_EXIT };
MyGuiButton nextLevelButton { false, "Next Level (SPACE)" , KEY_SPACE, GuiEvent::EVENT_MENU_NEXT_LEVEL };
MyGuiButton noMoreLevelsButton { true, "All Level Completed", KEY_NULL, GuiEvent::EVENT_NULL };
MyGuiButton startButton { false, "Start (SPACE)" , KEY_SPACE, GuiEvent::EVENT_MENU_START };
MyGuiButton resumeButton { false, "Resume (SPACE)" , KEY_SPACE, GuiEvent::EVENT_MENU_RESUME };
MyGuiButton restartButton { false, "Restart (R)" , KEY_R, GuiEvent::EVENT_MENU_RESTART };
MyGuiButton quitButton { false, "Quit (Q)" , KEY_Q, GuiEvent::EVENT_MENU_EXIT };

auto CreateButton = [&rects, &numRects](const MyGuiButton& b)->bool{
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
Expand All @@ -165,7 +165,7 @@ GameEvent Draw(raylib::Window& window, const Sokoban& game) {
}
};

auto ret = GameEvent::EVENT_NULL;
auto ret = GuiEvent::EVENT_NULL;

int expectedWidth = 800;
int expectedHeight = 600;
Expand Down Expand Up @@ -197,34 +197,34 @@ GameEvent Draw(raylib::Window& window, const Sokoban& game) {
case MAIN_GAME_SCENE: {
DrawGameScene(game.GetState());
} break;
default: break;
default: UNREACHABLE(); break;
}
return ret;
}

// Return true if we should exit
bool ProcessGuiEvent(GameEvent e, Sokoban& game) {
bool ProcessGuiEvent(GuiEvent e, Sokoban& game) {
switch (e) {
case GameEvent::EVENT_MENU_START: {
case GuiEvent::EVENT_MENU_START: {
SetGameScene(MAIN_GAME_SCENE);
} break;
case GameEvent::EVENT_MENU_EXIT: {
case GuiEvent::EVENT_MENU_EXIT: {
return true;
} break;
case GameEvent::EVENT_MENU_RESTART: {
case GuiEvent::EVENT_MENU_RESTART: {
SetGameScene(MAIN_GAME_SCENE);
game.Restart();
} break;
case GameEvent::EVENT_MENU_PAUSE: {
case GuiEvent::EVENT_MENU_PAUSE: {
if (GetGameScene() == ESC_SCENE)
SetGameScene(MAIN_GAME_SCENE);
else if (GetGameScene() == MAIN_GAME_SCENE)
SetGameScene(ESC_SCENE);
} break;
case GameEvent::EVENT_MENU_RESUME: {
case GuiEvent::EVENT_MENU_RESUME: {
SetGameScene(MAIN_GAME_SCENE);
} break;
case GameEvent::EVENT_MENU_LEVEL_FINISHED: {
case GuiEvent::EVENT_MENU_LEVEL_FINISHED: {
// Ignore the event (which will be issued again) if
// any mouse button is down.
// This is because if we switch scene too early,
Expand All @@ -236,20 +236,15 @@ bool ProcessGuiEvent(GameEvent e, Sokoban& game) {
break;
SetGameScene(LEVEL_FINISHED_SCENE);
} break;
case GameEvent::EVENT_MENU_NEXT_LEVEL: {
case GuiEvent::EVENT_MENU_NEXT_LEVEL: {
SetGameScene(MAIN_GAME_SCENE);
#if defined(DEBUG)
assert(!game.IsLastLevel());
#endif
game.NextLevel();
} break;
case GameEvent::EVENT_NULL:
case GuiEvent::EVENT_NULL:
break;
default: {
#if defined(DEBUG)
assert(false);
#endif
}
}
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions src/game_gui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ void SetGameScene(GameScene newScene);
void Init(GameResources* resourcePtr);

// CookInputEvent just translates kbd/mouse event into GameEvent
std::pair<std::vector<GameEvent>, GameEvent> CookInputEvent(const Sokoban& game);
std::pair<std::vector<GameEvent>, GuiEvent> CookInputEvent(const Sokoban& game);

// GuiEvent here means raygui interaction, e.g., button clicked.
GameEvent Draw(raylib::Window& window, const Sokoban& game);
bool ProcessGuiEvent(GameEvent guiEvent, Sokoban& game);
GuiEvent Draw(raylib::Window& window, const Sokoban& game);
bool ProcessGuiEvent(GuiEvent guiEvent, Sokoban& game);
std::pair<int,int> GetWindowSize(const Sokoban::State& state);
Sokoban::Pos PixelToPos(Vector2 pos);

Expand Down
4 changes: 0 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
#include "raylib-cpp.hpp"
#include "raylib.h"
#include "raygui.h"
#include "rgestures.h"

#include "game.hpp"
#include "game_gui.hpp"
#include "game_config.hpp"

#include <CLI/CLI.hpp>
#include <chrono>
#include <thread>

using namespace GameGui;
using namespace std;
Expand Down

0 comments on commit e0443c5

Please sign in to comment.