diff --git a/default.puzzle b/default.puzzle index 54559cb..eeded14 100644 --- a/default.puzzle +++ b/default.puzzle @@ -1,5 +1,5 @@ // 1 Block, 1 Axis, no goal -R4599ab...................................... +R459912...................................... // 2 Blocks, 2 Axes, no goal R45991212.................................... diff --git a/include/puzzle.hpp b/include/puzzle.hpp index eb1ce38..d7902ef 100644 --- a/include/puzzle.hpp +++ b/include/puzzle.hpp @@ -226,6 +226,8 @@ public: auto IsWon() const -> bool; + auto SetGoal(int x, int y) -> bool; + auto AddColumn() const -> State; auto RemoveColumn() const -> State; @@ -240,6 +242,8 @@ public: auto GetBlockAt(int x, int y) const -> std::string; + auto GetTargetBlock() const -> Block; + auto GetIndex(int x, int y) const -> int; auto RemoveBlock(int x, int y) -> bool; diff --git a/src/input.cpp b/src/input.cpp index 7a7e45d..9335bcd 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -89,6 +89,15 @@ auto InputHandler::HandleMouse() -> void { block_add_y = -1; has_block_add_xy = false; } + } else if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) { + if (hov_x >= 0 && hov_x < state.current_state.width && hov_y >= 0 && + hov_y < state.current_state.height) { + if (state.current_state.SetGoal(hov_x, hov_y)) { + // We can't just call state.FindWinningStates() because the + // state is entirely different if it has a different win condition. + state.ClearGraph(); + } + } } } diff --git a/src/puzzle.cpp b/src/puzzle.cpp index 9f5d6e9..fec02ba 100644 --- a/src/puzzle.cpp +++ b/src/puzzle.cpp @@ -54,7 +54,7 @@ auto Block::Collides(const Block &other) const -> bool { auto State::Hash() const -> int { return std::hash{}(state); } auto State::HasWinCondition() const -> bool { - return target_x == 9 || target_y == 9; + return target_x != 9 && target_y != 9; } auto State::IsWon() const -> bool { @@ -71,6 +71,26 @@ auto State::IsWon() const -> bool { return false; } +auto State::SetGoal(int x, int y) -> bool { + if (x < 0 || x >= width || y < 0 || y >= height || + !GetTargetBlock().IsValid()) { + return false; + } + + if (target_x == x && target_y == y) { + target_x = 9; + target_y = 9; + } else { + target_x = x; + target_y = y; + } + + state.replace(3, 1, std::format("{}", target_x)); + state.replace(4, 1, std::format("{}", target_y)); + + return true; +} + auto State::AddColumn() const -> State { State newstate = State(width + 1, height, restricted); @@ -146,6 +166,16 @@ auto State::GetBlockAt(int x, int y) const -> std::string { return state.substr(GetIndex(x, y), 2); } +auto State::GetTargetBlock() const -> Block { + for (Block b : *this) { + if (b.target) { + return b; + } + } + + return Block::Invalid(); +} + auto State::GetIndex(int x, int y) const -> int { return prefix + (y * width + x) * 2; } diff --git a/src/renderer.cpp b/src/renderer.cpp index c95e560..1d0d260 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -132,13 +132,13 @@ auto Renderer::DrawMassSprings( const Vector3 &winning_mass = masses.at(winning_index); if (input.mark_solutions) { DrawCube(winning_mass, 2 * VERTEX_SIZE, 2 * VERTEX_SIZE, - 2 * VERTEX_SIZE, BLUE); + 2 * VERTEX_SIZE, TARGET_BLOCK_COLOR); } std::size_t current_index = state.CurrentMassIndex(); if (input.connect_solutions && masses.size() > current_index) { const Vector3 ¤t_mass = masses.at(current_index); - DrawLine3D(winning_mass, current_mass, PURPLE); + DrawLine3D(winning_mass, current_mass, ORANGE); } } } @@ -168,7 +168,7 @@ auto Renderer::DrawMassSprings( if (masses.size() > current_index) { const Vector3 ¤t_mass = masses.at(current_index); DrawCube(current_mass, VERTEX_SIZE * 2, VERTEX_SIZE * 2, VERTEX_SIZE * 2, - RED); + BLUE); } // DrawCubeWires(current_mass.position, REPULSION_RANGE, REPULSION_RANGE, @@ -267,6 +267,23 @@ auto Renderer::DrawKlotski() -> void { block_size / 10.0, Fade(BLACK, 0.5)); } + // Draw board goal position + const Block target = state.current_state.GetTargetBlock(); + if (target.IsValid() && state.current_state.HasWinCondition()) { + int target_x = state.current_state.target_x; + int target_y = state.current_state.target_y; + DrawRectangleLinesEx( + Rectangle(x_offset + BOARD_PADDING + target_x * BLOCK_PADDING * 2 + + BLOCK_PADDING + target_x * block_size, + y_offset + BOARD_PADDING + target_y * BLOCK_PADDING * 2 + + BLOCK_PADDING + target_y * block_size, + target.width * block_size + target.width * 2 * BLOCK_PADDING - + 2 * BLOCK_PADDING, + target.height * block_size + + target.height * 2 * BLOCK_PADDING - 2 * BLOCK_PADDING), + 2.0, TARGET_BLOCK_COLOR); + } + DrawLine(GetScreenWidth() / 2 - 1, 0, GetScreenWidth() / 2 - 1, GetScreenHeight() - MENU_HEIGHT, BLACK); EndTextureMode();