From 3e0809ebf65cecb0633d7a715a539ff54ff2770c Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Sun, 27 Sep 2020 08:26:39 +0200 Subject: [PATCH 01/10] add scanText(), printHtml() + code simplification --- BoardHasher.h | 141 ++- CMakeLists.txt | 20 +- MoveDiscovery.cpp | 38 +- MoveDiscovery.h | 59 +- MoveValidation.cpp | 73 +- MoveValidation.h | 46 +- README.md | 28 +- block.cpp | 111 +-- block.h | 80 +- in_hardPuzzle.txt | 10 + in_largePuzzle.txt | 10 + in_smallPuzzle.txt | 11 + main.cpp | 53 +- out_hardPuzzle.html | 185 ++++ out_hardPuzzle.txt | 2002 ++++++++++++++++++++++++++++++++++++++++++ out_smallPuzzle.html | 12 + printer.cpp | 224 +++++ printer.h | 65 +- puzzle.cpp | 74 +- puzzle.h | 156 ++-- solver.cpp | 181 +++- solver.h | 253 +----- test.cpp | 1008 ++++++++++++++------- test.h | 1 - 24 files changed, 3843 insertions(+), 998 deletions(-) create mode 100644 in_hardPuzzle.txt create mode 100644 in_largePuzzle.txt create mode 100644 in_smallPuzzle.txt create mode 100644 out_hardPuzzle.html create mode 100644 out_hardPuzzle.txt create mode 100644 out_smallPuzzle.html delete mode 100644 test.h diff --git a/BoardHasher.h b/BoardHasher.h index 3d1b39c..b904a34 100644 --- a/BoardHasher.h +++ b/BoardHasher.h @@ -1,10 +1,10 @@ #pragma once +#include "puzzle.h" #include #include #include - -#include "puzzle.h" +#include // std::find // Need a hash that's both order invariant & block-id invariant // i.e. 2 blocks with different ids at the same position should still hash the same @@ -13,95 +13,68 @@ // As we only update 1 block at a time, this would be perfect to update incrementally // But i'll add this to the TODO list :-) ... -struct BlockSizeType -{ - int width; - int height; - bool operator==(const BlockSizeType &other) - { - return width == other.width && height == other.height; - } -}; - -template -struct BoardHasher -{ - // TODO: provide implementation for other HashTypes - template - HashType hash(const BoardState &state) - { - HashType result{}; - result ^= runnerCode(state.m_runner); - for (const auto &block : state.m_blocks) - { - result ^= blockStateCode(block); - } - return result; - }; +template +class BoardHasher { +public: + HashType hash(const BoardState &boardState) { + HashType result{}; + result ^= runnerHash(boardState.runner); + for (const auto &block : boardState.blocks) { + result ^= blockSetHash(block); + } + return result; + }; - template - BoardHasher(const Puzzle &puzzle) - : m_width{ puzzle.m_dimensions.m_x } - , m_height{ puzzle.m_dimensions.m_y } - , m_codes{} - , m_blockTypes{} - { - // Should use unordered set here, but compiler complains - // std::unordered_set uniqueBlocks; - for (const auto &block : puzzle.m_initialState.m_blocks) - { - const BlockSizeType blockType{ block.m_sizeX, block.m_sizeY }; - if (end(m_blockTypes) == std::find(begin(m_blockTypes), end(m_blockTypes), blockType)) - { - m_blockTypes.push_back(blockType); - } - } + BoardHasher(const Puzzle& puzzle) + : dimensions{ puzzle.dimensions } + , numberOfPuzzlePos{ puzzle.dimensions.x * puzzle.dimensions.y } + , hashList{} + , blockPointSetSet{} + { + for (const auto block : puzzle.boardState.blocks) { + blockPointSetSet.insert(block.pointSet); + } - std::random_device device{}; - std::mt19937 generator{ device() }; - std::uniform_int_distribution distribution{}; + std::mt19937 generator{ (std::random_device{})() }; + std::uniform_int_distribution distribution{}; - const auto numberOfStates = (m_blockTypes.size() + 1) * puzzle.m_dimensions.m_x * puzzle.m_dimensions.m_y; - for (auto i = 0u; i < numberOfStates; ++i) - { - m_codes.push_back(distribution(generator)); - } - } + const auto numberOfBlockSetPos = (blockPointSetSet.size() + 1) * numberOfPuzzlePos; + for (auto blockSetPos = 0u; blockSetPos < numberOfBlockSetPos; ++blockSetPos) { + hashList.push_back(distribution(generator)); + } + } private: - int blockStateCode(const Block &block) - { - const auto blockType = std::distance(begin(m_blockTypes), std::find_if( - begin(m_blockTypes), - end(m_blockTypes), - [&](const auto &type) - { - return type.width == block.m_sizeX && type.height == block.m_sizeY; - })); + int blockSetHash(const Block& block) { + const auto blockPos = std::distance( + begin(blockPointSetSet), + std::find_if( + begin(blockPointSetSet), + end(blockPointSetSet), + [&](const auto& b) { + return b == block.pointSet; + } + ) + ); - // FIrst blockType is runner, so index offset of the other blocks is 1 - return m_codes[ - ((blockType + 1) * (m_width * m_height)) - + (block.m_startX * m_height) - + block.m_startY]; - } + // First hash is runner, so index offset of the other blocks is 1 + return hashList[((blockPos + 1) * numberOfPuzzlePos) + (block.shift.x * dimensions.y) + block.shift.y]; + } - int runnerCode(const Block &runner) - { - // First blockType is the runner - return m_codes[(runner.m_startX * m_height) + runner.m_startY]; - } + int runnerHash(const Block &runner) { + // First blockType is the runner : blockPos == 0 + return hashList[(runner.shift.x * dimensions.y) + runner.shift.y]; + } -private: - // Dimensions of the playing field - int m_width; - int m_height; + // Dimensions of the playing field + const Point dimensions; + const int numberOfPuzzlePos; - // unique code for each blocktype positioned on the board - // Note: indexing scheme = [blockType][x][y] - std::vector m_codes; + // unique hash for each blocktype positioned on the board + // Note: indexing scheme = [blockType][x][y] + std::vector hashList; + + // Unique hash for each block size + std::set> blockPointSetSet; +}; - // Unique code for each block size - std::vector m_blockTypes; - -}; \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9774e10..9d68fbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,21 @@ cmake_minimum_required (VERSION 2.8.11) project (KLOTSKI-SOLVER) -add_executable (run-tests test.cpp solver.cpp printer.cpp block.cpp MoveDiscovery.cpp MoveValidation.cpp puzzle.cpp) -add_executable (solve main.cpp solver.cpp block.cpp MoveDiscovery.cpp MoveValidation.cpp puzzle.cpp) \ No newline at end of file +add_executable (solve main.cpp MoveDiscovery.cpp MoveValidation.cpp block.cpp printer.cpp puzzle.cpp solver.cpp) +add_executable (unit-tests test.cpp MoveDiscovery.cpp MoveValidation.cpp block.cpp printer.cpp puzzle.cpp solver.cpp) + +target_compile_options(solve PRIVATE +# -std=c++11 + -pipe + +# -O0 + + -g + + -Wall + -Wextra + -Wpedantic + + -Wno-unused-function +) + diff --git a/MoveDiscovery.cpp b/MoveDiscovery.cpp index 050132c..a7f3da0 100644 --- a/MoveDiscovery.cpp +++ b/MoveDiscovery.cpp @@ -1,6 +1,36 @@ #include "MoveDiscovery.h" -namespace -{ - constexpr auto numberOfDirections = static_cast(Direction::Number_of_dirs); -} \ No newline at end of file +#include "block.h" + +#include + +std::vector MoveRunnerFirst::gatherMoves( + const Point dimensions, + const std::shared_ptr& boardState, + const std::set& invalidPositions +) const { + std::vector result{}; + + auto moveBlockIfPossible = [&](const Block &block) { + for (auto dir = 0; dir < static_cast(Direction::Number_of_dirs); ++dir) { + if (validBlockPosition( + block.move(static_cast(dir)), + dimensions, + *boardState, + invalidPositions + )) { + result.emplace_back(boardState, block, static_cast(dir)); + } + } + }; + + // Move runner first + moveBlockIfPossible(boardState->runner); + + // Move other blocks second + for (const auto &block : boardState->blocks) { + moveBlockIfPossible(block); + } + return result; +} + diff --git a/MoveDiscovery.h b/MoveDiscovery.h index a8d4898..36b0bb3 100644 --- a/MoveDiscovery.h +++ b/MoveDiscovery.h @@ -1,47 +1,26 @@ #pragma once -#include -#include - -#include "block.h" -#include "puzzle.h" #include "MoveValidation.h" +#include "puzzle.h" -template -struct MoveRunnerFirst -{ - template - static std::vector> gatherMoves( - const Point dimensions, - const std::shared_ptr> ¤tState, - const std::vector &invalidPositions, - Direction previousDirection = Direction::Number_of_dirs) - { - std::vector> newMoves{}; +#include +#include - auto moveBlockIfPossible = [&](const Block &block) - { - for (auto dir = 0; dir < static_cast(Direction::Number_of_dirs); ++dir) - { - if (dir != static_cast(previousDirection)) - { - const auto newBlock = move(block, static_cast(dir)); - if (Validation::validBlockPosition(newBlock, dimensions, *currentState, invalidPositions)) - { - newMoves.emplace_back(currentState, block, static_cast(dir)); - } - } - } - }; +class MoveDiscovery { +public: + virtual std::vector gatherMoves( + const Point dimensions, + const std::shared_ptr& boardState, + const std::set& invalidPositions + ) const = 0; +}; - // Move runner first - moveBlockIfPossible(currentState->m_runner); +class MoveRunnerFirst : public MoveDiscovery { +public: + virtual std::vector gatherMoves( + const Point dimensions, + const std::shared_ptr& boardState, + const std::set& invalidPositions + ) const; +}; - // Move other blocks second - for (const auto &block : currentState->m_blocks) - { - moveBlockIfPossible(block); - } - return newMoves; - } -}; \ No newline at end of file diff --git a/MoveValidation.cpp b/MoveValidation.cpp index 52158de..c8e6b5a 100644 --- a/MoveValidation.cpp +++ b/MoveValidation.cpp @@ -1,27 +1,62 @@ #include "MoveValidation.h" +#include #include -namespace detail -{ - bool overlapsWithInvalidSpaces(const Block &block, const std::vector &invalidSpots) - { - return std::any_of( - begin(invalidSpots), - end(invalidSpots), - [&](const auto &spot) - { - return overlaps(block, Block{ spot.m_x, spot.m_y, 1, 1, block.id}); - }); - } +namespace detail { - bool overlapsWithBorder(const Block &block, const Point &dims) - { - return block.m_startX < 0 || - block.m_startY < 0 || - (block.m_startX + block.m_sizeX) > dims.m_x || - (block.m_startY + block.m_sizeY) > dims.m_y; - } + bool overlapsWithInvalidSpaces(const Block& block, const std::set& invalidSpotSet) { + return std::any_of( + begin(invalidSpotSet), + end(invalidSpotSet), + [&](const Point& invalidSpot) { + return block.overlaps(invalidSpot); + } + ); + } + + bool overlapsWithBorder(const Block& block, const Point& dims) { + if ( + (block.shift.x < 0) + || + (block.shift.y < 0) + ) { + return true; + } + for (const auto& blockPoint : block.pointSet) { + if ( + ((block.shift.x + blockPoint.x) >= dims.x) + || + ((block.shift.y + blockPoint.y) >= dims.y) + ) { + return true; + } + } + return false; + } + + bool overlapsWithOtherBlocks(const Block& block, const BoardState& board) { + return + ((block.id != board.runner.id) && block.overlaps(board.runner)) + || + std::any_of( + begin(board.blocks), + end(board.blocks), + [&](const auto &other) { return (other.id != block.id) && block.overlaps(other); } + ) + ; + } } +bool validBlockPosition( + const Block &block, + const Point &dims, + const BoardState& boardState, + const std::set invalidPositions +) { + return !detail::overlapsWithBorder(block, dims) + && !detail::overlapsWithInvalidSpaces(block, invalidPositions) + && !detail::overlapsWithOtherBlocks(block, boardState) + ; +} diff --git a/MoveValidation.h b/MoveValidation.h index ab2c0ac..2cebe96 100644 --- a/MoveValidation.h +++ b/MoveValidation.h @@ -2,43 +2,11 @@ #include "puzzle.h" -namespace detail -{ - bool overlapsWithInvalidSpaces(const Block &block, const std::vector &invalidSpots); - - bool overlapsWithBorder(const Block &block, const Point &dims); - - template - bool overlapsWithOtherBlocks(const Block &block, const BoardState &board) - { - const auto overlapsRunner = same(block, board.m_runner) ? false : overlaps(block, board.m_runner); +// Checks if the proposed position of the block against the current state of the board is a valid one. +bool validBlockPosition( + const Block &block, + const Point &dims, + const BoardState& boardState, + const std::set invalidPositions +); - const auto overlapsOthers = std::any_of( - begin(board.m_blocks), - end(board.m_blocks), - [&](const auto &other) - { - return same(other, block) ? false : overlaps(block, other); - }); - - return overlapsRunner || overlapsOthers; - }; -} - -struct DefaultMoveValidation -{ - // Checks if the proposed position of the block against the current state of the board - // is a valid one. - // The position of the current block is ignored - template - static bool validBlockPosition( - const Block &block, - const Point &dims, - const BoardState &boardState, - const std::vector invalidPositions) - { - return !detail::overlapsWithBorder(block, dims) - && !detail::overlapsWithInvalidSpaces(block, invalidPositions) - && !detail::overlapsWithOtherBlocks(block, boardState); - } -}; \ No newline at end of file diff --git a/README.md b/README.md index 8128248..1dbcdeb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ No external libraries used. Not even for UTests. # Build instructions ## Linux -mkdir build && cd build && cmake .. && make -j +rm -frv /tmp/build +mkdir -pv /tmp/build && cmake -B /tmp/build -S . && make -j --directory=/tmp/build && /tmp/build/unit-tests && echo done ## Windows mkdir build && cd build && cmake .. @@ -12,16 +13,25 @@ Build with Visual studio 2017 # Run ## Tests -run `run-test.exe` in debug build +### Linux +/tmp/build/unit-tests + +### Windows +run `unit-tests.exe` in debug build ## Solve -run `solve.exe` -Puzzles are hardcoded in `main.cpp` +### Linux +/tmp/build/solve < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +/tmp/build/solve < "in_smallPuzzle.txt" 2> /dev/null +/tmp/build/solve < "in_largePuzzle.txt" +time /tmp/build/solve < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt + +### Windows +solve.exe < "in_smallPuzzle.txt" 1> out_smallPuzzle.html # Notes -Solvers can be created using: -`auto solver = makeSolver( Puzzle{ ... });` -See `puzzle.h` for how to construct Puzzles. +solve is using : +- standard input as puzzle to solve +- standard output as html solution +- error output as text solution and puzzle bug -Printing & debug information on the end-result can be obtained by solves' template parameter: -`solver.solve()` diff --git a/block.cpp b/block.cpp index 3e016cc..83b440e 100644 --- a/block.cpp +++ b/block.cpp @@ -1,64 +1,75 @@ #include "block.h" #include +#include -// Does not take block dimensions into account -// Intended as a rough filtering step to see which blocks to try to move first -bool nextToFreeSpace(const Block &block, const std::vector &freeSpaces) -{ - return std::any_of(begin(freeSpaces), end(freeSpaces), [&](const auto &freeSpace) - { - const auto nextToInX = overlaps(block, Block{ freeSpace.m_x - 1, freeSpace.m_y, 1, 1, block.id}) - || overlaps(block, Block{ freeSpace.m_x + 1, freeSpace.m_y, 1, 1, block.id}); - const auto nextToInY = overlaps(block, Block{ freeSpace.m_x, freeSpace.m_y - 1, 1, 1, block.id}) - || overlaps(block, Block{ freeSpace.m_x, freeSpace.m_y + 1, 1, 1, block.id}); +Block::Block() { } +Block::Block( + const Point& aShift, + const std::set& aPointSet, + const std::string& anId +) { + auto aPointSetIt = aPointSet.begin(); + const auto aPointSetItEnd = aPointSet.end(); + if (aPointSetIt == aPointSetItEnd) { + //empty point list + shift = aShift; - return nextToInX ^ nextToInY; - }); -} - -bool overlaps(const Block &left, const Block &right) -{ - const auto valueInRange = [](auto value, auto min, auto max) - { - return (value >= min) && (value <= max); - }; - const auto xOverlap = - valueInRange(left.m_startX, right.m_startX, right.m_startX + right.m_sizeX - 1) - || valueInRange(right.m_startX, left.m_startX, left.m_startX + left.m_sizeX - 1); + } else { + int xMin = aPointSetIt->x; + int yMin = aPointSetIt->y; + ++aPointSetIt; + for (; aPointSetIt != aPointSetItEnd; ++aPointSetIt) { + if (xMin > aPointSetIt->x) { xMin = aPointSetIt->x; } + if (yMin > aPointSetIt->y) { yMin = aPointSetIt->y; } + } + shift.x = aShift.x + xMin; + shift.y = aShift.y + yMin; - const auto yOverlap = - valueInRange(left.m_startY, right.m_startY, right.m_startY + right.m_sizeY - 1) - || valueInRange(right.m_startY, left.m_startY, left.m_startY + left.m_sizeY - 1); + for (auto& p : aPointSet) { + pointSet.insert({ p.x - xMin, p.y - yMin }); + } + } - return xOverlap && yOverlap; + id = anId; } -Block move(const Block &block, Direction dir) -{ - switch (dir) - { - case Up: - return Block{ block.m_startX, block.m_startY - 1, block.m_sizeX, block.m_sizeY, block.id }; - case Down: - return Block{ block.m_startX, block.m_startY + 1, block.m_sizeX, block.m_sizeY, block.id }; - case Left: - return Block{ block.m_startX - 1, block.m_startY, block.m_sizeX, block.m_sizeY, block.id }; - case Right: - return Block{ block.m_startX + 1, block.m_startY, block.m_sizeX, block.m_sizeY, block.id }; - } +bool Block::overlaps(const Point& otherPoint) const { + for (auto& thisPoint : this->pointSet) { + if ( + ((this->shift.x + thisPoint.x) == (otherPoint.x)) + && + ((this->shift.y + thisPoint.y) == (otherPoint.y)) + ) { + return true; + } + } + return false; +} - throw std::runtime_error("Unknown direction " + static_cast(dir)); - return block; +bool Block::overlaps(const Block& other) const { + for (auto& thisPoint : this->pointSet) { + for (auto& otherPoint : other.pointSet) { + if ( + ((this->shift.x + thisPoint.x) == (other.shift.x + otherPoint.x)) + && + ((this->shift.y + thisPoint.y) == (other.shift.y + otherPoint.y)) + ) { + return true; + } + } + } + return false; } -bool equalPosition(const Block &left, const Block &right) -{ - return left.m_startX == right.m_startX - && left.m_startY == right.m_startY; +Block Block::move(const Direction& dir) const { + switch (dir) { + case Up: return Block({ shift.x , shift.y - 1 }, pointSet, id); + case Down: return Block({ shift.x , shift.y + 1 }, pointSet, id); + case Left: return Block({ shift.x - 1, shift.y }, pointSet, id); + case Right: return Block({ shift.x + 1, shift.y }, pointSet, id); + default: + throw std::runtime_error("Unknown direction " + static_cast(dir)); + } } -bool same(const Block &left, const Block &right) -{ - return left.id == right.id; -} \ No newline at end of file diff --git a/block.h b/block.h index 790ed34..fe355e3 100644 --- a/block.h +++ b/block.h @@ -1,34 +1,64 @@ #pragma once #include -#include - -enum Direction -{ - Down, - Right, - Left, - Up, - Number_of_dirs +#include +#include + +template +std::string toString(T val) { + std::stringstream ss; + ss << val; + return ss.str(); +} + +enum Direction { + Down, + Right, + Left, + Up, + Number_of_dirs }; -const struct Block -{ - int m_startX; - int m_startY; - int m_sizeX; - int m_sizeY; - std::string id; +class Point { +public: + int x; + int y; }; -const struct Point -{ - int m_x; - int m_y; +inline bool operator<( const Point& p1, const Point& p2) { + if (p1.x == p2.x) { + return (p1.y < p2.y); + } + return (p1.x < p2.x); +} +inline bool operator==(const Point& p1, const Point& p2) { return (p1.x == p2.x) && (p1.y == p2.y); } +inline bool operator!=(const Point& p1, const Point& p2) { return !(p1 == p2); } + +class Block { +public: + Point shift; + std::set pointSet; + std::string id; + Block(); + Block( + const Point& aShift, + const std::set& aPointSet, + const std::string& anId + ); + + bool overlaps(const Block& other) const; + bool overlaps(const Point& otherPoint) const; + Block move(const Direction& dir) const; }; -bool nextToFreeSpace(const Block &block, const std::vector &freeSpaces); -bool overlaps(const Block &left, const Block &right); -Block move(const Block &block, Direction dir); -bool same(const Block &left, const Block &right); -bool equalPosition(const Block &left, const Block &right); \ No newline at end of file +inline bool operator==(const Block& b1, const Block& b2) { + return + (b1.shift == b2.shift) + && + (b1.id == b2.id) + && + (b1.pointSet == b2.pointSet) + ; +} +inline bool operator!=(const Block& b1, const Block& b2) { return !(b1 == b2); } + diff --git a/in_hardPuzzle.txt b/in_hardPuzzle.txt new file mode 100644 index 0000000..6a1a15a --- /dev/null +++ b/in_hardPuzzle.txt @@ -0,0 +1,10 @@ +6 5 +4 3 +######## +#@@ aab# +#@@ acd# +#kklmdd# +#eefgij# +#effhij# +######## + diff --git a/in_largePuzzle.txt b/in_largePuzzle.txt new file mode 100644 index 0000000..fd4e202 --- /dev/null +++ b/in_largePuzzle.txt @@ -0,0 +1,10 @@ +4 6 +1 4 +###### +#A@@F# +#A@@F# +#BCCG# +#BDEG# +#H I# +## ## +###### diff --git a/in_smallPuzzle.txt b/in_smallPuzzle.txt new file mode 100644 index 0000000..c91742b --- /dev/null +++ b/in_smallPuzzle.txt @@ -0,0 +1,11 @@ +5 6 +0 0 +####### +# # +# AA # +# A@@# +# AA@# +# @@# +## ## +####### + diff --git a/main.cpp b/main.cpp index ac097e2..8a83b0d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,45 +1,18 @@ +#include "printer.h" #include "solver.h" +#include "MoveDiscovery.h" -int main(int argc, char *argv[]) -{ - // Standard klotski puzzle - // print for sample ascii layout - const Puzzle<9> largePuzzle - { - { 4, 6 }, // dims - { 1, 4, 2, 2, "^" }, // goal - { // invalid spaces - { 0, 5 }, - { 3, 5 }, - }, - { // Initial board state - 0, // no moves made, - { 1, 0, 2, 2, "@" }, // runner - { // blocks - Block{ 0, 0, 1, 2, "A" }, - Block{ 0, 2, 1, 2, "B" }, - Block{ 1, 2, 2, 1, "C" }, - Block{ 1, 3, 1, 1, "D" }, - Block{ 2, 3, 1, 1, "E" }, - Block{ 3, 0, 1, 2, "F" }, - Block{ 3, 2, 1, 2, "G" }, - Block{ 0, 4, 1, 1, "H" }, - Block{ 3, 4, 1, 1, "I" } - } - } - }; +#include - auto solver = makeSolver(largePuzzle); +int main(int /*argc*/, char* /*argv*/[]) { + const auto result = Solver(scanText(std::cin), MoveRunnerFirst()).solve(); + if (result.size() == 0) { + std::cerr << "Could not find a solution." << std::endl; + return 1; + } - const auto result = solver.solve(); - if (result < 0) - { - std::cout << "Could not find a solution." << std::endl; - return 1; - } - else - { - std::cout << result << std::endl; - return 0; - } + printHtml(result, std::cout); + printText(result, std::cerr); + return 0; } + diff --git a/out_hardPuzzle.html b/out_hardPuzzle.html new file mode 100644 index 0000000..5bfeaa9 --- /dev/null +++ b/out_hardPuzzle.html @@ -0,0 +1,185 @@ + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 + 124 + 125 + 126 + 127 + 128 + 129 + 130 + 131 + 132 + 133 + 134 + 135 + 136 + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + \ No newline at end of file diff --git a/out_hardPuzzle.txt b/out_hardPuzzle.txt new file mode 100644 index 0000000..993ab2e --- /dev/null +++ b/out_hardPuzzle.txt @@ -0,0 +1,2002 @@ + +-------------- 0 +6 5 +4 3 +######## +#@@ aab# +#@@ acd# +#kklmdd# +#eefgij# +#effhij# +######## + +-------------- 1 +6 5 +4 3 +######## +#@@aa b# +#@@a cd# +#kklmdd# +#eefgij# +#effhij# +######## + +-------------- 2 +6 5 +4 3 +######## +#@@aab # +#@@a cd# +#kklmdd# +#eefgij# +#effhij# +######## + +-------------- 3 +6 5 +4 3 +######## +#@@aab # +#@@ac d# +#kklmdd# +#eefgij# +#effhij# +######## + +-------------- 4 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kklm # +#eefgij# +#effhij# +######## + +-------------- 5 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl m # +#eefgij# +#effhij# +######## + +-------------- 6 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl m# +#eefgij# +#effhij# +######## + +-------------- 7 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl im# +#eefgij# +#effh^j# +######## + +-------------- 8 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl im# +#eefgij# +#eff hj# +######## + +-------------- 9 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl im# +#eef ij# +#effghj# +######## + +-------------- 10 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkli m# +#eefi^j# +#effghj# +######## + +-------------- 11 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkli m# +#eefihj# +#effg^j# +######## + +-------------- 12 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkli m# +#eefihj# +#eff gj# +######## + +-------------- 13 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kkl m# +#eefihj# +#effigj# +######## + +-------------- 14 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#kk l m# +#eefihj# +#effigj# +######## + +-------------- 15 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +# kkl m# +#eefihj# +#effigj# +######## + +-------------- 16 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +# kk lm# +#eefihj# +#effigj# +######## + +-------------- 17 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +# kklm# +#eefihj# +#effigj# +######## + +-------------- 18 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekklm# +#e fihj# +# ffigj# +######## + +-------------- 19 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekklm# +#ef ihj# +#ff igj# +######## + +-------------- 20 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekklm# +#efi hj# +#ffi gj# +######## + +-------------- 21 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekklm# +#efi hj# +#ffig^j# +######## + +-------------- 22 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekklm# +#efi ^j# +#ffighj# +######## + +-------------- 23 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eekk m# +#efi lj# +#ffighj# +######## + +-------------- 24 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#ee kkm# +#efi lj# +#ffighj# +######## + +-------------- 25 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eeikkm# +#efi lj# +#ff ghj# +######## + +-------------- 26 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eeikkm# +#efi lj# +#ffg hj# +######## + +-------------- 27 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eeikkm# +#efi lj# +#ffgh^j# +######## + +-------------- 28 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eeikkm# +#efi ^j# +#ffghlj# +######## + +-------------- 29 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eei m# +#efikkj# +#ffghlj# +######## + +-------------- 30 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eei m # +#efikkj# +#ffghlj# +######## + +-------------- 31 +6 5 +4 3 +######## +#@@aabd# +#@@acdd# +#eeim # +#efikkj# +#ffghlj# +######## + +-------------- 32 +6 5 +4 3 +######## +#@@aab # +#@@ac d# +#eeimdd# +#efikkj# +#ffghlj# +######## + +-------------- 33 +6 5 +4 3 +######## +#@@aa b# +#@@ac d# +#eeimdd# +#efikkj# +#ffghlj# +######## + +-------------- 34 +6 5 +4 3 +######## +#@@aa b# +#@@a cd# +#eeimdd# +#efikkj# +#ffghlj# +######## + +-------------- 35 +6 5 +4 3 +######## +#@@aacb# +#@@a d# +#eeimdd# +#efikkj# +#ffghlj# +######## + +-------------- 36 +6 5 +4 3 +######## +#@@aacb# +#@@am d# +#eei dd# +#efikkj# +#ffghlj# +######## + +-------------- 37 +6 5 +4 3 +######## +#@@aacb# +#@@amd # +#eeidd # +#efikkj# +#ffghlj# +######## + +-------------- 38 +6 5 +4 3 +######## +#@@aacb# +#@@amd # +#eeiddj# +#efikkj# +#ffghl^# +######## + +-------------- 39 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efikk^# +#ffghl^# +######## + +-------------- 40 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efi kk# +#ffghl^# +######## + +-------------- 41 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efihkk# +#ffg l^# +######## + +-------------- 42 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efihkk# +#ffgl^^# +######## + +-------------- 43 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efih^^# +#ffglkk# +######## + +-------------- 44 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efi h^# +#ffglkk# +######## + +-------------- 45 +6 5 +4 3 +######## +#@@aacb# +#@@amdj# +#eeiddj# +#efi ^h# +#ffglkk# +######## + +-------------- 46 +6 5 +4 3 +######## +#@@aacb# +#@@am j# +#eei dj# +#efiddh# +#ffglkk# +######## + +-------------- 47 +6 5 +4 3 +######## +#@@aa b# +#@@amcj# +#eei dj# +#efiddh# +#ffglkk# +######## + +-------------- 48 +6 5 +4 3 +######## +#@@aa b# +#@@a cj# +#eeimdj# +#efiddh# +#ffglkk# +######## + +-------------- 49 +6 5 +4 3 +######## +#@@ aab# +#@@ acj# +#eeimdj# +#efiddh# +#ffglkk# +######## + +-------------- 50 +6 5 +4 3 +######## +#@@ aab# +#@@iacj# +#eeimdj# +#ef ddh# +#ffglkk# +######## + +-------------- 51 +6 5 +4 3 +######## +#@@ aab# +#@@iacj# +#eeimdj# +#efgddh# +#ff lkk# +######## + +-------------- 52 +6 5 +4 3 +######## +#@@iaab# +#@@iacj# +#ee mdj# +#efgddh# +#ff lkk# +######## + +-------------- 53 +6 5 +4 3 +######## +#@@iaab# +#@@iacj# +#ee mdj# +#efgddh# +#ffl kk# +######## + +-------------- 54 +6 5 +4 3 +######## +#@@iaab# +#@@iacj# +#ee mdj# +#efgddh# +#fflkk^# +######## + +-------------- 55 +6 5 +4 3 +######## +#@@iaab# +#@@iacj# +#ee mdj# +#efgdd^# +#fflkkh# +######## + +-------------- 56 +6 5 +4 3 +######## +#@@iaab# +#@@iac # +#ee mdj# +#efgddj# +#fflkkh# +######## + +-------------- 57 +6 5 +4 3 +######## +#@@iaab# +#@@ia c# +#ee mdj# +#efgddj# +#fflkkh# +######## + +-------------- 58 +6 5 +4 3 +######## +#@@iaab# +#@@ia c# +#eem dj# +#efgddj# +#fflkkh# +######## + +-------------- 59 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#efg ^j# +#fflkkh# +######## + +-------------- 60 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#efgkkj# +#ffl ^h# +######## + +-------------- 61 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#efgkkj# +#ff l^h# +######## + +-------------- 62 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#ef kkj# +#ffgl^h# +######## + +-------------- 63 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#ef kkj# +#ffg lh# +######## + +-------------- 64 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#eemddj# +#ef kkj# +#ff glh# +######## + +-------------- 65 +6 5 +4 3 +######## +#@@iaab# +#@@iadc# +#ee ddj# +#efmkkj# +#ff glh# +######## + +-------------- 66 +6 5 +4 3 +######## +#@@ aab# +#@@iadc# +#eeiddj# +#efmkkj# +#ff glh# +######## + +-------------- 67 +6 5 +4 3 +######## +#@@ aab# +#@@iadc# +#eeiddj# +#ef kkj# +#ffmglh# +######## + +-------------- 68 +6 5 +4 3 +######## +#@@ aab# +#@@ adc# +#eeiddj# +#efikkj# +#ffmglh# +######## + +-------------- 69 +6 5 +4 3 +######## +#@@aa b# +#@@a dc# +#eeiddj# +#efikkj# +#ffmglh# +######## + +-------------- 70 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eei j# +#efikkj# +#ffmglh# +######## + +-------------- 71 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeikkj# +#efi ^j# +#ffmglh# +######## + +-------------- 72 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeikkj# +#efig^j# +#ffm lh# +######## + +-------------- 73 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeikkj# +#efiglj# +#ffm ^h# +######## + +-------------- 74 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeikkj# +#efiglj# +#ffm h^# +######## + +-------------- 75 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeikk # +#efiglj# +#ffm hj# +######## + +-------------- 76 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eei kk# +#efiglj# +#ffm hj# +######## + +-------------- 77 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeigkk# +#efi lj# +#ffm hj# +######## + +-------------- 78 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeigkk# +#efi lj# +#ff mhj# +######## + +-------------- 79 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#ee gkk# +#efi lj# +#ffimhj# +######## + +-------------- 80 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeg kk# +#efi lj# +#ffimhj# +######## + +-------------- 81 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eeg kk# +#efimlj# +#ffi hj# +######## + +-------------- 82 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eegmkk# +#efi lj# +#ffi hj# +######## + +-------------- 83 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eegmkk# +#ef ilj# +#ff ihj# +######## + +-------------- 84 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#eegmkk# +#e filj# +# ffihj# +######## + +-------------- 85 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +# gmkk# +#eefilj# +#effihj# +######## + +-------------- 86 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +# g mkk# +#eefilj# +#effihj# +######## + +-------------- 87 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#g mkk# +#eefilj# +#effihj# +######## + +-------------- 88 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#g m kk# +#eefilj# +#effihj# +######## + +-------------- 89 +6 5 +4 3 +######## +#@@aadb# +#@@addc# +#g mkk # +#eefilj# +#effihj# +######## + +-------------- 90 +6 5 +4 3 +######## +#@@aadb# +#@@add # +#g mkkc# +#eefilj# +#effihj# +######## + +-------------- 91 +6 5 +4 3 +######## +#@@aad # +#@@addb# +#g mkkc# +#eefilj# +#effihj# +######## + +-------------- 92 +6 5 +4 3 +######## +#@@aad # +#@@addb# +#gm kkc# +#eefilj# +#effihj# +######## + +-------------- 93 +6 5 +4 3 +######## +#@@aad # +#@@addb# +#gmkk c# +#eefilj# +#effihj# +######## + +-------------- 94 +6 5 +4 3 +######## +#@@aad # +#@@addb# +#gmkkc # +#eefilj# +#effihj# +######## + +-------------- 95 +6 5 +4 3 +######## +#@@aad # +#@@add # +#gmkkcb# +#eefilj# +#effihj# +######## + +-------------- 96 +6 5 +4 3 +######## +#@@aa d# +#@@a dd# +#gmkkcb# +#eefilj# +#effihj# +######## + +-------------- 97 +6 5 +4 3 +######## +#@@ aad# +#@@ add# +#gmkkcb# +#eefilj# +#effihj# +######## + +-------------- 98 +6 5 +4 3 +######## +# @@aad# +# @@add# +#gmkkcb# +#eefilj# +#effihj# +######## + +-------------- 99 +6 5 +4 3 +######## +# @@aad# +#g@@add# +# mkkcb# +#eefilj# +#effihj# +######## + +-------------- 100 +6 5 +4 3 +######## +#g@@aad# +# @@add# +# mkkcb# +#eefilj# +#effihj# +######## + +-------------- 101 +6 5 +4 3 +######## +#g@@aad# +# @@add# +#m kkcb# +#eefilj# +#effihj# +######## + +-------------- 102 +6 5 +4 3 +######## +#g@@aad# +# @@add# +#mkk cb# +#eefilj# +#effihj# +######## + +-------------- 103 +6 5 +4 3 +######## +#g@@aad# +# @@add# +#mkkc b# +#eefilj# +#effihj# +######## + +-------------- 104 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +# kkc b# +#eefilj# +#effihj# +######## + +-------------- 105 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kk c b# +#eefilj# +#effihj# +######## + +-------------- 106 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc b# +#eefilj# +#effihj# +######## + +-------------- 107 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkci b# +#eefilj# +#eff hj# +######## + +-------------- 108 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkci b# +#eefilj# +#effh^j# +######## + +-------------- 109 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkci b# +#eefi^j# +#effhlj# +######## + +-------------- 110 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc ib# +#eef ij# +#effhlj# +######## + +-------------- 111 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc ib# +#eefhij# +#eff lj# +######## + +-------------- 112 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc ib# +#eefhij# +#effl^j# +######## + +-------------- 113 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc b# +#eefhij# +#efflij# +######## + +-------------- 114 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkc b # +#eefhij# +#efflij# +######## + +-------------- 115 +6 5 +4 3 +######## +#g@@aad# +#m@@add# +#kkcb # +#eefhij# +#efflij# +######## + +-------------- 116 +6 5 +4 3 +######## +#g@@aa # +#m@@a d# +#kkcbdd# +#eefhij# +#efflij# +######## + +-------------- 117 +6 5 +4 3 +######## +#g@@ aa# +#m@@ ad# +#kkcbdd# +#eefhij# +#efflij# +######## + +-------------- 118 +6 5 +4 3 +######## +#g @@aa# +#m @@ad# +#kkcbdd# +#eefhij# +#efflij# +######## + +-------------- 119 +6 5 +4 3 +######## +# g@@aa# +#m @@ad# +#kkcbdd# +#eefhij# +#efflij# +######## + +-------------- 120 +6 5 +4 3 +######## +#mg@@aa# +# @@ad# +#kkcbdd# +#eefhij# +#efflij# +######## + +-------------- 121 +6 5 +4 3 +######## +#mg@@aa# +#kk@@ad# +# cbdd# +#eefhij# +#efflij# +######## + +-------------- 122 +6 5 +4 3 +######## +#mg@@aa# +#kk@@ad# +# c bdd# +#eefhij# +#efflij# +######## + +-------------- 123 +6 5 +4 3 +######## +#mg@@aa# +#kk@@ad# +# cb dd# +#eefhij# +#efflij# +######## + +-------------- 124 +6 5 +4 3 +######## +#mg@@aa# +#kk@@ad# +#c b dd# +#eefhij# +#efflij# +######## + +-------------- 125 +6 5 +4 3 +######## +#mg@@aa# +#kk@@ad# +#cb dd# +#eefhij# +#efflij# +######## + +-------------- 126 +6 5 +4 3 +######## +#mg aa# +#kk@@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 127 +6 5 +4 3 +######## +#m g aa# +#kk@@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 128 +6 5 +4 3 +######## +#m gaa# +#kk@@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 129 +6 5 +4 3 +######## +# m gaa# +#kk@@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 130 +6 5 +4 3 +######## +# mgaa# +#kk@@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 131 +6 5 +4 3 +######## +#kkmgaa# +# @@ad# +#cb@@dd# +#eefhij# +#efflij# +######## + +-------------- 132 +6 5 +4 3 +######## +#kkmgaa# +# b@@ad# +#c @@dd# +#eefhij# +#efflij# +######## + +-------------- 133 +6 5 +4 3 +######## +#kkmgaa# +#cb@@ad# +# @@dd# +#eefhij# +#efflij# +######## + +-------------- 134 +6 5 +4 3 +######## +#kkmgaa# +#cb@@ad# +#ee@@dd# +#e fhij# +# fflij# +######## + +-------------- 135 +6 5 +4 3 +######## +#kkmgaa# +#cb@@ad# +#ee@@dd# +#ef hij# +#ff lij# +######## + +-------------- 136 +6 5 +4 3 +######## +#kkmgaa# +#cb@@ad# +#ee@@dd# +#efh ij# +#ff lij# +######## + +-------------- 137 +6 5 +4 3 +######## +#kkmgaa# +#cb@@ad# +#ee@@dd# +#ef ij# +#ffhlij# +######## + +-------------- 138 +6 5 +4 3 +######## +#kkmgaa# +#cb ad# +#ee@@dd# +#ef@@ij# +#ffhlij# +######## + +-------------- 139 +6 5 +4 3 +######## +#kkm aa# +#cb gad# +#ee@@dd# +#ef@@ij# +#ffhlij# +######## + +-------------- 140 +6 5 +4 3 +######## +#kkm aa# +#cbg ad# +#ee@@dd# +#ef@@ij# +#ffhlij# +######## + +-------------- 141 +6 5 +4 3 +######## +#kkmaa # +#cbga d# +#ee@@dd# +#ef@@ij# +#ffhlij# +######## + +-------------- 142 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ # +#ef@@ij# +#ffhlij# +######## + +-------------- 143 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@i # +#ef@@ij# +#ffhl^j# +######## + +-------------- 144 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ij# +#ef@@ij# +#ffhl^^# +######## + +-------------- 145 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ij# +#ef@@ij# +#ffh l^# +######## + +-------------- 146 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ij# +#ef@@ij# +#ff hl^# +######## + +-------------- 147 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ij# +#ef@@ij# +#ff h^l# +######## + +-------------- 148 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee@@ij# +#ef@@ij# +#ff hl# +######## + +-------------- 149 +6 5 +4 3 +######## +#kkmaad# +#cbgadd# +#ee ij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 150 +6 5 +4 3 +######## +#kkmaad# +#cb add# +#eeg ij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 151 +6 5 +4 3 +######## +#kkmaad# +#c badd# +#eeg ij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 152 +6 5 +4 3 +######## +#kkmaad# +# cbadd# +#eeg ij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 153 +6 5 +4 3 +######## +#kkmaad# +# cbadd# +#ee gij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 154 +6 5 +4 3 +######## +#kkmaad# +# c add# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 155 +6 5 +4 3 +######## +#kkmaad# +# cadd# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 156 +6 5 +4 3 +######## +# maad# +#kkcadd# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 157 +6 5 +4 3 +######## +# m aad# +#kkcadd# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 158 +6 5 +4 3 +######## +# mcaad# +#kk add# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 159 +6 5 +4 3 +######## +#m caad# +#kk add# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 160 +6 5 +4 3 +######## +#mc aad# +#kk add# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 161 +6 5 +4 3 +######## +#mcaa d# +#kka dd# +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 162 +6 5 +4 3 +######## +#mcaad # +#kkadd # +#eebgij# +#ef@@ij# +#ff@@hl# +######## + +-------------- 163 +6 5 +4 3 +######## +#mcaad # +#kkaddj# +#eebgij# +#ef@@i^# +#ff@@hl# +######## + +-------------- 164 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebgi # +#ef@@i^# +#ff@@hl# +######## + +-------------- 165 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebg i# +#ef@@^i# +#ff@@hl# +######## + +-------------- 166 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebg i# +#ef@@hi# +#ff@@^l# +######## + +-------------- 167 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebghi# +#ef@@^i# +#ff@@^l# +######## + +-------------- 168 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebghi# +#ef @@i# +#ff @@l# +######## + +-------------- 169 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +#eebghi# +#e f@@i# +# ff@@l# +######## + +-------------- 170 +6 5 +4 3 +######## +#mcaadj# +#kkaddj# +# bghi# +#eef@@i# +#eff@@l# +######## + +-------------- 171 +6 5 +4 3 +######## +#mcaadj# +# addj# +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 172 +6 5 +4 3 +######## +#m aadj# +# caddj# +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 173 +6 5 +4 3 +######## +#m aadj# +#c addj# +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 174 +6 5 +4 3 +######## +#maa dj# +#ca ddj# +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 175 +6 5 +4 3 +######## +#maad j# +#cadd j# +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 176 +6 5 +4 3 +######## +#maadj # +#caddj # +#kkbghi# +#eef@@i# +#eff@@l# +######## + +-------------- 177 +6 5 +4 3 +######## +#maadj # +#caddji# +#kkbghi# +#eef@@^# +#eff@@l# +######## + +-------------- 178 +6 5 +4 3 +######## +#maadji# +#caddji# +#kkbgh # +#eef@@^# +#eff@@l# +######## + +-------------- 179 +6 5 +4 3 +######## +#maadji# +#caddji# +#kkbgh # +#eef@@l# +#eff@@^# +######## + +-------------- 180 +6 5 +4 3 +######## +#maadji# +#caddji# +#kkbghl# +#eef@@^# +#eff@@^# +######## + +-------------- 181 +6 5 +4 3 +######## +#maadji# +#caddji# +#kkbghl# +#eef @@# +#eff @@# +######## diff --git a/out_smallPuzzle.html b/out_smallPuzzle.html new file mode 100644 index 0000000..e58fb42 --- /dev/null +++ b/out_smallPuzzle.html @@ -0,0 +1,12 @@ + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + \ No newline at end of file diff --git a/printer.cpp b/printer.cpp index 578f10f..f685e11 100644 --- a/printer.cpp +++ b/printer.cpp @@ -1 +1,225 @@ #include "printer.h" + +#include +#include +#include +#include + +std::map colorMap{ + { 0, "pink" }, + { 1, "aqua" }, + { 2, "blueviolet" }, + { 3, "darkblue" }, + { 4, "darkcyan" }, + { 5, "darkgoldenrod" }, + { 6, "darkred" }, + { 7, "darkmagenta" }, + { 8, "darkorchid" }, + { 9, "darkslategray" }, + {10, "firebrick" }, + {11, "green" }, + {12, "indigo" }, + {13, "seagreen" }, + {14, "teal" }, + {15, "yellowgreen" }, + {16, "yellow" }, +}; + +void printSvgStyle(const Puzzle& puzzle, std::ostream& out) { + out << " .dimensions { stroke : red; stroke-width : 0.1; }"; + out << " .blockRunner { fill : red; }"; + out << " .blockWall { fill : black; }"; + out << " .blockGoal { fill : powderblue; }"; + + int iColor = -1; + for (const Block& block : puzzle.boardState.blocks) { + out << " .block" << block.id << " { fill : " << colorMap[++iColor] << "; }"; + } + + out << " .puzzle { fill : #202020; }"; +} + +void printSvg(const Point& point, std::ostream& out) { + out << ""; +} + +void printSvg(const Block& block, std::ostream& out) { + out << ""; + for (const Point& point : block.pointSet) { + printSvg(point, out); + } + out << ""; +} + +void printSvg(const BoardState& boardState, std::ostream& out) { + printSvg({ boardState.runner.shift, boardState.runner.pointSet, "Runner" }, out); + for (const Block& block : boardState.blocks) { + printSvg(block, out); + } +} + +void printSvg(const Puzzle& puzzle, std::ostream& out) { + out + << "" + << "" + ; + + Block forbiddenSpots; + forbiddenSpots.shift = {0, 0}; + forbiddenSpots.pointSet = puzzle.forbiddenSpots; + forbiddenSpots.id = "Wall"; + printSvg(forbiddenSpots, out); + printSvg(Block(puzzle.goal, puzzle.boardState.runner.pointSet, "Goal"), out); + printSvg(puzzle.boardState, out); + out << ""; +} + +void printSvg(const std::list& puzzleList, std::string preffix, std::string suffix, std::ostream& out) { + size_t i = 0; + for (const Puzzle& puzzleStep : puzzleList) { + const std::string pos(toString(++i)); + out << std::regex_replace(preffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); + printSvg(puzzleStep, out); + out << std::regex_replace(suffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); + } +} + +void printHtml(const std::list& puzzleList, std::ostream& out) { + const Puzzle& firstPuzzle = *(puzzleList.begin()); + out << "\n\n"; + printSvg( + puzzleList, + " {pos}", + "\n", + out + ); + out << ""; +} + +void printText(const Puzzle& puzzle, std::ostream& out) { + + //init layout + std::vector> layout( + puzzle.dimensions.x + 2, + std::vector(puzzle.dimensions.y + 2) + ); + for (auto x = 1; x < puzzle.dimensions.x + 1; ++x) { + for (auto y = 1; y < puzzle.dimensions.y + 1; ++y) { + layout[x][y] = ' '; + } + } + + // Print border blocks + for (auto x = 0; x < puzzle.dimensions.x + 2; ++x) { + layout[x][0] = '#'; + layout[x][puzzle.dimensions.y + 1] = '#'; + } + for (auto y = 1; y < puzzle.dimensions.y + 1; ++y) { + layout[0][y] = '#'; + layout[puzzle.dimensions.x + 1][y] = '#'; + } + + // print content + for (const auto &forbiddenPoint : puzzle.forbiddenSpots) { + layout[forbiddenPoint.x + 1][forbiddenPoint.y + 1] = '#'; + } + + auto fillBlock = [&](const Block& block) { + for (const auto& blockPoint : block.pointSet) { + layout[block.shift.x + blockPoint.x + 1][block.shift.y + blockPoint.y + 1] = block.id[0]; + } + }; + + fillBlock({ puzzle.goal, puzzle.boardState.runner.pointSet, "^" }); + + //fill runner block + fillBlock(puzzle.boardState.runner); + + //fill other blocks + for (const auto &contentBlock : puzzle.boardState.blocks) { + fillBlock(contentBlock); + } + + //prepare output + out << puzzle.dimensions.x << " " << puzzle.dimensions.y << "\n"; + out << puzzle.goal.x << " " << puzzle.goal.y << "\n"; + for (auto y = 0; y < puzzle.dimensions.y + 2; ++y) { + for (auto x = 0; x < puzzle.dimensions.x + 2; ++x) { + out << layout[x][y]; + } + out << "\n"; + } +} + +void printText(const std::list& puzzleList, std::ostream& out) { + int pos = -1; + for (const Puzzle& puzzleStep : puzzleList) { + out << std::endl << "-------------- " << ++pos << "\n"; + printText(puzzleStep, out); + } +} + +Puzzle scanText(std::istream& in) { + Point dimension; + Point goal; + in >> dimension.x >> dimension.y >> goal.x >> goal.y; + //std::cout << dimension.x << "\n" << dimension.y << "\n" << goal.x << "\n" << goal.y << "\n"; + std::string line; + std::getline(in, line); + std::getline(in, line); + + std::map> objMap; + for (auto y = 0; y < dimension.y; ++y) { + std::getline(in, line); + //std::cout << line << "\n"; + for (auto x = 0; x < dimension.x; ++x) { + objMap[line[x + 1]].insert({ x, y }); + } + } + + std::set runnerPointSet; + std::string runnerId; + std::set forbiddenSpots = {}; + std::vector blockList; + for (auto objPair : objMap) { + if ((' ' == objPair.first)) { + //forget blanc place + + } else if ('^' == objPair.first) { + //orget goal + + } else if ('@' == objPair.first) { + runnerPointSet = objPair.second; + runnerId = toString(objPair.first); + + } else if (line[0] == objPair.first) { + forbiddenSpots = objPair.second; + + } else { + blockList.push_back({ + {0, 0}, + objPair.second, + toString(objPair.first) + }); + + } + } + + return { + dimension, + goal, + forbiddenSpots, + { + 0, + Block({0, 0}, runnerPointSet, runnerId), + blockList + } + }; +} + diff --git a/printer.h b/printer.h index 10a7be7..66abc4a 100644 --- a/printer.h +++ b/printer.h @@ -1,60 +1,19 @@ #pragma once -#include "solver.h" -#include -#include +#include "puzzle.h" +#include -template -void print(const Puzzle &puzzle) -{ - std::vector> layout( - puzzle.m_dimensions.m_y + 2, - std::vector(puzzle.m_dimensions.m_x + 2)); +void printSvgStyle(const Puzzle& puzzle, std::ostream& out); +void printSvg(const Point& point, std::ostream& out); +void printSvg(const Block& block, std::ostream& out); +void printSvg(const BoardState& boardState, std::ostream& out); +void printSvg(const Puzzle& puzzle, std::ostream& out); +void printSvg(const std::list& puzzleList, std::string preffix, std::string suffix, std::ostream& out); - auto fillBlock = [&](const auto &block) - { - for (auto x = block.m_startX; x < block.m_startX + block.m_sizeX; ++x) - { - for (auto y = block.m_startY; y < block.m_startY + block.m_sizeY; ++y) - { - layout[y + 1][x + 1] = block.id[0]; - } - } - }; +void printHtml(const std::list& puzzleList, std::ostream& out); - // Print border blocks - for (auto y = 0; y < puzzle.m_dimensions.m_y + 2; ++y) - { - layout[y][0] = '#'; - layout[y][puzzle.m_dimensions.m_x + 1] = '#'; - } - for (auto x = 1; x < puzzle.m_dimensions.m_x + 1; ++x) - { - layout[0][x] = '#'; - layout[puzzle.m_dimensions.m_y + 1][x] = '#'; - } - for (const auto &forbiddenPoint : puzzle.m_forbiddenSpots) - { - layout[forbiddenPoint.m_y + 1][forbiddenPoint.m_x + 1] = '#'; - } +void printText(const Puzzle& puzzle, std::ostream& out); +void printText(const std::list& puzzleList, std::ostream& out); - fillBlock(puzzle.m_goal); - fillBlock(puzzle.m_initialState.m_runner); +Puzzle scanText(std::istream& in); - // Print other blocks - for (const auto &contentBlock : puzzle.m_initialState.m_blocks) - { - fillBlock(contentBlock); - } - - for (auto y = 0u; y < layout.size(); ++y) - { - for (auto x = 0u; x < layout[0].size(); ++x) - { - std::cout << layout[y][x]; - } - std::cout << std::endl; - } - - std::cout << std::endl; -}; diff --git a/puzzle.cpp b/puzzle.cpp index cd00ec8..eab5dc9 100644 --- a/puzzle.cpp +++ b/puzzle.cpp @@ -1 +1,73 @@ -#include "puzzle.h" \ No newline at end of file +#include "puzzle.h" + +BoardState Move::proceed() { + if (block.id == boardState->runner.id) { + // Block to move is the runner + return BoardState { + boardState->numberOfMoves + 1, + boardState->runner.move(directionToMove), + boardState->blocks, + }; + + } else { + // Block to move is one of the other blocks + // Notes: assumes linear distance in storage container + const auto blockIndex = &block - &boardState->blocks[0]; + + auto newBlocks = boardState->blocks; + newBlocks[blockIndex] = block.move(directionToMove); + + return BoardState { + boardState->numberOfMoves + 1, + boardState->runner, + std::move(newBlocks), + }; + + } +} + +Move::Move(std::shared_ptr boardState, const Block &block, Direction dir) + : boardState{ boardState } + , block{ block } + , directionToMove{ dir } +{ +} + +PuzzleValidation Puzzle::validate() const { + const auto& blockSize = boardState.blocks.size(); + + for (size_t i = 0; i < blockSize; ++i) { + for (size_t j = 0; j < blockSize; ++j) { + if (i < j) { + if (boardState.blocks[i].overlaps(boardState.blocks[j])) { + return blocksOverlaps; + } + if (boardState.blocks[i].id == boardState.blocks[j].id) { + return blocksWithSameId; + } + } + } + + if (boardState.blocks[i].overlaps(this->boardState.runner)) { + return runnerOverlaps; + } + if (boardState.runner.id == boardState.blocks[i].id) { + return runnerWithSameId; + } + } + + return PuzzleValidation::valid; +} + +std::string Puzzle::validationString(const PuzzleValidation& validation) { + switch (validation) { + case valid: return "puzzle is valid"; + case blocksOverlaps: return "tow blocks overlaps"; + case runnerOverlaps: return "runner and block overlaps"; + case blocksWithSameId: return "tow blocks has the same id"; + case runnerWithSameId: return "runner and block has the same id"; + default: + throw std::runtime_error("Unknown validation " + static_cast(validation)); + } +} + diff --git a/puzzle.h b/puzzle.h index 0dfb271..202a014 100644 --- a/puzzle.h +++ b/puzzle.h @@ -1,121 +1,79 @@ #pragma once -#include -#include -#include - - #include "block.h" -template -struct BoardState -{ - constexpr static int blockCount = BlockCount; +#include +#include +#include +#include - // Numer of moves made since the start position - const int m_numberOfMovesFromStart; +struct BoardState { + // Numer of moves made since the start position + const int numberOfMoves; - // Puzzle piece to be moved to the goal - const Block m_runner; + // Puzzle piece to be moved to the goal + const Block runner; - // all movable bystander blocks on the board - const std::array m_blocks; + // all movable bystander blocks on the board + const std::vector blocks; }; -template -struct Move -{ - // State from which to move - std::shared_ptr> m_state; +class Move { +public: + // State from which to move + std::shared_ptr boardState; + + // Block to be moved + const Block █ - // Block to be moved - const Block &m_block; + // Direction in which to move block + Direction directionToMove; - // Direction in which to move block - Direction m_directionToMove; + // Returns the BoardState after the move + BoardState proceed(); - // Returns the BoardState after the move - BoardState operator()(); + Move(std::shared_ptr boardState, const Block &block, Direction dir); +}; - Move(std::shared_ptr> state, const Block &block, Direction dir) - : m_state{ state } - , m_block{ block } - , m_directionToMove{ dir } - { - } +enum PuzzleValidation { + valid, + blocksOverlaps, + runnerOverlaps, + blocksWithSameId, + runnerWithSameId, + Number_of_validation }; -template -struct Puzzle -{ - // Dimensions of the puzzle: - // X: [ 0, width - 1] - // Y: [ 0, height - 1] - const Point m_dimensions; +class Puzzle { +public: + // Dimensions of the puzzle: + const Point dimensions; - // Position of the runner required in order to finish the puzzle - const Block m_goal; + // Position of the runner required in order to finish the puzzle + const Point goal; - // Positions (in addition to regular border) where blocks cannot be placed - const std::vector m_forbiddenSpots; + // Positions (in addition to regular border) where blocks cannot be placed + const std::set forbiddenSpots; - // Initial position of all blocks on the board - const BoardState m_initialState; + // Initial position of all blocks on the board + const BoardState boardState; + + PuzzleValidation validate() const; + static std::string validationString(const PuzzleValidation& validation); }; -template -bool valid(const Puzzle &puzzle) -{ - const auto blockCount = puzzle.m_initialState.m_blocks.size(); - const auto &blocks = puzzle.m_initialState.m_blocks; - bool valid = true; - - for (auto i = 0u; i < blockCount; ++i) - { - for (auto j = 0u; j < blockCount; ++j) - { - if (i != j) - { - valid = valid && !overlaps(blocks[i], blocks[j]); - valid = valid && (blocks[i].id != blocks[j].id); - } - } - - valid = valid && !overlaps(blocks[i], puzzle.m_initialState.m_runner); - valid = valid && (puzzle.m_goal.id != blocks[i].id); - valid = valid && (puzzle.m_initialState.m_runner.id != blocks[i].id); - } - - return valid; +inline bool operator==(const Puzzle p1, const Puzzle p2) { + return + (p1.dimensions == p2.dimensions) + && + (p1.forbiddenSpots == p2.forbiddenSpots) + && + (p1.goal == p2.goal) + && + (p1.boardState.runner == p2.boardState.runner) + && + (p1.boardState.blocks == p2.boardState.blocks) + ; } +inline bool operator!=(const Puzzle p1, const Puzzle p2) { return !(p1 == p2); } -template -BoardState Move::operator()() -{ - if (same(m_block, m_state->m_runner)) - { - // Block to move is the runner - return BoardState - { - m_state->m_numberOfMovesFromStart + 1, - move(m_state->m_runner, m_directionToMove), - m_state->m_blocks, - }; - } - else - { - // Block to move is one of the other blocks - // Notes: assumes linear distance in storage container - const auto blockIndex = &m_block - &m_state->m_blocks[0]; - - auto newBlocks = m_state->m_blocks; - newBlocks[blockIndex] = move(m_block, m_directionToMove); - - return BoardState - { - m_state->m_numberOfMovesFromStart + 1, - m_state->m_runner, - std::move(newBlocks), - }; - } -} diff --git a/solver.cpp b/solver.cpp index 422f40c..6ad5e43 100644 --- a/solver.cpp +++ b/solver.cpp @@ -1,3 +1,182 @@ #include "solver.h" -#include \ No newline at end of file +#include "printer.h" +#include + +bool isSolution(const BoardState& boardState, const Point& goal) { + return (boardState.runner.shift.x == goal.x) && (boardState.runner.shift.y == goal.y); +} + +Solver::Solver(const Puzzle &puzzle, const MoveDiscovery& moveDiscovery) + : puzzle{ puzzle } + , hasher{ puzzle } + , moveDiscovery{ moveDiscovery } +{ + const auto initialMoves = moveDiscovery.gatherMoves( + puzzle.dimensions, + std::make_shared(puzzle.boardState), + puzzle.forbiddenSpots + ); + for (auto &move : initialMoves) { + possibleMoveStack.push_back(std::move(move)); + } +} + +std::list Solver::solve(std::ostream* debugOut) { + return (nullptr == debugOut) ? solveFast() : solveDebug(debugOut); +} + +std::list Solver::solveDebug(std::ostream* debugOut) { + printText(puzzle, *debugOut); + + auto globalTime = std::chrono::high_resolution_clock::now(); + auto pickMoveTime = std::chrono::high_resolution_clock::duration{}; + auto solutionCheckTime = std::chrono::high_resolution_clock::duration{}; + auto hashTime = std::chrono::high_resolution_clock::duration{}; + auto lookupTime = std::chrono::high_resolution_clock::duration{}; + auto gatherMovesTime = std::chrono::high_resolution_clock::duration{}; + auto insertMovesTime = std::chrono::high_resolution_clock::duration{}; + + while (!possibleMoveStack.empty()) { + auto start_time = std::chrono::high_resolution_clock::now(); + + Move firstMove = *(begin(possibleMoveStack)); + // Note: invalidates firstMoveIt + possibleMoveStack.pop_front(); + + auto boardStateAfterMove = firstMove.proceed(); + + auto end_time = std::chrono::high_resolution_clock::now(); + pickMoveTime += (end_time - start_time); + start_time = std::chrono::high_resolution_clock::now(); + + if (isSolution(boardStateAfterMove, puzzle.goal)) { + *debugOut << "Solution is:" << std::endl; + printText(Puzzle{ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, boardStateAfterMove }, *debugOut); + *debugOut << "distance: " << boardStateAfterMove.numberOfMoves << std::endl; + const auto hash = hasher.hash(boardStateAfterMove); + *debugOut << "Final hash: " << hash << std::endl; + + auto result = solution(*firstMove.boardState, boardStateAfterMove); + + *debugOut << hasher.hash(puzzle.boardState) << std::endl; + printText(puzzle, *debugOut); + *debugOut << std::endl << "-------------- " << std::endl; + + const auto now = std::chrono::high_resolution_clock::now(); + const auto totalTime = std::chrono::duration_cast(now - globalTime).count(); + *debugOut << "Total time was: " << totalTime << std::endl; + if (0 < totalTime) { + *debugOut + << "pickMoveTime: " << (100 * std::chrono::duration_cast(pickMoveTime).count() / totalTime) << "%" << std::endl + << "solutionCheckTime: " << (100 * std::chrono::duration_cast(solutionCheckTime).count() / totalTime) << "%" << std::endl + << "hashTime: " << (100 * std::chrono::duration_cast(hashTime).count() / totalTime) << "%" << std::endl + << "lookupTime: " << (100 * std::chrono::duration_cast(lookupTime).count() / totalTime) << "%" << std::endl + << "gatherMovesTime: " << (100 * std::chrono::duration_cast(gatherMovesTime).count() / totalTime) << "%" << std::endl + << "insertMovesTime: " << (100 * std::chrono::duration_cast(insertMovesTime).count() / totalTime) << "%" << std::endl + ; + } + return result; + } + + end_time = std::chrono::high_resolution_clock::now(); + solutionCheckTime += (end_time - start_time); + start_time = std::chrono::high_resolution_clock::now(); + + const auto hash = hasher.hash(boardStateAfterMove); + + end_time = std::chrono::high_resolution_clock::now(); + hashTime += (end_time - start_time); + start_time = std::chrono::high_resolution_clock::now(); + + auto& distance = knownPaths[hash]; + + end_time = std::chrono::high_resolution_clock::now(); + lookupTime += (end_time - start_time); + + if (distance == 0) { + distance = boardStateAfterMove.numberOfMoves; + + parentsOf[hasher.hash(boardStateAfterMove)].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + + start_time = std::chrono::high_resolution_clock::now(); + + // Queue follow-up moves + const auto newMoves = moveDiscovery.gatherMoves( + puzzle.dimensions, + std::make_shared(std::move(boardStateAfterMove)), + puzzle.forbiddenSpots + ); + + end_time = std::chrono::high_resolution_clock::now(); + gatherMovesTime += (end_time - start_time); + start_time = std::chrono::high_resolution_clock::now(); + + for (auto &move : newMoves) { + possibleMoveStack.push_back(std::move(move)); + } + + end_time = std::chrono::high_resolution_clock::now(); + insertMovesTime += (end_time - start_time); + } + } + + return {}; +} + +std::list Solver::solveFast() { + // Note: This can be distributed over multiple threads + // Just lock the datastructure possibleMoveStack when popping moves & reinserting moves + // It's not necessary to check the latest state of possibleMoveStack, worst case scenario + // a few already-known moves will be queued twice + while (!possibleMoveStack.empty()) { + //peek a move + Move firstMove = *(begin(possibleMoveStack)); + // Note: invalidates firstMoveIt + possibleMoveStack.pop_front(); + + BoardState boardStateAfterMove = firstMove.proceed(); + + if (isSolution(boardStateAfterMove, puzzle.goal)) { + return solution(*firstMove.boardState, boardStateAfterMove); + } + + auto& distance = knownPaths[hasher.hash(boardStateAfterMove)]; + if (distance == 0) { + distance = boardStateAfterMove.numberOfMoves; + + parentsOf[hasher.hash(boardStateAfterMove)].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + + // Queue follow-up moves + const auto newMoves = moveDiscovery.gatherMoves( + puzzle.dimensions, + std::make_shared(std::move(boardStateAfterMove)), + puzzle.forbiddenSpots + ); + + for (auto& move : newMoves) { + possibleMoveStack.push_back(std::move(move)); + } + } + } + + return {}; +} + +std::list Solver::solution(const BoardState& firstBoardState, const BoardState& lastBoardState) { + std::list result; + result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, lastBoardState }); + + const auto initialHash = hasher.hash(puzzle.boardState); + HashType stopHash = hasher.hash(firstBoardState); + while (stopHash != 0 && stopHash != initialHash) { + auto start = parentsOf[stopHash]; + if (start.size() > 0 && start[0].first != 0) { + result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, start[0].second }); + stopHash = start[0].first; + } + } + result.push_front(puzzle); + return result; +} + diff --git a/solver.h b/solver.h index d5e5224..8186631 100644 --- a/solver.h +++ b/solver.h @@ -1,249 +1,38 @@ #pragma once -#include -#include -#include -#include -#include - #include "BoardHasher.h" #include "MoveDiscovery.h" -#include "MoveValidation.h" -#include "printer.h" -template -bool isSolution(const BoardState& state, const Block &goal) -{ - return state.m_runner.m_startX == goal.m_startX - && state.m_runner.m_startY == goal.m_startY; -}; - -template -bool containsMove(const std::list> &moves, const Move &move) -{ - return std::any_of(begin(moves), end(moves), [&](const auto &existingMove) - { - return existingMove.m_state.get() == move.m_state.get() - && existingMove.m_directionToMove == move.m_directionToMove - && same(existingMove.m_block, move.m_block); - }); -}; +#include +#include -template < - int BlockCount, - typename MoveDiscovery -> -class Solver -{ +class Solver { public: - using BoardStateId = int; - using MovesFromStart = typename std::remove_const::m_numberOfMovesFromStart)>::type; + using HashType = int; + using NumberOfMovesType = typename std::remove_const::type; public: - Solver(const Puzzle &puzzle) - : m_puzzle{ puzzle } - , m_hasher{ puzzle } - { - const auto initialMoves = MoveDiscovery::gatherMoves( - puzzle.m_dimensions, - std::make_shared>(m_puzzle.m_initialState), - puzzle.m_forbiddenSpots); - for (auto &move : initialMoves) - { - m_possibleMoves.push_back(std::move(move)); - } - } - - ~Solver() = default; - - template - MovesFromStart solve(); - - template<> - MovesFromStart solve() - { - auto globalTime = std::chrono::high_resolution_clock::now(); - auto pickMoveTime = std::chrono::high_resolution_clock::duration{}; - auto solutionCheckTime = std::chrono::high_resolution_clock::duration{}; - auto hashTime = std::chrono::high_resolution_clock::duration{}; - auto lookupTime = std::chrono::high_resolution_clock::duration{}; - auto gatherMovesTime = std::chrono::high_resolution_clock::duration{}; - auto insertMovesTime = std::chrono::high_resolution_clock::duration{}; - - while (!m_possibleMoves.empty()) - { - auto start_time = std::chrono::high_resolution_clock::now(); - - auto firstMove = begin(m_possibleMoves); - auto stateAfterMove = (*firstMove)(); - - auto tempCopy = *firstMove; - - // Note: invalidates firstMove - m_possibleMoves.pop_front(); - - auto end_time = std::chrono::high_resolution_clock::now(); - pickMoveTime += (end_time - start_time); - start_time = std::chrono::high_resolution_clock::now(); - - const auto previousHash = m_hasher.hash(*tempCopy.m_state); - - if (isSolution(stateAfterMove, m_puzzle.m_goal)) - { - std::cout << "Solution is:" << std::endl; - print(Puzzle{ m_puzzle.m_dimensions, m_puzzle.m_goal, m_puzzle.m_forbiddenSpots, stateAfterMove }); - std::cout << "distance: " << stateAfterMove.m_numberOfMovesFromStart << std::endl; - const auto hash = m_hasher.hash(stateAfterMove); - std::cout << "Final hash: " << hash << std::endl; - - const auto initialHash = m_hasher.hash(m_puzzle.m_initialState); - int stopHash = previousHash; - while (stopHash != 0 && stopHash != initialHash) - { - auto start = parentsOf[stopHash]; - if (start.size() > 0 && start[0].first != 0) - { - std::cout << start[0].first << std::endl; - print(Puzzle{ m_puzzle.m_dimensions, m_puzzle.m_goal, m_puzzle.m_forbiddenSpots, start[0].second }); - std::cout << std::endl << " -------------- " << std::endl; - - stopHash = start[0].first; - } - } - - std::cout << initialHash << std::endl; - print(Puzzle{ m_puzzle.m_dimensions, m_puzzle.m_goal, m_puzzle.m_forbiddenSpots, m_puzzle.m_initialState }); - std::cout << std::endl << " -------------- " << std::endl; - - const auto now = std::chrono::high_resolution_clock::now(); - std::cout << "Total time was: " << std::chrono::duration_cast(now - globalTime).count() << std::endl; - std::cout << "pickMoveTime " << std::chrono::duration_cast(pickMoveTime).count() << std::endl; - std::cout << "solutionCheckTime " << std::chrono::duration_cast(solutionCheckTime).count() << std::endl; - std::cout << "hashTime " << std::chrono::duration_cast(hashTime).count() << std::endl; - std::cout << "lookupTime " << std::chrono::duration_cast(lookupTime).count() << std::endl; - std::cout << "gatherMovesTime " << std::chrono::duration_cast(gatherMovesTime).count() << std::endl; - std::cout << "insertMovesTime " << std::chrono::duration_cast(insertMovesTime).count() << std::endl; - - return stateAfterMove.m_numberOfMovesFromStart; - } + Solver(const Puzzle &puzzle, const MoveDiscovery& moveDiscovery); + ~Solver() = default; + std::list solve(std::ostream* debugOut = nullptr); - end_time = std::chrono::high_resolution_clock::now(); - solutionCheckTime += (end_time - start_time); - start_time = std::chrono::high_resolution_clock::now(); - - const auto hash = m_hasher.hash(stateAfterMove); - - end_time = std::chrono::high_resolution_clock::now(); - hashTime += (end_time - start_time); - start_time = std::chrono::high_resolution_clock::now(); - - auto &distance = m_knownPaths[hash]; - - end_time = std::chrono::high_resolution_clock::now(); - lookupTime += (end_time - start_time); - - if (distance == 0) // New path - /*|| (distance > 0 // Shorter path - && distance > stateAfterMove.m_numberOfMovesFromStart))*/ - { - auto &parents = parentsOf[hash]; - parents.push_back({ previousHash, stateAfterMove }); - - distance = stateAfterMove.m_numberOfMovesFromStart; - - start_time = std::chrono::high_resolution_clock::now(); - - // Queue follow-up moves - const auto newMoves = MoveDiscovery::gatherMoves( - m_puzzle.m_dimensions, - std::make_shared>(std::move(stateAfterMove)), - m_puzzle.m_forbiddenSpots); - - end_time = std::chrono::high_resolution_clock::now(); - gatherMovesTime += (end_time - start_time); - start_time = std::chrono::high_resolution_clock::now(); - - for (auto &move : newMoves) - { - m_possibleMoves.push_back(std::move(move)); - } - - end_time = std::chrono::high_resolution_clock::now(); - insertMovesTime += (end_time - start_time); - } - } - - return -1; - } - - template<> - MovesFromStart solve() - { - // Note: This can be distributed over multiple threads - // Just lock the datastructure m_possibleMoves when popping moves & reinserting moves - // It's not necessary to check the latest state of m_possibleMoves, worst case scenario - // a few already-known moves will be queued twice - while (!m_possibleMoves.empty()) - { - auto firstMove = begin(m_possibleMoves); - auto stateAfterMove = (*firstMove)(); - // Note: invalidates firstMove - m_possibleMoves.pop_front(); - - if (isSolution(stateAfterMove, m_puzzle.m_goal)) - { - return stateAfterMove.m_numberOfMovesFromStart; - } - - const auto hash = m_hasher.hash(stateAfterMove); - - auto &distance = m_knownPaths[hash]; - - if (distance == 0) // New path - /*|| (distance > 0 // Shorter path - && distance > stateAfterMove.m_numberOfMovesFromStart))*/ - { - distance = stateAfterMove.m_numberOfMovesFromStart; - - // Queue follow-up moves - const auto newMoves = MoveDiscovery::gatherMoves( - m_puzzle.m_dimensions, - std::make_shared>(std::move(stateAfterMove)), - m_puzzle.m_forbiddenSpots); - - for (auto &move : newMoves) - { - m_possibleMoves.push_back(std::move(move)); - } - } - } - - return -1; - } +private: + std::list solveDebug(std::ostream* debugOut); + std::list solveFast(); + std::list solution(const BoardState& firstBoardState, const BoardState& lastBoardState); - // Retrieves all currently queued moves - const std::list>& possibleMoves() - { - return m_possibleMoves; - } + const Puzzle puzzle; + BoardHasher hasher; -private: - const Puzzle m_puzzle; - BoardHasher<> m_hasher; + // Stores all possible moves to explore + std::list possibleMoveStack; - // Stores all possible moves to explore - std::list> m_possibleMoves; + // Stores the number of moves from the starting state + std::unordered_map knownPaths; - // Stores the number of moves from the starting state - std::unordered_map m_knownPaths; + // Testing rermove me + std::unordered_map>> parentsOf; - // Testing rermove me - using State = std::pair>; - std::unordered_map> parentsOf; + const MoveDiscovery& moveDiscovery; }; -template > -Solver makeSolver(const Puzzle &puzzle) -{ - return Solver{ puzzle }; -} diff --git a/test.cpp b/test.cpp index 8b33a87..4ed05fe 100644 --- a/test.cpp +++ b/test.cpp @@ -1,325 +1,735 @@ -#include "test.h" +#include "solver.h" +#include "printer.h" +#include "BoardHasher.h" +#include "MoveDiscovery.h" +#include "MoveValidation.h" #include #include +#include + + +namespace { + auto compareString = [&](const std::string& s1, const std::string& s2) { + if (s1 != s2) { + std::cout << s1 << "\n!=\n" << s2 << "\n"; + } + return s1 == s2; + }; + + // Standard klotski puzzle + // print for sample ascii layout + const Puzzle largePuzzle { + { 4, 6 }, // dims + { 1, 4 }, // goal + { // invalid spaces + { 0, 5 }, + { 3, 5 }, + }, + { // Initial board state + 0, // no moves made, + Block({ 1, 0 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "@"), // runner + { // blocks + Block({ 0, 0 }, { { 0, 0 }, { 0, 1 } }, "A"), + Block({ 0, 2 }, { { 0, 0 }, { 0, 1 } }, "B"), + Block({ 1, 2 }, { { 0, 0 }, { 1, 0 } }, "C"), + Block({ 1, 3 }, { { 0, 0 } }, "D"), + Block({ 2, 3 }, { { 0, 0 } }, "E"), + Block({ 3, 0 }, { { 0, 0 }, { 0, 1 } }, "F"), + Block({ 3, 2 }, { { 0, 0 }, { 0, 1 } }, "G"), + Block({ 0, 4 }, { { 0, 0 } }, "H"), + Block({ 3, 4 }, { { 0, 0 } }, "I") + } + } + }; + + // Empty 3x3 block + // Runner 1x1 at the origin + // Single 1x1 block in the middle of the board + const Puzzle emptyPuzzle { + { 3, 3 }, // dims + { 2, 2 }, // goal + { + { 1, 1 } // single hindrance in the middle + }, // empty spaces + { + 0, // no moves made, + Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner at origin + {} // no blocks + } + }; + + const Puzzle tinyPuzzle + { + { 3, 3 }, // dims + { 1, 1 }, // goal + {}, // empty spaces + { + 0, // no moves made, + Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner + { + Block({1, 1 }, { { 0, 0 } }, "A") // Single block on the goal + } + } + }; + + // Empty 3x3 block + // Runner 1x1 at the origin + // Single 1x1 block in the middle of the board + const Puzzle smallPuzzle + { + { 3, 3 }, // dims + { 2, 2 }, // goal + { + { 1, 1 } + }, // empty spaces + { + 0, // no moves made, + Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner at origin + { // 2 blocks surrounding origin + Block({ 1, 0 }, { { 0, 0 } }, "A"), + Block({ 0, 1 }, { { 0, 0 } }, "B") + } + } + }; + + // Tetris klotski puzzle + // print for sample ascii layout + const Puzzle tetrisPuzzle { + { 5, 6 }, // dims + { 0, 0 }, // goal + { // invalid spaces + { 0, 5 }, + { 4, 5 }, + }, + { // Initial board state + 0, // no moves made, + Block({ 3, 2 }, { { 0, 0 }, { 0, 2 }, { 1, 0 }, { 1, 1 }, { 1, 2 } }, "@"), // runner + { // blocks + Block({ 2, 1 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 0 }, { 1, 2 } }, "A") + } + } + }; -#include "solver.h" -#include "MoveDiscovery.h" -#include "MoveValidation.h" +} +void testPuzzles() { + auto testPuzzle = [&](const auto& puzzle) { + auto puzzleValidation = puzzle.validate(); + if (valid != puzzleValidation) { + printText(puzzle, std::cout); + std::cout << Puzzle::validationString(puzzleValidation) << std::endl; + return false; + } + return true; + }; + + assert(testPuzzle(emptyPuzzle)); + assert(testPuzzle(tinyPuzzle)); + assert(testPuzzle(smallPuzzle)); + assert(testPuzzle(largePuzzle)); + assert(testPuzzle(tetrisPuzzle)); +} -namespace -{ - // Standard klotski puzzle - // print for sample ascii layout - const Puzzle<9> largePuzzle - { - { 4, 6 }, // dims - { 1, 4, 2, 2, "^"}, // goal - { // invalid spaces - { 0, 5 }, - { 3, 5 }, - }, - { // Initial board state - 0, // no moves made, - { 1, 0, 2, 2, "@"}, // runner - { // blocks - Block{ 0, 0, 1, 2, "A"}, - Block{ 0, 2, 1, 2, "B" }, - Block{ 1, 2, 2, 1, "C" }, - Block{ 1, 3, 1, 1, "D" }, - Block{ 2, 3, 1, 1, "E" }, - Block{ 3, 0, 1, 2, "F" }, - Block{ 3, 2, 1, 2, "G" }, - Block{ 0, 4, 1, 1, "H" }, - Block{ 3, 4, 1, 1, "I" } - } - } - }; - - // Empty 3x3 block - // Runner 1x1 at the origin - // Single 1x1 block in the middle of the board - const Puzzle<0> emptyPuzzle - { - { 3, 3 }, // dims - { 2, 2, 1, 1, "$" }, // goal - { - { 1, 1 } // single hindrance in the middle - }, // empty spaces - { - 0, // no moves made, - { 0, 0, 1, 1, "@"}, // runner at origin - {} // no blocks - } - }; - - const Puzzle<1> tinyPuzzle - { - { 3, 3 }, // dims - { 1, 1, 1, 1, "$"}, // goal - {}, // empty spaces - { - 0, // no moves made, - { 0, 0, 1, 1, "@"}, // runner in the middle - { - {1, 1, 1, 1, "A"} // Single block on the goal - } - } - }; - - // Empty 3x3 block - // Runner 1x1 at the origin - // Single 1x1 block in the middle of the board - const Puzzle<2> smallPuzzle - { - { 3, 3 }, // dims - { 2, 2, 1, 1, "$" }, // goal - { - { 1, 1 } - }, // empty spaces - { - 0, // no moves made, - { 0, 0, 1, 1, "@"}, // runner at origin - { // 2 blocks surrounding origin - Block{ 1, 0, 1, 1, "A"}, - Block{ 0, 1, 1, 1, "B" } - } - } - }; +void testPoint() { + Point p1{2, 5}; + Point p2{2, 4}; + Point p3{2, 5}; + assert(p1 != p2); + assert(p1 == p3); + + std::set pointSet = { + { 0, 0 }, + { 1, 5 }, + { 0, 0 }, + { -1, 5 }, + { 0, 0 }, + { 1, -5 }, + { 1, 4 }, + }; + std::stringstream orderResult; + for (const Point& p : pointSet) { + orderResult << p.x << ", " << p.y << "\n"; + } + const std::string orderExpected = + "-1, 5\n" + "0, 0\n" + "1, -5\n" + "1, 4\n" + "1, 5\n" + ; + assert(compareString(orderResult.str(), orderExpected)); } -void testPuzzles() -{ - assert(valid(emptyPuzzle)); - assert(valid(tinyPuzzle)); - assert(valid(smallPuzzle)); - assert(valid(largePuzzle)); +void testBlocks() { + { + //overlaps Block + Block singleLeft({ 1, 1 }, { { 0, 0 } }, "1"); + Block singleRight({ 3, 1 }, { { 0, 0 } }, "2"); + Block singleMiddle({ 2, 1 }, { { 0, 0 } }, "3"); + Block doubleLeft({ 0, 0 }, { { 0, 0 }, { 1, 0 } }, "4"); + Block doubleRight({ 1, 0 }, { { 0, 0 }, { 1, 0 } }, "5"); + Block somewhereElse({ 2, 2 }, { { 0, 0 } }, "6"); + + assert(!singleLeft.overlaps(singleRight)); + assert(!singleLeft.overlaps(singleMiddle)); + assert(doubleLeft.overlaps(doubleRight) && "Block should overlap in the middle"); + assert(doubleRight.overlaps(doubleLeft) && "Block should overlap in the middle"); + assert(!doubleLeft.overlaps(somewhereElse) && "Blocks should not overlap"); + assert(!doubleRight.overlaps(somewhereElse) && "Blocks should not overlap"); + } + + { + //overlaps Point + Block b({ 1, 1 }, { { 0, 1 }, { 1, 0 } }, "x"); + + std::stringstream strResult; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + strResult << x << ", " << y << " : " << ((b.overlaps(Point{ x, y })) ? "true" : "false") << "\n"; + } + } + assert(compareString( + strResult.str(), + "0, 0 : false\n" + "1, 0 : false\n" + "2, 0 : false\n" + "3, 0 : false\n" + + "0, 1 : false\n" + "1, 1 : false\n" + "2, 1 : true\n" + "3, 1 : false\n" + + "0, 2 : false\n" + "1, 2 : true\n" + "2, 2 : false\n" + "3, 2 : false\n" + + "0, 3 : false\n" + "1, 3 : false\n" + "2, 3 : false\n" + "3, 3 : false\n" + )); + } + + { + std::vector shapeList = { + Block({ 0, 0 }, { { 0, 0 } }, "1"), + Block({ 1, 5 }, { { 0, 0 } }, "2"), + Block({ 0, 0 }, { { 0, 0 }, { 1, 1 } }, "3"), + Block({ 0, 0 }, { { 1, 1 }, { 0, 0 } }, "4"), + }; + + std::stringstream shapeComareResult; + for (size_t i = 0; i < shapeList.size(); ++i) { + for (size_t j = 0; j < shapeList.size(); ++j) { + shapeComareResult << i << ", " << j << " : " << ((shapeList[i].pointSet == shapeList[j].pointSet) ? "true" : "false") << "\n"; + } + } + assert(compareString( + shapeComareResult.str(), + "0, 0 : true\n" + "0, 1 : true\n" + "0, 2 : false\n" + "0, 3 : false\n" + + "1, 0 : true\n" + "1, 1 : true\n" + "1, 2 : false\n" + "1, 3 : false\n" + + "2, 0 : false\n" + "2, 1 : false\n" + "2, 2 : true\n" + "2, 3 : true\n" + + "3, 0 : false\n" + "3, 1 : false\n" + "3, 2 : true\n" + "3, 3 : true\n" + )); + } } -void testBlocks() -{ - Block singleLeft{ 1, 1, 1, 1 }; - Block singleRight{ 3, 1, 1, 1 }; - Block singleMiddle{ 2, 1, 1, 1 }; - Block doubleLeft{ 0, 0, 2, 1 }; - Block doubleRight{ 1, 0, 2, 1 }; - Block somewhereElse{ 2, 2, 1, 1 }; - - assert(!overlaps(singleLeft, singleRight)); - assert(!overlaps(singleLeft, singleMiddle)); - assert(overlaps(doubleLeft, doubleRight) && "Block should overlap in the middle"); - assert(overlaps(doubleRight, doubleLeft) && "Block should overlap in the middle"); - assert(!overlaps(doubleLeft, somewhereElse) && "Blocks should not overlap"); - assert(!overlaps(doubleRight, somewhereElse) && "Blocks should not overlap"); - - Block middle{ 2, 2, 2, 2 }; - Block origin{ 0, 0, 1, 1 }; - std::vector freeSpaceLeft{ { 1, 2 } }; - std::vector freeSpaceRight{ { 4, 2 } }; - std::vector freeSpaceTop{ { 3, 1 } }; - std::vector freeSpaceBottom{ { 3, 4} }; - - assert(nextToFreeSpace(middle, freeSpaceLeft) && "Block should be next to free space"); - assert(nextToFreeSpace(middle, freeSpaceRight) && "Block should be next to free space"); - assert(nextToFreeSpace(middle, freeSpaceTop) && "Block should be next to free space"); - assert(nextToFreeSpace(middle, freeSpaceBottom) && "Block should be next to free space"); - assert(!nextToFreeSpace(origin, freeSpaceBottom) && "Origin should not be next to free space"); - assert(!nextToFreeSpace(origin, freeSpaceTop) && "Origin should not be next to free space"); - assert(!nextToFreeSpace(origin, freeSpaceRight) && "Origin should not be next to free space"); - assert(!nextToFreeSpace(origin, freeSpaceLeft) && "Origin should not be next to free space"); - - assert(equalPosition(move(middle, Direction::Up), Block{ 2, 1, 2, 2 })); - assert(equalPosition(move(middle, Direction::Down), Block{ 2, 3, 2, 2 })); - assert(equalPosition(move(middle, Direction::Left), Block{ 1, 2, 2, 2 })); - assert(equalPosition(move(middle, Direction::Right), Block{ 3, 2, 2, 2 })); - - assert(same(move(middle, Direction::Up), Block{ 2, 1, 2, 2, middle.id })); - assert(same(move(middle, Direction::Down), Block{ 2, 3, 2, 2, middle.id })); - assert(same(move(middle, Direction::Left), Block{ 1, 2, 2, 2, middle.id })); - assert(same(move(middle, Direction::Right), Block{ 3, 2, 2, 2, middle.id })); +void testPrintScan() { + auto checkPrintScan = [&](const Puzzle& p, const std::string& expectedText) { + //print text + std::stringstream strResult; + printText(p, strResult); + if (!compareString(strResult.str(), expectedText)) { + return false; + } + + //scan + Puzzle scanResult(scanText(strResult)); + + if (scanResult != p) { + printText(p, std::cout); + std::cout << "puzzle scan differs\n"; + printText(scanResult, std::cout); + return false; + } + + return true; + }; + + assert(checkPrintScan( + tetrisPuzzle, + "5 6\n" + "0 0\n" + "#######\n" + "#^^ #\n" + "# ^AA #\n" + "#^^A@@#\n" + "# AA@#\n" + "# @@#\n" + "## ##\n" + "#######\n" + )); + + assert(checkPrintScan( + largePuzzle, + "4 6\n" + "1 4\n" + "######\n" + "#A@@F#\n" + "#A@@F#\n" + "#BCCG#\n" + "#BDEG#\n" + "#H^^I#\n" + "##^^##\n" + "######\n" + )); + + { + //print svg style + std::stringstream strResult; + printSvgStyle(largePuzzle, strResult); + assert(compareString( + strResult.str(), + " .dimensions { stroke : red; stroke-width : 0.1; }" + " .blockRunner { fill : red; }" + " .blockWall { fill : black; }" + " .blockGoal { fill : powderblue; }" + " .blockA { fill : pink; }" + " .blockB { fill : aqua; }" + " .blockC { fill : blueviolet; }" + " .blockD { fill : darkblue; }" + " .blockE { fill : darkcyan; }" + " .blockF { fill : darkgoldenrod; }" + " .blockG { fill : darkred; }" + " .blockH { fill : darkmagenta; }" + " .blockI { fill : darkorchid; }" + " .puzzle { fill : #202020; }" + )); + } + + { + //print svg Point + std::stringstream strResult; + printSvg(Point{2, 5}, strResult); + assert(compareString(strResult.str(), "")); + } + + { + //print svg Block + std::stringstream strResult; + printSvg(Block({ 1, 2 }, { { 0, 0 }, { 0, 1 }, { 1, 0 } }, "A"), strResult); + assert(compareString(strResult.str(), + "" + "" + "" + "" + "" + )); + } + + { + //print svg BoardState + std::stringstream strResult; + printSvg(tetrisPuzzle.boardState, strResult); + assert(compareString(strResult.str(), + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + )); + } + + { + //print svg Puzzle + std::stringstream strResult; + printSvg(tetrisPuzzle, strResult); + assert(compareString(strResult.str(), + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + )); + } + + { + //print svg Puzzle list + std::stringstream strResult; + printSvg(std::list{ tetrisPuzzle, tetrisPuzzle}, "av", "ap", strResult); + assert(compareString(strResult.str(), + "av" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "apav" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "ap" + )); + } + + { + //print html Puzzle list + std::stringstream strResult; + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle}, strResult); + assert(compareString(strResult.str(), + "\n" + "\n" + " 1" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n" + " 2" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n" + "" + )); + } + } -void testMoveValidation() -{ - // Test if class can be constructed - DefaultMoveValidation moveValidation{}; - - // Test that all blocks do not overlap with their current state on the board - for (const auto &block : largePuzzle.m_initialState.m_blocks) - { - assert( - DefaultMoveValidation::validBlockPosition(block, largePuzzle.m_dimensions, largePuzzle.m_initialState, largePuzzle.m_forbiddenSpots) - && "A block should never overlap itself"); - - auto blockAtSamePosition = block; - blockAtSamePosition.id = "Another Block"; - assert( - !DefaultMoveValidation::validBlockPosition(blockAtSamePosition, largePuzzle.m_dimensions, largePuzzle.m_initialState, largePuzzle.m_forbiddenSpots) - && "2 blocks at the same position should always overlap"); - } - - // Test that a block can move in all directions on an empty board - const auto isRunnerPosition = [&](const auto x, const auto y) - { - return x == emptyPuzzle.m_initialState.m_runner.m_startX - && y == emptyPuzzle.m_initialState.m_runner.m_startY; - }; - - const auto isBlockPosition = [&](const auto x, const auto y) - { - return x == emptyPuzzle.m_forbiddenSpots[0].m_x - && y == emptyPuzzle.m_forbiddenSpots[0].m_y; - }; - - for (auto i = 0; i < emptyPuzzle.m_dimensions.m_x; i++) - { - for (auto j = 0; j < emptyPuzzle.m_dimensions.m_y; ++j) - { - if (!isRunnerPosition(i, j) && !isBlockPosition(i, j)) - { - const auto block = Block{ i, j, 1, 1, "someBlock" }; - assert( - DefaultMoveValidation::validBlockPosition(block, emptyPuzzle.m_dimensions, emptyPuzzle.m_initialState, emptyPuzzle.m_forbiddenSpots) - && "Block should be able to be positioned anywhere except origin & center"); - } - } - } + +void testMoveValidation() { + // Test if class can be constructed + //MoveValidation moveValidation{}; + + // Test that all blocks do not overlap with their current state on the board + for (const auto &block : largePuzzle.boardState.blocks) { + assert( + validBlockPosition(block, largePuzzle.dimensions, largePuzzle.boardState, largePuzzle.forbiddenSpots) + && "A block should never overlap itself" + ); + + auto blockAtSamePosition = block; + blockAtSamePosition.id = "Another Block"; + assert( + !validBlockPosition(blockAtSamePosition, largePuzzle.dimensions, largePuzzle.boardState, largePuzzle.forbiddenSpots) + && "2 blocks at the same position should always overlap" + ); + } + + // Test all block pisition + //printText(emptyPuzzle, std::cout); + assert(!validBlockPosition(Block({ 0, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 1, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 0, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert(!validBlockPosition(Block({ 1, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 0, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 1, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); } -void testMoveDiscovery() -{ - // Test if class can be constructed - MoveRunnerFirst<> moveRunnerFirst{}; - - { - using BoardType = std::remove_const::type; - - const auto runnerMoves = 2; // Down + Right - const auto blockMoves = 4; // Up + Down + Right + Left - const auto newMoves = MoveRunnerFirst<>::gatherMoves( - tinyPuzzle.m_dimensions, - std::make_shared(tinyPuzzle.m_initialState), - tinyPuzzle.m_forbiddenSpots); - assert(!newMoves.empty() && "At least some moves should be possible"); - assert(newMoves.size() == (runnerMoves + blockMoves) && "We should have 6 moves discovered"); - } - - { - using BoardType = std::remove_const::type; - - const auto blockMoves = 4; - auto newMoves = MoveRunnerFirst<>::gatherMoves( - largePuzzle.m_dimensions, - std::make_shared(largePuzzle.m_initialState), - largePuzzle.m_forbiddenSpots); - assert(!newMoves.empty() && "At least some moves should be possible"); - assert(newMoves.size() == blockMoves && "We should have 4 moves discovered"); - } +void testMoveDiscovery() { + MoveRunnerFirst moveDiscovery; + { + const int runnerMoves = 2; // Down + Right + const int blockMoves = 4; // Up + Down + Right + Left + const auto newMoves = moveDiscovery.gatherMoves( + tinyPuzzle.dimensions, + std::make_shared(tinyPuzzle.boardState), + tinyPuzzle.forbiddenSpots + ); + assert(!newMoves.empty() && "At least some moves should be possible"); + assert(newMoves.size() == (runnerMoves + blockMoves) && "We should have 6 moves discovered"); + } + + { + const auto blockMoves = 4; + auto newMoves = moveDiscovery.gatherMoves( + largePuzzle.dimensions, + std::make_shared(largePuzzle.boardState), + largePuzzle.forbiddenSpots + ); + assert(!newMoves.empty() && "At least some moves should be possible"); + //std::cout << "discover " << newMoves.size() << " moves" << std::endl; + assert(newMoves.size() == blockMoves && "We should have 4 moves discovered"); + } } -void testMoving() -{ - constexpr auto blockCount = largePuzzle.m_initialState.blockCount; - using BoardType = std::remove_const::type; +void testMoving() { + using BoardType = std::remove_const::type; + + auto sharedState = std::make_shared(largePuzzle.boardState); + Move moveRight{ sharedState, sharedState->blocks[0], Direction::Right }; + assert(sharedState.get() == moveRight.boardState.get() && "A move should not copy the state, but only reference the original state"); - auto sharedState = std::make_shared(largePuzzle.m_initialState); - Move moveRight{ sharedState, sharedState->m_blocks[0], Direction::Right }; - assert(sharedState.get() == moveRight.m_state.get() && "A move should not copy the state, but only reference the original state"); + const auto afterMoveRight = moveRight.proceed(); + assert(sharedState->blocks[0].move(Direction::Right) == afterMoveRight.blocks[0]); + assert(sharedState->blocks[0].move(Direction::Left) != afterMoveRight.blocks[0]); + assert(sharedState->blocks[0].move(Direction::Up) != afterMoveRight.blocks[0]); + assert(sharedState->blocks[0].move(Direction::Down) != afterMoveRight.blocks[0]); + assert(sharedState->blocks[0].id == afterMoveRight.blocks[0].id); - const auto afterMoveRight = moveRight(); - assert(equalPosition(move(sharedState->m_blocks[0], Direction::Right), afterMoveRight.m_blocks[0])); - assert(!equalPosition(move(sharedState->m_blocks[0], Direction::Left), afterMoveRight.m_blocks[0])); - assert(!equalPosition(move(sharedState->m_blocks[0], Direction::Up), afterMoveRight.m_blocks[0])); - assert(!equalPosition(move(sharedState->m_blocks[0], Direction::Down), afterMoveRight.m_blocks[0])); - assert(same(sharedState->m_blocks[0], afterMoveRight.m_blocks[0])); + assert(sharedState->numberOfMoves + 1 == afterMoveRight.numberOfMoves); + + { + Block middle({ 2, 2 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"); + assert(middle == (Block({ 0, 0 }, { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }, "blockMid"))); + assert(middle == (Block({ 0, 0 }, { { 3, 3 }, { 2, 2 }, { 3, 2 }, { 2, 3 } }, "blockMid"))); + + assert(middle.move(Direction::Up) == (Block({ 2, 1 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"))); + assert(middle.move(Direction::Down) == (Block({ 2, 3 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"))); + assert(middle.move(Direction::Left) == (Block({ 1, 2 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"))); + assert(middle.move(Direction::Right) == (Block({ 3, 2 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"))); + } - assert(sharedState->m_numberOfMovesFromStart + 1 == afterMoveRight.m_numberOfMovesFromStart); } -void testHashing() -{ - // Test if type can be constructed - BoardHasher<> emptyHasher{ emptyPuzzle }; - BoardHasher<> initialHasher{ largePuzzle }; - - assert(emptyHasher.hash(emptyPuzzle.m_initialState) == emptyHasher.hash(emptyPuzzle.m_initialState) - && "Hash for identical states should be equal"); - assert(initialHasher.hash(largePuzzle.m_initialState) == initialHasher.hash(largePuzzle.m_initialState) - && "Hash for identical states should be equal"); - assert(initialHasher.hash(largePuzzle.m_initialState) != emptyHasher.hash(emptyPuzzle.m_initialState) - && "Hash for different states should be different"); - - auto swappedBlocks = largePuzzle.m_initialState.m_blocks; - auto temp= swappedBlocks[0]; - swappedBlocks[0].id = swappedBlocks[1].id; - swappedBlocks[1].id = temp.id; - BoardState swappedState{ - 0, - largePuzzle.m_initialState.m_runner, - swappedBlocks - }; - assert(initialHasher.hash(swappedState) == initialHasher.hash(largePuzzle.m_initialState) - && "Hash should be the same for 2 same-sized blocks in swapped positions"); +void testHashing() { + // Test if type can be constructed + BoardHasher emptyHasher{ emptyPuzzle }; + BoardHasher initialHasher{ largePuzzle }; + + assert(emptyHasher.hash(emptyPuzzle.boardState) == emptyHasher.hash(emptyPuzzle.boardState) && "Hash for identical states should be equal"); + assert(initialHasher.hash(largePuzzle.boardState) == initialHasher.hash(largePuzzle.boardState) && "Hash for identical states should be equal"); + assert(initialHasher.hash(largePuzzle.boardState) != emptyHasher.hash(emptyPuzzle.boardState) && "Hash for different states should be different"); + + auto swappedBlocks = largePuzzle.boardState.blocks; + auto temp= swappedBlocks[0]; + swappedBlocks[0].id = swappedBlocks[1].id; + swappedBlocks[1].id = temp.id; + BoardState swappedState{ + 0, + largePuzzle.boardState.runner, + swappedBlocks + }; + assert(initialHasher.hash(swappedState) == initialHasher.hash(largePuzzle.boardState) && "Hash should be the same for 2 same-sized blocks in swapped positions"); +} +auto testSolverFx = [&](Solver solver, const bool& debug, std::string expectedOut = "") { + std::stringstream out; + std::list result; + if (debug) { + result = solver.solve(&out); + } else { + result = solver.solve(); + } + + if ("" != expectedOut) { + printText(result, out); + assert(compareString(out.str(), expectedOut)); + } + + std::cout << "found solution in " << (result.size() - 1) << " steps" << std::endl; + return result; +}; + +void testSolver() { + MoveRunnerFirst moveDiscovery; + assert( 4 == testSolverFx(Solver(tinyPuzzle, moveDiscovery), true).size()); + + assert( 4 == testSolverFx(Solver(tinyPuzzle, moveDiscovery), false, + "\n" + "-------------- 0\n" + "3 3\n" + "1 1\n" + "#####\n" + "#@ #\n" + "# A #\n" + "# #\n" + "#####\n" + "\n" + "-------------- 1\n" + "3 3\n" + "1 1\n" + "#####\n" + "# #\n" + "#@A #\n" + "# #\n" + "#####\n" + "\n" + "-------------- 2\n" + "3 3\n" + "1 1\n" + "#####\n" + "# #\n" + "#@^ #\n" + "# A #\n" + "#####\n" + "\n" + "-------------- 3\n" + "3 3\n" + "1 1\n" + "#####\n" + "# #\n" + "# @ #\n" + "# A #\n" + "#####\n" + ).size()); + assert( 5 == testSolverFx(Solver(emptyPuzzle, moveDiscovery), false).size()); + assert( 9 == testSolverFx(Solver(smallPuzzle, moveDiscovery), false).size()); + assert( 9 == testSolverFx(Solver(tetrisPuzzle, moveDiscovery), false).size()); + assert(39 == testSolverFx(Solver(largePuzzle, moveDiscovery), false).size()); } -void testSolver() -{ - { - const auto blockCount = tinyPuzzle.m_initialState.blockCount; - auto solver = makeSolver(tinyPuzzle); - - assert( - !solver.possibleMoves().empty() - && "A few initial moves are available"); - - const auto result = solver.solve(); - std::cout << "found solution in " << result << " steps" << std::endl; - assert(result < 4 && result > 0 && "Tiny puzzle should be solved in less than 4 moves"); - } - - { - auto solver = makeSolver(emptyPuzzle); - assert( - !solver.possibleMoves().empty() - && "A few initial moves are available"); - - const auto result = solver.solve(); - std::cout << "found solution in " << result << " steps" << std::endl; - assert(result < 6 && result > 0 && "Empty puzzle should be solved in less than 6 moves"); - } - - { - auto solver = makeSolver(smallPuzzle); - assert( - !solver.possibleMoves().empty() - && "A few initial moves are available"); - - const auto result = solver.solve(); - std::cout << "found solution in " << result << " steps" << std::endl; - assert(result < 10 && result > 0 && "Small puzzle should be solved in less than 10 moves"); - } - - { - auto solver = makeSolver(largePuzzle); - assert( - !solver.possibleMoves().empty() - && "A few initial moves are available"); - - const auto result = solver.solve(); - std::cout << "found solution in " << result << " steps" << std::endl; - assert(result > 0 && result < 50 && "Not sure what a reasonable number of moves is here..."); - } +int main(int /*argc*/, char* /*argv*/[]) { + testPoint(); + testBlocks(); + testPuzzles(); + testPrintScan(); + testMoveValidation(); + testMoveDiscovery(); + testMoving(); + testHashing(); + testSolver(); } -int main(int argc, char *argv[]) -{ - testBlocks(); - testPuzzles(); - testMoveValidation(); - testMoveDiscovery(); - testMoving(); - testHashing(); - testSolver(); -} \ No newline at end of file diff --git a/test.h b/test.h deleted file mode 100644 index 6f70f09..0000000 --- a/test.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once From 9f74335a6422c70ee20a4e78a5d3a4b9478ce9e7 Mon Sep 17 00:00:00 2001 From: pga78 <71857699+pga78@users.noreply.github.com> Date: Sun, 27 Sep 2020 08:48:07 +0200 Subject: [PATCH 02/10] Update README.md --- README.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1dbcdeb..961e02a 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,36 @@ # klotski-solver -a klotski-solver written in C++ +a klotski-solver written in C++ No external libraries used. Not even for UTests. # Build instructions ## Linux -rm -frv /tmp/build -mkdir -pv /tmp/build && cmake -B /tmp/build -S . && make -j --directory=/tmp/build && /tmp/build/unit-tests && echo done +rm -frv /tmp/build; +mkdir -pv /tmp/build && cmake -B /tmp/build -S . && make -j --directory=/tmp/build && echo done ## Windows -mkdir build && cd build && cmake .. +mkdir build && cd build && cmake .. Build with Visual studio 2017 # Run ## Tests ### Linux -/tmp/build/unit-tests +`/tmp/build/unit-tests` ### Windows run `unit-tests.exe` in debug build ## Solve ### Linux -/tmp/build/solve < "in_smallPuzzle.txt" 1> out_smallPuzzle.html -/tmp/build/solve < "in_smallPuzzle.txt" 2> /dev/null -/tmp/build/solve < "in_largePuzzle.txt" -time /tmp/build/solve < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt +`/tmp/build/solve` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +`/tmp/build/solve` < "in_smallPuzzle.txt" 2> /dev/null +`/tmp/build/solve` < "in_largePuzzle.txt" +time `/tmp/build/solve` < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt ### Windows -solve.exe < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +`solve.exe` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html # Notes -solve is using : +`solve` is using : - standard input as puzzle to solve - standard output as html solution - error output as text solution and puzzle bug - From f3ccd5094eafcdff5884987216cb6783dfc35b16 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Tue, 29 Sep 2020 00:25:34 +0200 Subject: [PATCH 03/10] add animate html output --- README.md | 18 ++- main.cpp | 3 +- out_hardPuzzle.html | 366 ++++++++++++++++++++++--------------------- out_smallPuzzle.html | 20 +-- printer.cpp | 136 +++++++++++++--- printer.h | 24 ++- test.cpp | 275 +++++++++++++++++++++++++++++++- 7 files changed, 610 insertions(+), 232 deletions(-) diff --git a/README.md b/README.md index 961e02a..f1f7222 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # klotski-solver a klotski-solver written in C++ -No external libraries used. Not even for UTests. +No external libraries used. Not even for UTests. +text input. +text, svg, animated html output. # Build instructions ## Linux -rm -frv /tmp/build; -mkdir -pv /tmp/build && cmake -B /tmp/build -S . && make -j --directory=/tmp/build && echo done +rm -frv "/tmp/build"; +mkdir -pv "/tmp/build" && cmake -B "/tmp/build" -S . && make -j --directory="/tmp/build" && echo done ## Windows mkdir build && cd build && cmake .. @@ -14,17 +16,17 @@ Build with Visual studio 2017 # Run ## Tests ### Linux -`/tmp/build/unit-tests` +"/tmp/build/unit-tests" && echo done ### Windows run `unit-tests.exe` in debug build ## Solve ### Linux -`/tmp/build/solve` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html -`/tmp/build/solve` < "in_smallPuzzle.txt" 2> /dev/null -`/tmp/build/solve` < "in_largePuzzle.txt" -time `/tmp/build/solve` < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt +"/tmp/build/solve" < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +"/tmp/build/solve" < "in_smallPuzzle.txt" 2> /dev/null +"/tmp/build/solve" < "in_largePuzzle.txt" +time "/tmp/build/solve" < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt ### Windows `solve.exe` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html diff --git a/main.cpp b/main.cpp index 8a83b0d..8529b8b 100644 --- a/main.cpp +++ b/main.cpp @@ -11,7 +11,8 @@ int main(int /*argc*/, char* /*argv*/[]) { return 1; } - printHtml(result, std::cout); + printHtml(result, true, 100, std::cout); + //printHtml(result, false, 20, std::cout); printText(result, std::cerr); return 0; } diff --git a/out_hardPuzzle.html b/out_hardPuzzle.html index 5bfeaa9..abacbd3 100644 --- a/out_hardPuzzle.html +++ b/out_hardPuzzle.html @@ -1,185 +1,187 @@ + - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 118 - 119 - 120 - 121 - 122 - 123 - 124 - 125 - 126 - 127 - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - 148 - 149 - 150 - 151 - 152 - 153 - 154 - 155 - 156 - 157 - 158 - 159 - 160 - 161 - 162 - 163 - 164 - 165 - 166 - 167 - 168 - 169 - 170 - 171 - 172 - 173 - 174 - 175 - 176 - 177 - 178 - 179 - 180 - 181 - 182 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/out_smallPuzzle.html b/out_smallPuzzle.html index e58fb42..071f0c9 100644 --- a/out_smallPuzzle.html +++ b/out_smallPuzzle.html @@ -1,12 +1,14 @@ + - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 + + + + + + + + + + \ No newline at end of file diff --git a/printer.cpp b/printer.cpp index f685e11..601638f 100644 --- a/printer.cpp +++ b/printer.cpp @@ -43,22 +43,26 @@ void printSvg(const Point& point, std::ostream& out) { out << ""; } -void printSvg(const Block& block, std::ostream& out) { - out << ""; +void printSvg(const Block& block, const bool& displayId, std::ostream& out) { + out << ""; for (const Point& point : block.pointSet) { printSvg(point, out); } out << ""; } -void printSvg(const BoardState& boardState, std::ostream& out) { - printSvg({ boardState.runner.shift, boardState.runner.pointSet, "Runner" }, out); +void printSvg(const BoardState& boardState, const bool& displayId, std::ostream& out) { + printSvg({ boardState.runner.shift, boardState.runner.pointSet, "Runner" }, displayId, out); for (const Block& block : boardState.blocks) { - printSvg(block, out); + printSvg(block, displayId, out); } } -void printSvg(const Puzzle& puzzle, std::ostream& out) { +void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out) { out << "" << "" @@ -68,9 +72,9 @@ void printSvg(const Puzzle& puzzle, std::ostream& out) { forbiddenSpots.shift = {0, 0}; forbiddenSpots.pointSet = puzzle.forbiddenSpots; forbiddenSpots.id = "Wall"; - printSvg(forbiddenSpots, out); - printSvg(Block(puzzle.goal, puzzle.boardState.runner.pointSet, "Goal"), out); - printSvg(puzzle.boardState, out); + printSvg(forbiddenSpots, displayId, out); + printSvg(Block(puzzle.goal, puzzle.boardState.runner.pointSet, "Goal"), displayId, out); + printSvg(puzzle.boardState, displayId, out); out << ""; } @@ -79,26 +83,116 @@ void printSvg(const std::list& puzzleList, std::string preffix, std::str for (const Puzzle& puzzleStep : puzzleList) { const std::string pos(toString(++i)); out << std::regex_replace(preffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); - printSvg(puzzleStep, out); + printSvg(puzzleStep, false, out); out << std::regex_replace(suffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); } } -void printHtml(const std::list& puzzleList, std::ostream& out) { - const Puzzle& firstPuzzle = *(puzzleList.begin()); - out << "\n\n"; - printSvg( - puzzleList, - " {pos}", - "\n", + if (animated) { out - ); + << "" + << "" + ; + printSvg(firstPuzzle, true, out); + out << "\n"; + printSvgAnimate(puzzleList, out); + out << "\n"; + + } else { + printSvg( + puzzleList, + toString(" {pos}" + + "", + "\n", + out + ); + } out << ""; } diff --git a/printer.h b/printer.h index 66abc4a..12381a8 100644 --- a/printer.h +++ b/printer.h @@ -5,12 +5,28 @@ void printSvgStyle(const Puzzle& puzzle, std::ostream& out); void printSvg(const Point& point, std::ostream& out); -void printSvg(const Block& block, std::ostream& out); -void printSvg(const BoardState& boardState, std::ostream& out); -void printSvg(const Puzzle& puzzle, std::ostream& out); +void printSvg(const Block& block, const bool& displayId, std::ostream& out); +void printSvg(const BoardState& boardState, const bool& displayId, std::ostream& out); +void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out); void printSvg(const std::list& puzzleList, std::string preffix, std::string suffix, std::ostream& out); -void printHtml(const std::list& puzzleList, std::ostream& out); +void printSvgAnimate( + const std::string& id, + const std::string& from, + const std::string& to, + const std::string& step, + std::ostream& out +); +void printSvgAnimate(const Block& b1, const Block& b2, const size_t& step, std::ostream& out); +void printSvgAnimate(const Puzzle& puzzle1, const Puzzle& puzzle2, const size_t& step, std::ostream& out); +void printSvgAnimate(const std::list& puzzleList, std::ostream& out); + +void printHtml( + const std::list& puzzleList, + const bool& animated, + const size_t& scale, + std::ostream& out +); void printText(const Puzzle& puzzle, std::ostream& out); void printText(const std::list& puzzleList, std::ostream& out); diff --git a/test.cpp b/test.cpp index 4ed05fe..c538e98 100644 --- a/test.cpp +++ b/test.cpp @@ -13,6 +13,14 @@ namespace { auto compareString = [&](const std::string& s1, const std::string& s2) { if (s1 != s2) { std::cout << s1 << "\n!=\n" << s2 << "\n"; + std::cout << "(len1:" << s1.size() << ")\n(len2:" << s2.size() << ")\n"; + for (size_t i = 0; i < s1.size(); ++i) { + if (s1[i] != s2[i]) { + std::cout << "(first diff at position " << i << ") ('" << s1[i] << "' != '" << s2[i] << "')\n"; + //std::cout << "(first diff at position " << i << ") ('" << s1.substr(i - 10, 20) << "' != '" << s2.substr(i - 10, 20) << "')\n"; + break; + } + } } return s1 == s2; }; @@ -335,21 +343,46 @@ void testPrintScan() { { //print svg Block std::stringstream strResult; - printSvg(Block({ 1, 2 }, { { 0, 0 }, { 0, 1 }, { 1, 0 } }, "A"), strResult); + printSvg(Block({ 1, 2 }, { { 0, 0 }, { 0, 1 }, { 1, 0 } }, "A"), true, strResult); + strResult << "\n---\n"; + printSvg(Block({ 2, 3 }, { { 4, 5 }, { 6, 7 }, { 8, 9 } }, "A"), false, strResult); assert(compareString(strResult.str(), - "" + "" "" "" "" "" + "\n---\n" + "" + "" + "" + "" + "" )); } { //print svg BoardState std::stringstream strResult; - printSvg(tetrisPuzzle.boardState, strResult); + printSvg(tetrisPuzzle.boardState, true, strResult); + strResult << "\n---\n"; + printSvg(tetrisPuzzle.boardState, false, strResult); assert(compareString(strResult.str(), + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n---\n" "" "" "" @@ -370,8 +403,39 @@ void testPrintScan() { { //print svg Puzzle std::stringstream strResult; - printSvg(tetrisPuzzle, strResult); + printSvg(tetrisPuzzle, true, strResult); + strResult << "\n---\n"; + printSvg(tetrisPuzzle, false, strResult); assert(compareString(strResult.str(), + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n---\n" "" "" "" @@ -467,11 +531,144 @@ void testPrintScan() { )); } + { + //print svg animate tag + std::stringstream strResult; + printSvgAnimate("anId", "aFrom", "aTo", "aStep", strResult); + assert(compareString(strResult.str(), + "\n" + )); + } + { + //print svg animate Block + std::stringstream strResult; + printSvgAnimate( + tetrisPuzzle.boardState.runner, + tetrisPuzzle.boardState.runner, + 4, + strResult + ); + strResult << "\n---\n"; + printSvgAnimate( + { { 0, 1 }, tetrisPuzzle.boardState.runner.pointSet, "anId" }, + { { 2, 3 }, tetrisPuzzle.boardState.runner.pointSet, "anId" }, + 5, + strResult + ); + assert(compareString(strResult.str(), + "\n---\n" + "\n" + )); + } + { + //print svg animate Puzzle + std::stringstream strResult; + printSvgAnimate( + smallPuzzle, + smallPuzzle, + 6, + strResult + ); + strResult << "\n---\n"; + printSvgAnimate( + smallPuzzle, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, + 7, + strResult + ); + assert(compareString(strResult.str(), + "\n---\n" + "\n" + )); + } + { + //print svg animate Puzzle list + std::stringstream strResult; + printSvgAnimate( + { + smallPuzzle, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 1 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, + }, + strResult + ); + assert(compareString(strResult.str(), + "\n" + "\n" + )); + } + { //print html Puzzle list + const Puzzle tetrisPuzzle2 { + tetrisPuzzle.dimensions, + tetrisPuzzle.goal, + tetrisPuzzle.forbiddenSpots, + { + 1, + Block({ 0, 0 }, { { 0, 0 }, { 0, 2 }, { 1, 0 }, { 1, 1 }, { 1, 2 } }, "@"), // runner + { // blocks + Block({ 3, 1 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 0 }, { 1, 2 } }, "A") + } + } + }; + std::stringstream strResult; - printHtml(std::list{ tetrisPuzzle, tetrisPuzzle}, strResult); + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, false, 20, strResult); + strResult << "\n---\n"; + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, true, 100, strResult); assert(compareString(strResult.str(), + "\n" "\n" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n" + "\n" + "\n" + "\n" + "" )); } From 4214f54a4355d15604d2f069bd9defafb2258628 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Fri, 2 Oct 2020 21:38:49 +0200 Subject: [PATCH 04/10] unify references --- BoardHasher.h | 10 ++++------ MoveDiscovery.cpp | 4 ++-- MoveValidation.cpp | 6 +++--- MoveValidation.h | 4 ++-- printer.cpp | 2 +- puzzle.cpp | 2 +- puzzle.h | 4 ++-- solver.cpp | 6 +++--- solver.h | 2 +- 9 files changed, 19 insertions(+), 21 deletions(-) diff --git a/BoardHasher.h b/BoardHasher.h index b904a34..d5be40e 100644 --- a/BoardHasher.h +++ b/BoardHasher.h @@ -16,10 +16,10 @@ template class BoardHasher { public: - HashType hash(const BoardState &boardState) { + HashType hash(const BoardState& boardState) { HashType result{}; result ^= runnerHash(boardState.runner); - for (const auto &block : boardState.blocks) { + for (const auto& block : boardState.blocks) { result ^= blockSetHash(block); } return result; @@ -51,9 +51,7 @@ class BoardHasher { std::find_if( begin(blockPointSetSet), end(blockPointSetSet), - [&](const auto& b) { - return b == block.pointSet; - } + [&](const auto& b) { return b == block.pointSet; } ) ); @@ -61,7 +59,7 @@ class BoardHasher { return hashList[((blockPos + 1) * numberOfPuzzlePos) + (block.shift.x * dimensions.y) + block.shift.y]; } - int runnerHash(const Block &runner) { + int runnerHash(const Block& runner) { // First blockType is the runner : blockPos == 0 return hashList[(runner.shift.x * dimensions.y) + runner.shift.y]; } diff --git a/MoveDiscovery.cpp b/MoveDiscovery.cpp index a7f3da0..ea1c8d9 100644 --- a/MoveDiscovery.cpp +++ b/MoveDiscovery.cpp @@ -11,7 +11,7 @@ std::vector MoveRunnerFirst::gatherMoves( ) const { std::vector result{}; - auto moveBlockIfPossible = [&](const Block &block) { + auto moveBlockIfPossible = [&](const Block& block) { for (auto dir = 0; dir < static_cast(Direction::Number_of_dirs); ++dir) { if (validBlockPosition( block.move(static_cast(dir)), @@ -28,7 +28,7 @@ std::vector MoveRunnerFirst::gatherMoves( moveBlockIfPossible(boardState->runner); // Move other blocks second - for (const auto &block : boardState->blocks) { + for (const auto& block : boardState->blocks) { moveBlockIfPossible(block); } return result; diff --git a/MoveValidation.cpp b/MoveValidation.cpp index c8e6b5a..efa08a7 100644 --- a/MoveValidation.cpp +++ b/MoveValidation.cpp @@ -42,15 +42,15 @@ namespace detail { std::any_of( begin(board.blocks), end(board.blocks), - [&](const auto &other) { return (other.id != block.id) && block.overlaps(other); } + [&](const auto& other) { return (other.id != block.id) && block.overlaps(other); } ) ; } } bool validBlockPosition( - const Block &block, - const Point &dims, + const Block& block, + const Point& dims, const BoardState& boardState, const std::set invalidPositions ) { diff --git a/MoveValidation.h b/MoveValidation.h index 2cebe96..cffb167 100644 --- a/MoveValidation.h +++ b/MoveValidation.h @@ -4,8 +4,8 @@ // Checks if the proposed position of the block against the current state of the board is a valid one. bool validBlockPosition( - const Block &block, - const Point &dims, + const Block& block, + const Point& dims, const BoardState& boardState, const std::set invalidPositions ); diff --git a/printer.cpp b/printer.cpp index 601638f..c3f5c2e 100644 --- a/printer.cpp +++ b/printer.cpp @@ -236,7 +236,7 @@ void printText(const Puzzle& puzzle, std::ostream& out) { fillBlock(puzzle.boardState.runner); //fill other blocks - for (const auto &contentBlock : puzzle.boardState.blocks) { + for (const auto& contentBlock : puzzle.boardState.blocks) { fillBlock(contentBlock); } diff --git a/puzzle.cpp b/puzzle.cpp index eab5dc9..5487403 100644 --- a/puzzle.cpp +++ b/puzzle.cpp @@ -26,7 +26,7 @@ BoardState Move::proceed() { } } -Move::Move(std::shared_ptr boardState, const Block &block, Direction dir) +Move::Move(std::shared_ptr boardState, const Block& block, Direction dir) : boardState{ boardState } , block{ block } , directionToMove{ dir } diff --git a/puzzle.h b/puzzle.h index 202a014..4aa8570 100644 --- a/puzzle.h +++ b/puzzle.h @@ -24,7 +24,7 @@ class Move { std::shared_ptr boardState; // Block to be moved - const Block █ + const Block& block; // Direction in which to move block Direction directionToMove; @@ -32,7 +32,7 @@ class Move { // Returns the BoardState after the move BoardState proceed(); - Move(std::shared_ptr boardState, const Block &block, Direction dir); + Move(std::shared_ptr boardState, const Block& block, Direction dir); }; enum PuzzleValidation { diff --git a/solver.cpp b/solver.cpp index 6ad5e43..8db5384 100644 --- a/solver.cpp +++ b/solver.cpp @@ -7,7 +7,7 @@ bool isSolution(const BoardState& boardState, const Point& goal) { return (boardState.runner.shift.x == goal.x) && (boardState.runner.shift.y == goal.y); } -Solver::Solver(const Puzzle &puzzle, const MoveDiscovery& moveDiscovery) +Solver::Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery) : puzzle{ puzzle } , hasher{ puzzle } , moveDiscovery{ moveDiscovery } @@ -17,7 +17,7 @@ Solver::Solver(const Puzzle &puzzle, const MoveDiscovery& moveDiscovery) std::make_shared(puzzle.boardState), puzzle.forbiddenSpots ); - for (auto &move : initialMoves) { + for (auto& move : initialMoves) { possibleMoveStack.push_back(std::move(move)); } } @@ -112,7 +112,7 @@ std::list Solver::solveDebug(std::ostream* debugOut) { gatherMovesTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); - for (auto &move : newMoves) { + for (auto& move : newMoves) { possibleMoveStack.push_back(std::move(move)); } diff --git a/solver.h b/solver.h index 8186631..5b4784b 100644 --- a/solver.h +++ b/solver.h @@ -12,7 +12,7 @@ class Solver { using NumberOfMovesType = typename std::remove_const::type; public: - Solver(const Puzzle &puzzle, const MoveDiscovery& moveDiscovery); + Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery); ~Solver() = default; std::list solve(std::ostream* debugOut = nullptr); From 9721519e505d55fae39fc78d95493264c70a1524 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Sat, 3 Oct 2020 01:59:00 +0200 Subject: [PATCH 05/10] BoardState become shared_ptr in puzzle and solver --- BoardHasher.h | 2 +- MoveValidation.cpp | 27 ++++---- printer.cpp | 29 +++++---- puzzle.cpp | 39 ++++++----- puzzle.h | 12 ++-- solver.cpp | 50 +++++++------- solver.h | 4 +- test.cpp | 158 ++++++++++++++++++++++++++++++--------------- 8 files changed, 190 insertions(+), 131 deletions(-) diff --git a/BoardHasher.h b/BoardHasher.h index d5be40e..1d9f6c7 100644 --- a/BoardHasher.h +++ b/BoardHasher.h @@ -31,7 +31,7 @@ class BoardHasher { , hashList{} , blockPointSetSet{} { - for (const auto block : puzzle.boardState.blocks) { + for (const auto block : puzzle.boardState->blocks) { blockPointSetSet.insert(block.pointSet); } diff --git a/MoveValidation.cpp b/MoveValidation.cpp index efa08a7..44c9881 100644 --- a/MoveValidation.cpp +++ b/MoveValidation.cpp @@ -23,25 +23,26 @@ namespace detail { ) { return true; } - for (const auto& blockPoint : block.pointSet) { - if ( - ((block.shift.x + blockPoint.x) >= dims.x) - || - ((block.shift.y + blockPoint.y) >= dims.y) - ) { - return true; + return std::any_of( + begin(block.pointSet), + end(block.pointSet), + [&](const Point& blockPoint) { + return + ((block.shift.x + blockPoint.x) >= dims.x) + || + ((block.shift.y + blockPoint.y) >= dims.y) + ; } - } - return false; + ); } - bool overlapsWithOtherBlocks(const Block& block, const BoardState& board) { + bool overlapsWithOtherBlocks(const Block& block, const BoardState& boardState) { return - ((block.id != board.runner.id) && block.overlaps(board.runner)) + ((block.id != boardState.runner.id) && block.overlaps(boardState.runner)) || std::any_of( - begin(board.blocks), - end(board.blocks), + begin(boardState.blocks), + end(boardState.blocks), [&](const auto& other) { return (other.id != block.id) && block.overlaps(other); } ) ; diff --git a/printer.cpp b/printer.cpp index c3f5c2e..8bac19c 100644 --- a/printer.cpp +++ b/printer.cpp @@ -31,9 +31,10 @@ void printSvgStyle(const Puzzle& puzzle, std::ostream& out) { out << " .blockWall { fill : black; }"; out << " .blockGoal { fill : powderblue; }"; - int iColor = -1; - for (const Block& block : puzzle.boardState.blocks) { - out << " .block" << block.id << " { fill : " << colorMap[++iColor] << "; }"; + int iColor = 0; + for (const Block& block : puzzle.boardState->blocks) { + out << " .block" << block.id << " { fill : " << colorMap[iColor] << "; }"; + iColor = (iColor + 1) % colorMap.size(); } out << " .puzzle { fill : #202020; }"; @@ -73,8 +74,8 @@ void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out) { forbiddenSpots.pointSet = puzzle.forbiddenSpots; forbiddenSpots.id = "Wall"; printSvg(forbiddenSpots, displayId, out); - printSvg(Block(puzzle.goal, puzzle.boardState.runner.pointSet, "Goal"), displayId, out); - printSvg(puzzle.boardState, displayId, out); + printSvg(Block(puzzle.goal, puzzle.boardState->runner.pointSet, "Goal"), displayId, out); + printSvg(*(puzzle.boardState), displayId, out); out << ""; } @@ -138,13 +139,13 @@ void printSvgAnimate(const Block& b1, const Block& b2, const size_t& step, std:: void printSvgAnimate(const Puzzle& puzzle1, const Puzzle& puzzle2, const size_t& step, std::ostream& out) { printSvgAnimate( - { puzzle1.boardState.runner.shift, puzzle1.boardState.runner.pointSet, "Runner" }, - { puzzle2.boardState.runner.shift, puzzle2.boardState.runner.pointSet, "Runner" }, + { puzzle1.boardState->runner.shift, puzzle1.boardState->runner.pointSet, "Runner" }, + { puzzle2.boardState->runner.shift, puzzle2.boardState->runner.pointSet, "Runner" }, step, out ); - for (size_t i = 0; i < puzzle1.boardState.blocks.size() ; ++i) { - printSvgAnimate(puzzle1.boardState.blocks[i], puzzle2.boardState.blocks[i], step, out); + for (size_t i = 0; i < puzzle1.boardState->blocks.size() ; ++i) { + printSvgAnimate(puzzle1.boardState->blocks[i], puzzle2.boardState->blocks[i], step, out); } } @@ -230,13 +231,13 @@ void printText(const Puzzle& puzzle, std::ostream& out) { } }; - fillBlock({ puzzle.goal, puzzle.boardState.runner.pointSet, "^" }); + fillBlock({ puzzle.goal, puzzle.boardState->runner.pointSet, "^" }); //fill runner block - fillBlock(puzzle.boardState.runner); + fillBlock(puzzle.boardState->runner); //fill other blocks - for (const auto& contentBlock : puzzle.boardState.blocks) { + for (const auto& contentBlock : puzzle.boardState->blocks) { fillBlock(contentBlock); } @@ -309,11 +310,11 @@ Puzzle scanText(std::istream& in) { dimension, goal, forbiddenSpots, - { + std::make_shared(BoardState{ 0, Block({0, 0}, runnerPointSet, runnerId), blockList - } + }) }; } diff --git a/puzzle.cpp b/puzzle.cpp index 5487403..c6689e5 100644 --- a/puzzle.cpp +++ b/puzzle.cpp @@ -1,29 +1,28 @@ #include "puzzle.h" -BoardState Move::proceed() { +std::shared_ptr Move::proceed() const { if (block.id == boardState->runner.id) { // Block to move is the runner - return BoardState { + return std::make_shared(BoardState { boardState->numberOfMoves + 1, boardState->runner.move(directionToMove), boardState->blocks, - }; + }); - } else { - // Block to move is one of the other blocks - // Notes: assumes linear distance in storage container - const auto blockIndex = &block - &boardState->blocks[0]; + } - auto newBlocks = boardState->blocks; - newBlocks[blockIndex] = block.move(directionToMove); + // Block to move is one of the other blocks + // Notes: assumes linear distance in storage container + const auto blockIndex = &block - &boardState->blocks[0]; - return BoardState { - boardState->numberOfMoves + 1, - boardState->runner, - std::move(newBlocks), - }; + auto newBlocks = boardState->blocks; + newBlocks[blockIndex] = block.move(directionToMove); - } + return std::make_shared(BoardState { + boardState->numberOfMoves + 1, + boardState->runner, + std::move(newBlocks), + }); } Move::Move(std::shared_ptr boardState, const Block& block, Direction dir) @@ -34,24 +33,24 @@ Move::Move(std::shared_ptr boardState, const Block& block, Direction } PuzzleValidation Puzzle::validate() const { - const auto& blockSize = boardState.blocks.size(); + const auto& blockSize = boardState->blocks.size(); for (size_t i = 0; i < blockSize; ++i) { for (size_t j = 0; j < blockSize; ++j) { if (i < j) { - if (boardState.blocks[i].overlaps(boardState.blocks[j])) { + if (boardState->blocks[i].overlaps(boardState->blocks[j])) { return blocksOverlaps; } - if (boardState.blocks[i].id == boardState.blocks[j].id) { + if (boardState->blocks[i].id == boardState->blocks[j].id) { return blocksWithSameId; } } } - if (boardState.blocks[i].overlaps(this->boardState.runner)) { + if (boardState->blocks[i].overlaps(this->boardState->runner)) { return runnerOverlaps; } - if (boardState.runner.id == boardState.blocks[i].id) { + if (boardState->runner.id == boardState->blocks[i].id) { return runnerWithSameId; } } diff --git a/puzzle.h b/puzzle.h index 4aa8570..6b5ba5f 100644 --- a/puzzle.h +++ b/puzzle.h @@ -30,7 +30,7 @@ class Move { Direction directionToMove; // Returns the BoardState after the move - BoardState proceed(); + std::shared_ptr proceed() const; Move(std::shared_ptr boardState, const Block& block, Direction dir); }; @@ -56,7 +56,7 @@ class Puzzle { const std::set forbiddenSpots; // Initial position of all blocks on the board - const BoardState boardState; + std::shared_ptr boardState; PuzzleValidation validate() const; static std::string validationString(const PuzzleValidation& validation); @@ -64,15 +64,15 @@ class Puzzle { inline bool operator==(const Puzzle p1, const Puzzle p2) { return - (p1.dimensions == p2.dimensions) + (p1.boardState->runner == p2.boardState->runner) && - (p1.forbiddenSpots == p2.forbiddenSpots) + (p1.boardState->blocks == p2.boardState->blocks) && (p1.goal == p2.goal) && - (p1.boardState.runner == p2.boardState.runner) + (p1.forbiddenSpots == p2.forbiddenSpots) && - (p1.boardState.blocks == p2.boardState.blocks) + (p1.dimensions == p2.dimensions) ; } inline bool operator!=(const Puzzle p1, const Puzzle p2) { return !(p1 == p2); } diff --git a/solver.cpp b/solver.cpp index 8db5384..b85ddeb 100644 --- a/solver.cpp +++ b/solver.cpp @@ -14,7 +14,7 @@ Solver::Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery) { const auto initialMoves = moveDiscovery.gatherMoves( puzzle.dimensions, - std::make_shared(puzzle.boardState), + puzzle.boardState, puzzle.forbiddenSpots ); for (auto& move : initialMoves) { @@ -44,22 +44,22 @@ std::list Solver::solveDebug(std::ostream* debugOut) { // Note: invalidates firstMoveIt possibleMoveStack.pop_front(); - auto boardStateAfterMove = firstMove.proceed(); + std::shared_ptr boardStateAfterMove = firstMove.proceed(); auto end_time = std::chrono::high_resolution_clock::now(); pickMoveTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); - if (isSolution(boardStateAfterMove, puzzle.goal)) { + if (isSolution(*boardStateAfterMove, puzzle.goal)) { *debugOut << "Solution is:" << std::endl; printText(Puzzle{ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, boardStateAfterMove }, *debugOut); - *debugOut << "distance: " << boardStateAfterMove.numberOfMoves << std::endl; - const auto hash = hasher.hash(boardStateAfterMove); + *debugOut << "numberOfMoves: " << boardStateAfterMove->numberOfMoves << std::endl; + const auto hash = hasher.hash(*boardStateAfterMove); *debugOut << "Final hash: " << hash << std::endl; - auto result = solution(*firstMove.boardState, boardStateAfterMove); + auto result = solution(firstMove.boardState, boardStateAfterMove); - *debugOut << hasher.hash(puzzle.boardState) << std::endl; + *debugOut << hasher.hash(*(puzzle.boardState)) << std::endl; printText(puzzle, *debugOut); *debugOut << std::endl << "-------------- " << std::endl; @@ -83,28 +83,28 @@ std::list Solver::solveDebug(std::ostream* debugOut) { solutionCheckTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); - const auto hash = hasher.hash(boardStateAfterMove); + const auto boardStateAfterMoveHash = hasher.hash(*boardStateAfterMove); end_time = std::chrono::high_resolution_clock::now(); hashTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); - auto& distance = knownPaths[hash]; + auto& numberOfMoves = knownPaths[boardStateAfterMoveHash]; end_time = std::chrono::high_resolution_clock::now(); lookupTime += (end_time - start_time); - if (distance == 0) { - distance = boardStateAfterMove.numberOfMoves; + if (numberOfMoves == 0) { + numberOfMoves = boardStateAfterMove->numberOfMoves; - parentsOf[hasher.hash(boardStateAfterMove)].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); start_time = std::chrono::high_resolution_clock::now(); // Queue follow-up moves const auto newMoves = moveDiscovery.gatherMoves( puzzle.dimensions, - std::make_shared(std::move(boardStateAfterMove)), + std::move(boardStateAfterMove), puzzle.forbiddenSpots ); @@ -135,22 +135,24 @@ std::list Solver::solveFast() { // Note: invalidates firstMoveIt possibleMoveStack.pop_front(); - BoardState boardStateAfterMove = firstMove.proceed(); + std::shared_ptr boardStateAfterMove(firstMove.proceed()); - if (isSolution(boardStateAfterMove, puzzle.goal)) { - return solution(*firstMove.boardState, boardStateAfterMove); + if (isSolution(*boardStateAfterMove, puzzle.goal)) { + return solution(firstMove.boardState, boardStateAfterMove); } - auto& distance = knownPaths[hasher.hash(boardStateAfterMove)]; - if (distance == 0) { - distance = boardStateAfterMove.numberOfMoves; + const auto boardStateAfterMoveHash = hasher.hash(*boardStateAfterMove); + auto& numberOfMoves = knownPaths[boardStateAfterMoveHash]; + if (numberOfMoves == 0) { + //unknown paths to add + numberOfMoves = boardStateAfterMove->numberOfMoves; - parentsOf[hasher.hash(boardStateAfterMove)].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); // Queue follow-up moves const auto newMoves = moveDiscovery.gatherMoves( puzzle.dimensions, - std::make_shared(std::move(boardStateAfterMove)), + std::move(boardStateAfterMove), puzzle.forbiddenSpots ); @@ -163,12 +165,12 @@ std::list Solver::solveFast() { return {}; } -std::list Solver::solution(const BoardState& firstBoardState, const BoardState& lastBoardState) { +std::list Solver::solution(std::shared_ptr firstBoardState, std::shared_ptr lastBoardState) { std::list result; result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, lastBoardState }); - const auto initialHash = hasher.hash(puzzle.boardState); - HashType stopHash = hasher.hash(firstBoardState); + const auto initialHash = hasher.hash(*(puzzle.boardState)); + HashType stopHash = hasher.hash(*firstBoardState); while (stopHash != 0 && stopHash != initialHash) { auto start = parentsOf[stopHash]; if (start.size() > 0 && start[0].first != 0) { diff --git a/solver.h b/solver.h index 5b4784b..bb3e885 100644 --- a/solver.h +++ b/solver.h @@ -19,7 +19,7 @@ class Solver { private: std::list solveDebug(std::ostream* debugOut); std::list solveFast(); - std::list solution(const BoardState& firstBoardState, const BoardState& lastBoardState); + std::list solution(std::shared_ptr firstBoardState, std::shared_ptr lastBoardState); const Puzzle puzzle; BoardHasher hasher; @@ -31,7 +31,7 @@ class Solver { std::unordered_map knownPaths; // Testing rermove me - std::unordered_map>> parentsOf; + std::unordered_map>>> parentsOf; const MoveDiscovery& moveDiscovery; }; diff --git a/test.cpp b/test.cpp index c538e98..ed8ebad 100644 --- a/test.cpp +++ b/test.cpp @@ -34,7 +34,7 @@ namespace { { 0, 5 }, { 3, 5 }, }, - { // Initial board state + std::make_shared(BoardState{ 0, // no moves made, Block({ 1, 0 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "@"), // runner { // blocks @@ -48,7 +48,7 @@ namespace { Block({ 0, 4 }, { { 0, 0 } }, "H"), Block({ 3, 4 }, { { 0, 0 } }, "I") } - } + }) }; // Empty 3x3 block @@ -60,11 +60,11 @@ namespace { { { 1, 1 } // single hindrance in the middle }, // empty spaces - { + std::make_shared(BoardState{ 0, // no moves made, Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner at origin {} // no blocks - } + }) }; const Puzzle tinyPuzzle @@ -72,13 +72,13 @@ namespace { { 3, 3 }, // dims { 1, 1 }, // goal {}, // empty spaces - { + std::make_shared(BoardState{ 0, // no moves made, Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner { Block({1, 1 }, { { 0, 0 } }, "A") // Single block on the goal } - } + }) }; // Empty 3x3 block @@ -91,14 +91,14 @@ namespace { { { 1, 1 } }, // empty spaces - { + std::make_shared(BoardState{ 0, // no moves made, Block({ 0, 0 }, { { 0, 0 } }, "@"), // runner at origin { // 2 blocks surrounding origin Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 1 }, { { 0, 0 } }, "B") } - } + }) }; // Tetris klotski puzzle @@ -110,13 +110,13 @@ namespace { { 0, 5 }, { 4, 5 }, }, - { // Initial board state + std::make_shared(BoardState{ 0, // no moves made, Block({ 3, 2 }, { { 0, 0 }, { 0, 2 }, { 1, 0 }, { 1, 1 }, { 1, 2 } }, "@"), // runner { // blocks Block({ 2, 1 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 0 }, { 1, 2 } }, "A") } - } + }) }; } @@ -313,7 +313,47 @@ void testPrintScan() { { //print svg style std::stringstream strResult; - printSvgStyle(largePuzzle, strResult); + printSvgStyle( + { + { 20, 20 }, // dims + { 19, 19 }, // goal + { // invalid spaces + }, + std::make_shared(BoardState{ + 0, // no moves made, + Block({ 0, 0 }, { { 0, 0 }, }, "@"), // runner + { // blocks + Block({ 0, 0 }, { { 0, 0 }, }, "A"), + Block({ 0, 0 }, { { 0, 0 }, }, "B"), + Block({ 0, 0 }, { { 0, 0 }, }, "C"), + Block({ 0, 0 }, { { 0, 0 }, }, "D"), + Block({ 0, 0 }, { { 0, 0 }, }, "E"), + Block({ 0, 0 }, { { 0, 0 }, }, "F"), + Block({ 0, 0 }, { { 0, 0 }, }, "G"), + Block({ 0, 0 }, { { 0, 0 }, }, "H"), + Block({ 0, 0 }, { { 0, 0 }, }, "I"), + Block({ 0, 0 }, { { 0, 0 }, }, "J"), + Block({ 0, 0 }, { { 0, 0 }, }, "K"), + Block({ 0, 0 }, { { 0, 0 }, }, "L"), + Block({ 0, 0 }, { { 0, 0 }, }, "M"), + Block({ 0, 0 }, { { 0, 0 }, }, "N"), + Block({ 0, 0 }, { { 0, 0 }, }, "O"), + Block({ 0, 0 }, { { 0, 0 }, }, "P"), + Block({ 0, 0 }, { { 0, 0 }, }, "Q"), + Block({ 0, 0 }, { { 0, 0 }, }, "R"), + Block({ 0, 0 }, { { 0, 0 }, }, "S"), + Block({ 0, 0 }, { { 0, 0 }, }, "T"), + Block({ 0, 0 }, { { 0, 0 }, }, "U"), + Block({ 0, 0 }, { { 0, 0 }, }, "V"), + Block({ 0, 0 }, { { 0, 0 }, }, "W"), + Block({ 0, 0 }, { { 0, 0 }, }, "X"), + Block({ 0, 0 }, { { 0, 0 }, }, "Y"), + Block({ 0, 0 }, { { 0, 0 }, }, "Z"), + } + }) + }, + strResult + ); assert(compareString( strResult.str(), " .dimensions { stroke : red; stroke-width : 0.1; }" @@ -329,6 +369,23 @@ void testPrintScan() { " .blockG { fill : darkred; }" " .blockH { fill : darkmagenta; }" " .blockI { fill : darkorchid; }" + " .blockJ { fill : darkslategray; }" + " .blockK { fill : firebrick; }" + " .blockL { fill : green; }" + " .blockM { fill : indigo; }" + " .blockN { fill : seagreen; }" + " .blockO { fill : teal; }" + " .blockP { fill : yellowgreen; }" + " .blockQ { fill : yellow; }" + " .blockR { fill : pink; }" + " .blockS { fill : aqua; }" + " .blockT { fill : blueviolet; }" + " .blockU { fill : darkblue; }" + " .blockV { fill : darkcyan; }" + " .blockW { fill : darkgoldenrod; }" + " .blockX { fill : darkred; }" + " .blockY { fill : darkmagenta; }" + " .blockZ { fill : darkorchid; }" " .puzzle { fill : #202020; }" )); } @@ -364,9 +421,9 @@ void testPrintScan() { { //print svg BoardState std::stringstream strResult; - printSvg(tetrisPuzzle.boardState, true, strResult); + printSvg(*(tetrisPuzzle.boardState), true, strResult); strResult << "\n---\n"; - printSvg(tetrisPuzzle.boardState, false, strResult); + printSvg(*(tetrisPuzzle.boardState), false, strResult); assert(compareString(strResult.str(), "" "" @@ -553,15 +610,15 @@ void testPrintScan() { //print svg animate Block std::stringstream strResult; printSvgAnimate( - tetrisPuzzle.boardState.runner, - tetrisPuzzle.boardState.runner, + tetrisPuzzle.boardState->runner, + tetrisPuzzle.boardState->runner, 4, strResult ); strResult << "\n---\n"; printSvgAnimate( - { { 0, 1 }, tetrisPuzzle.boardState.runner.pointSet, "anId" }, - { { 2, 3 }, tetrisPuzzle.boardState.runner.pointSet, "anId" }, + { { 0, 1 }, tetrisPuzzle.boardState->runner.pointSet, "anId" }, + { { 2, 3 }, tetrisPuzzle.boardState->runner.pointSet, "anId" }, 5, strResult ); @@ -592,7 +649,7 @@ void testPrintScan() { strResult << "\n---\n"; printSvgAnimate( smallPuzzle, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, 7, strResult ); @@ -617,8 +674,8 @@ void testPrintScan() { printSvgAnimate( { smallPuzzle, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, { smallPuzzle.boardState.numberOfMoves, { { 0, 0 }, smallPuzzle.boardState.runner.pointSet, "anOtherId" }, { Block({ 1, 1 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } } }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 1 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, }, strResult ); @@ -654,13 +711,13 @@ void testPrintScan() { tetrisPuzzle.dimensions, tetrisPuzzle.goal, tetrisPuzzle.forbiddenSpots, - { + std::make_shared(BoardState{ 1, Block({ 0, 0 }, { { 0, 0 }, { 0, 2 }, { 1, 0 }, { 1, 1 }, { 1, 2 } }, "@"), // runner { // blocks Block({ 3, 1 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 0 }, { 1, 2 } }, "A") } - } + }) }; std::stringstream strResult; @@ -812,31 +869,31 @@ void testMoveValidation() { //MoveValidation moveValidation{}; // Test that all blocks do not overlap with their current state on the board - for (const auto &block : largePuzzle.boardState.blocks) { + for (const auto &block : largePuzzle.boardState->blocks) { assert( - validBlockPosition(block, largePuzzle.dimensions, largePuzzle.boardState, largePuzzle.forbiddenSpots) + validBlockPosition(block, largePuzzle.dimensions, *(largePuzzle.boardState), largePuzzle.forbiddenSpots) && "A block should never overlap itself" ); auto blockAtSamePosition = block; blockAtSamePosition.id = "Another Block"; assert( - !validBlockPosition(blockAtSamePosition, largePuzzle.dimensions, largePuzzle.boardState, largePuzzle.forbiddenSpots) + !validBlockPosition(blockAtSamePosition, largePuzzle.dimensions, *(largePuzzle.boardState), largePuzzle.forbiddenSpots) && "2 blocks at the same position should always overlap" ); } // Test all block pisition //printText(emptyPuzzle, std::cout); - assert(!validBlockPosition(Block({ 0, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 1, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 2, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 0, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert(!validBlockPosition(Block({ 1, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 2, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 0, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 1, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); - assert( validBlockPosition(Block({ 2, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, emptyPuzzle.boardState, emptyPuzzle.forbiddenSpots)); + assert(!validBlockPosition(Block({ 0, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 1, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 0 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 0, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert(!validBlockPosition(Block({ 1, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 1 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 0, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 1, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); + assert( validBlockPosition(Block({ 2, 2 }, { { 0, 0 } }, "someBlock"), emptyPuzzle.dimensions, *(emptyPuzzle.boardState), emptyPuzzle.forbiddenSpots)); } void testMoveDiscovery() { @@ -846,7 +903,7 @@ void testMoveDiscovery() { const int blockMoves = 4; // Up + Down + Right + Left const auto newMoves = moveDiscovery.gatherMoves( tinyPuzzle.dimensions, - std::make_shared(tinyPuzzle.boardState), + tinyPuzzle.boardState, tinyPuzzle.forbiddenSpots ); assert(!newMoves.empty() && "At least some moves should be possible"); @@ -857,7 +914,7 @@ void testMoveDiscovery() { const auto blockMoves = 4; auto newMoves = moveDiscovery.gatherMoves( largePuzzle.dimensions, - std::make_shared(largePuzzle.boardState), + largePuzzle.boardState, largePuzzle.forbiddenSpots ); assert(!newMoves.empty() && "At least some moves should be possible"); @@ -869,18 +926,17 @@ void testMoveDiscovery() { void testMoving() { using BoardType = std::remove_const::type; - auto sharedState = std::make_shared(largePuzzle.boardState); - Move moveRight{ sharedState, sharedState->blocks[0], Direction::Right }; - assert(sharedState.get() == moveRight.boardState.get() && "A move should not copy the state, but only reference the original state"); + Move moveRight{ largePuzzle.boardState, largePuzzle.boardState->blocks[0], Direction::Right }; + assert(largePuzzle.boardState.get() == moveRight.boardState.get() && "A move should not copy the state, but only reference the original state"); const auto afterMoveRight = moveRight.proceed(); - assert(sharedState->blocks[0].move(Direction::Right) == afterMoveRight.blocks[0]); - assert(sharedState->blocks[0].move(Direction::Left) != afterMoveRight.blocks[0]); - assert(sharedState->blocks[0].move(Direction::Up) != afterMoveRight.blocks[0]); - assert(sharedState->blocks[0].move(Direction::Down) != afterMoveRight.blocks[0]); - assert(sharedState->blocks[0].id == afterMoveRight.blocks[0].id); + assert(largePuzzle.boardState->blocks[0].move(Direction::Right) == afterMoveRight->blocks[0]); + assert(largePuzzle.boardState->blocks[0].move(Direction::Left) != afterMoveRight->blocks[0]); + assert(largePuzzle.boardState->blocks[0].move(Direction::Up) != afterMoveRight->blocks[0]); + assert(largePuzzle.boardState->blocks[0].move(Direction::Down) != afterMoveRight->blocks[0]); + assert(largePuzzle.boardState->blocks[0].id == afterMoveRight->blocks[0].id); - assert(sharedState->numberOfMoves + 1 == afterMoveRight.numberOfMoves); + assert(largePuzzle.boardState->numberOfMoves + 1 == afterMoveRight->numberOfMoves); { Block middle({ 2, 2 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"); @@ -900,20 +956,20 @@ void testHashing() { BoardHasher emptyHasher{ emptyPuzzle }; BoardHasher initialHasher{ largePuzzle }; - assert(emptyHasher.hash(emptyPuzzle.boardState) == emptyHasher.hash(emptyPuzzle.boardState) && "Hash for identical states should be equal"); - assert(initialHasher.hash(largePuzzle.boardState) == initialHasher.hash(largePuzzle.boardState) && "Hash for identical states should be equal"); - assert(initialHasher.hash(largePuzzle.boardState) != emptyHasher.hash(emptyPuzzle.boardState) && "Hash for different states should be different"); + assert(emptyHasher.hash(*(emptyPuzzle.boardState)) == emptyHasher.hash(*(emptyPuzzle.boardState)) && "Hash for identical states should be equal"); + assert(initialHasher.hash(*(largePuzzle.boardState)) == initialHasher.hash(*(largePuzzle.boardState)) && "Hash for identical states should be equal"); + assert(initialHasher.hash(*(largePuzzle.boardState)) != emptyHasher.hash(*(emptyPuzzle.boardState)) && "Hash for different states should be different"); - auto swappedBlocks = largePuzzle.boardState.blocks; + auto swappedBlocks = largePuzzle.boardState->blocks; auto temp= swappedBlocks[0]; swappedBlocks[0].id = swappedBlocks[1].id; swappedBlocks[1].id = temp.id; BoardState swappedState{ 0, - largePuzzle.boardState.runner, + largePuzzle.boardState->runner, swappedBlocks }; - assert(initialHasher.hash(swappedState) == initialHasher.hash(largePuzzle.boardState) && "Hash should be the same for 2 same-sized blocks in swapped positions"); + assert(initialHasher.hash(swappedState) == initialHasher.hash(*(largePuzzle.boardState)) && "Hash should be the same for 2 same-sized blocks in swapped positions"); } auto testSolverFx = [&](Solver solver, const bool& debug, std::string expectedOut = "") { From e0af6f490228ce50c8b9370cfee23e3d687169ea Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Tue, 16 Nov 2021 04:35:54 +0100 Subject: [PATCH 06/10] goal block with zebra style --- README.md | 2 +- main.cpp | 3 +- out_hardPuzzle.html | 3666 +++++++++++++++++++++++++++++++++++++++++- out_smallPuzzle.html | 86 +- printer.cpp | 58 +- printer.h | 4 +- test.cpp | 184 +-- 7 files changed, 3882 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index f1f7222..f23c58a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ text, svg, animated html output. # Build instructions ## Linux -rm -frv "/tmp/build"; +rm -frv "/tmp/build"; mkdir -pv "/tmp/build" && cmake -B "/tmp/build" -S . && make -j --directory="/tmp/build" && echo done ## Windows diff --git a/main.cpp b/main.cpp index 8529b8b..4919321 100644 --- a/main.cpp +++ b/main.cpp @@ -11,8 +11,7 @@ int main(int /*argc*/, char* /*argv*/[]) { return 1; } - printHtml(result, true, 100, std::cout); - //printHtml(result, false, 20, std::cout); + printHtml(result, 100, 20, std::cout); printText(result, std::cerr); return 0; } diff --git a/out_hardPuzzle.html b/out_hardPuzzle.html index abacbd3..d9263b7 100644 --- a/out_hardPuzzle.html +++ b/out_hardPuzzle.html @@ -1,7 +1,26 @@ - + - + + + + + + + + + + + + + + + + + + + + @@ -184,4 +203,3645 @@ - \ No newline at end of file +
+ 1 + + + + + + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + + 11 + + + + + + + + + + + + + + + + + + + + 12 + + + + + + + + + + + + + + + + + + + + 13 + + + + + + + + + + + + + + + + + + + + 14 + + + + + + + + + + + + + + + + + + + + 15 + + + + + + + + + + + + + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + 17 + + + + + + + + + + + + + + + + + + + + 18 + + + + + + + + + + + + + + + + + + + + 19 + + + + + + + + + + + + + + + + + + + + 20 + + + + + + + + + + + + + + + + + + + + 21 + + + + + + + + + + + + + + + + + + + + 22 + + + + + + + + + + + + + + + + + + + + 23 + + + + + + + + + + + + + + + + + + + + 24 + + + + + + + + + + + + + + + + + + + + 25 + + + + + + + + + + + + + + + + + + + + 26 + + + + + + + + + + + + + + + + + + + + 27 + + + + + + + + + + + + + + + + + + + + 28 + + + + + + + + + + + + + + + + + + + + 29 + + + + + + + + + + + + + + + + + + + + 30 + + + + + + + + + + + + + + + + + + + + 31 + + + + + + + + + + + + + + + + + + + + 32 + + + + + + + + + + + + + + + + + + + + 33 + + + + + + + + + + + + + + + + + + + + 34 + + + + + + + + + + + + + + + + + + + + 35 + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + 37 + + + + + + + + + + + + + + + + + + + + 38 + + + + + + + + + + + + + + + + + + + + 39 + + + + + + + + + + + + + + + + + + + + 40 + + + + + + + + + + + + + + + + + + + + 41 + + + + + + + + + + + + + + + + + + + + 42 + + + + + + + + + + + + + + + + + + + + 43 + + + + + + + + + + + + + + + + + + + + 44 + + + + + + + + + + + + + + + + + + + + 45 + + + + + + + + + + + + + + + + + + + + 46 + + + + + + + + + + + + + + + + + + + + 47 + + + + + + + + + + + + + + + + + + + + 48 + + + + + + + + + + + + + + + + + + + + 49 + + + + + + + + + + + + + + + + + + + + 50 + + + + + + + + + + + + + + + + + + + + 51 + + + + + + + + + + + + + + + + + + + + 52 + + + + + + + + + + + + + + + + + + + + 53 + + + + + + + + + + + + + + + + + + + + 54 + + + + + + + + + + + + + + + + + + + + 55 + + + + + + + + + + + + + + + + + + + + 56 + + + + + + + + + + + + + + + + + + + + 57 + + + + + + + + + + + + + + + + + + + + 58 + + + + + + + + + + + + + + + + + + + + 59 + + + + + + + + + + + + + + + + + + + + 60 + + + + + + + + + + + + + + + + + + + + 61 + + + + + + + + + + + + + + + + + + + + 62 + + + + + + + + + + + + + + + + + + + + 63 + + + + + + + + + + + + + + + + + + + + 64 + + + + + + + + + + + + + + + + + + + + 65 + + + + + + + + + + + + + + + + + + + + 66 + + + + + + + + + + + + + + + + + + + + 67 + + + + + + + + + + + + + + + + + + + + 68 + + + + + + + + + + + + + + + + + + + + 69 + + + + + + + + + + + + + + + + + + + + 70 + + + + + + + + + + + + + + + + + + + + 71 + + + + + + + + + + + + + + + + + + + + 72 + + + + + + + + + + + + + + + + + + + + 73 + + + + + + + + + + + + + + + + + + + + 74 + + + + + + + + + + + + + + + + + + + + 75 + + + + + + + + + + + + + + + + + + + + 76 + + + + + + + + + + + + + + + + + + + + 77 + + + + + + + + + + + + + + + + + + + + 78 + + + + + + + + + + + + + + + + + + + + 79 + + + + + + + + + + + + + + + + + + + + 80 + + + + + + + + + + + + + + + + + + + + 81 + + + + + + + + + + + + + + + + + + + + 82 + + + + + + + + + + + + + + + + + + + + 83 + + + + + + + + + + + + + + + + + + + + 84 + + + + + + + + + + + + + + + + + + + + 85 + + + + + + + + + + + + + + + + + + + + 86 + + + + + + + + + + + + + + + + + + + + 87 + + + + + + + + + + + + + + + + + + + + 88 + + + + + + + + + + + + + + + + + + + + 89 + + + + + + + + + + + + + + + + + + + + 90 + + + + + + + + + + + + + + + + + + + + 91 + + + + + + + + + + + + + + + + + + + + 92 + + + + + + + + + + + + + + + + + + + + 93 + + + + + + + + + + + + + + + + + + + + 94 + + + + + + + + + + + + + + + + + + + + 95 + + + + + + + + + + + + + + + + + + + + 96 + + + + + + + + + + + + + + + + + + + + 97 + + + + + + + + + + + + + + + + + + + + 98 + + + + + + + + + + + + + + + + + + + + 99 + + + + + + + + + + + + + + + + + + + + 100 + + + + + + + + + + + + + + + + + + + + 101 + + + + + + + + + + + + + + + + + + + + 102 + + + + + + + + + + + + + + + + + + + + 103 + + + + + + + + + + + + + + + + + + + + 104 + + + + + + + + + + + + + + + + + + + + 105 + + + + + + + + + + + + + + + + + + + + 106 + + + + + + + + + + + + + + + + + + + + 107 + + + + + + + + + + + + + + + + + + + + 108 + + + + + + + + + + + + + + + + + + + + 109 + + + + + + + + + + + + + + + + + + + + 110 + + + + + + + + + + + + + + + + + + + + 111 + + + + + + + + + + + + + + + + + + + + 112 + + + + + + + + + + + + + + + + + + + + 113 + + + + + + + + + + + + + + + + + + + + 114 + + + + + + + + + + + + + + + + + + + + 115 + + + + + + + + + + + + + + + + + + + + 116 + + + + + + + + + + + + + + + + + + + + 117 + + + + + + + + + + + + + + + + + + + + 118 + + + + + + + + + + + + + + + + + + + + 119 + + + + + + + + + + + + + + + + + + + + 120 + + + + + + + + + + + + + + + + + + + + 121 + + + + + + + + + + + + + + + + + + + + 122 + + + + + + + + + + + + + + + + + + + + 123 + + + + + + + + + + + + + + + + + + + + 124 + + + + + + + + + + + + + + + + + + + + 125 + + + + + + + + + + + + + + + + + + + + 126 + + + + + + + + + + + + + + + + + + + + 127 + + + + + + + + + + + + + + + + + + + + 128 + + + + + + + + + + + + + + + + + + + + 129 + + + + + + + + + + + + + + + + + + + + 130 + + + + + + + + + + + + + + + + + + + + 131 + + + + + + + + + + + + + + + + + + + + 132 + + + + + + + + + + + + + + + + + + + + 133 + + + + + + + + + + + + + + + + + + + + 134 + + + + + + + + + + + + + + + + + + + + 135 + + + + + + + + + + + + + + + + + + + + 136 + + + + + + + + + + + + + + + + + + + + 137 + + + + + + + + + + + + + + + + + + + + 138 + + + + + + + + + + + + + + + + + + + + 139 + + + + + + + + + + + + + + + + + + + + 140 + + + + + + + + + + + + + + + + + + + + 141 + + + + + + + + + + + + + + + + + + + + 142 + + + + + + + + + + + + + + + + + + + + 143 + + + + + + + + + + + + + + + + + + + + 144 + + + + + + + + + + + + + + + + + + + + 145 + + + + + + + + + + + + + + + + + + + + 146 + + + + + + + + + + + + + + + + + + + + 147 + + + + + + + + + + + + + + + + + + + + 148 + + + + + + + + + + + + + + + + + + + + 149 + + + + + + + + + + + + + + + + + + + + 150 + + + + + + + + + + + + + + + + + + + + 151 + + + + + + + + + + + + + + + + + + + + 152 + + + + + + + + + + + + + + + + + + + + 153 + + + + + + + + + + + + + + + + + + + + 154 + + + + + + + + + + + + + + + + + + + + 155 + + + + + + + + + + + + + + + + + + + + 156 + + + + + + + + + + + + + + + + + + + + 157 + + + + + + + + + + + + + + + + + + + + 158 + + + + + + + + + + + + + + + + + + + + 159 + + + + + + + + + + + + + + + + + + + + 160 + + + + + + + + + + + + + + + + + + + + 161 + + + + + + + + + + + + + + + + + + + + 162 + + + + + + + + + + + + + + + + + + + + 163 + + + + + + + + + + + + + + + + + + + + 164 + + + + + + + + + + + + + + + + + + + + 165 + + + + + + + + + + + + + + + + + + + + 166 + + + + + + + + + + + + + + + + + + + + 167 + + + + + + + + + + + + + + + + + + + + 168 + + + + + + + + + + + + + + + + + + + + 169 + + + + + + + + + + + + + + + + + + + + 170 + + + + + + + + + + + + + + + + + + + + 171 + + + + + + + + + + + + + + + + + + + + 172 + + + + + + + + + + + + + + + + + + + + 173 + + + + + + + + + + + + + + + + + + + + 174 + + + + + + + + + + + + + + + + + + + + 175 + + + + + + + + + + + + + + + + + + + + 176 + + + + + + + + + + + + + + + + + + + + 177 + + + + + + + + + + + + + + + + + + + + 178 + + + + + + + + + + + + + + + + + + + + 179 + + + + + + + + + + + + + + + + + + + + 180 + + + + + + + + + + + + + + + + + + + + 181 + + + + + + + + + + + + + + + + + + + + 182 + + + + + + + + + + + + + + + + + + + + diff --git a/out_smallPuzzle.html b/out_smallPuzzle.html index 071f0c9..acda089 100644 --- a/out_smallPuzzle.html +++ b/out_smallPuzzle.html @@ -1,7 +1,14 @@ - + - + + + + + + + + @@ -11,4 +18,77 @@ - \ No newline at end of file +
+ 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + 5 + + + + + + + + 6 + + + + + + + + 7 + + + + + + + + 8 + + + + + + + + 9 + + + + + + + + diff --git a/printer.cpp b/printer.cpp index 8bac19c..9431865 100644 --- a/printer.cpp +++ b/printer.cpp @@ -26,10 +26,13 @@ std::map colorMap{ }; void printSvgStyle(const Puzzle& puzzle, std::ostream& out) { - out << " .dimensions { stroke : red; stroke-width : 0.1; }"; - out << " .blockRunner { fill : red; }"; - out << " .blockWall { fill : black; }"; - out << " .blockGoal { fill : powderblue; }"; + out << + " .dimensions { stroke : red; stroke-width : 0.01; }" + " .block { fill-opacity : 0.93 }" + " .blockRunner { fill : red; }" + " .blockWall { fill : black; }" + " .blockGoal { fill : url(#zebra-gradient) powderblue; }" + ; int iColor = 0; for (const Block& block : puzzle.boardState->blocks) { @@ -45,7 +48,7 @@ void printSvg(const Point& point, std::ostream& out) { } void printSvg(const Block& block, const bool& displayId, std::ostream& out) { - out << ""; + out << "
\n"; } void printSvg(const BoardState& boardState, const bool& displayId, std::ostream& out) { @@ -66,7 +69,7 @@ void printSvg(const BoardState& boardState, const bool& displayId, std::ostream& void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out) { out << "" - << "" + << "\n" ; Block forbiddenSpots; @@ -160,7 +163,7 @@ void printSvgAnimate(const std::list& puzzleList, std::ostream& out) { } } -void printHtml(const std::list& puzzleList, const bool& animated, const size_t& scale, std::ostream& out) { +void printHtml(const std::list& puzzleList, const size_t& animatedScale, const size_t& staticScale, std::ostream& out) { Puzzle firstPuzzle = *(puzzleList.begin()); out << "\n" @@ -169,32 +172,47 @@ void printHtml(const std::list& puzzleList, const bool& animated, const printSvgStyle(firstPuzzle, out); out << " body { color : grey; background : black; }"; out << "\n\n"; - if (animated) { + if (animatedScale > 0) { out << "" - << "" + << " width='" << ((firstPuzzle.dimensions.x + 1) * animatedScale) << "'" + << " height='" << ((firstPuzzle.dimensions.y + 1) * animatedScale) << "'" + << " xmlns:xlink='http://www.w3.org/1999/xlink'" + << ">\n" + << "" + ; + for (int i = 0; i < 100; i += 20) { + out + << "" + << "" + ; + } + out + << "\n" + << "" ; printSvg(firstPuzzle, true, out); out << "\n"; printSvgAnimate(puzzleList, out); out << "\n"; - } else { + } + if (staticScale > 0) { + if (animatedScale > 0) { + out << "
\n"; + } printSvg( puzzleList, toString(" {pos}" - + "", - "\n", + + " width='" + toString((firstPuzzle.dimensions.x + 1) * staticScale) + "'" + + " height='" + toString((firstPuzzle.dimensions.y + 1) * staticScale) + "'" + + ">\n" + + "", + "\n\n", out ); } - out << ""; + out << "\n"; } void printText(const Puzzle& puzzle, std::ostream& out) { diff --git a/printer.h b/printer.h index 12381a8..505720e 100644 --- a/printer.h +++ b/printer.h @@ -23,8 +23,8 @@ void printSvgAnimate(const std::list& puzzleList, std::ostream& out); void printHtml( const std::list& puzzleList, - const bool& animated, - const size_t& scale, + const size_t& animatedScale, + const size_t& staticScale, std::ostream& out ); diff --git a/test.cpp b/test.cpp index ed8ebad..b44fefc 100644 --- a/test.cpp +++ b/test.cpp @@ -356,10 +356,11 @@ void testPrintScan() { ); assert(compareString( strResult.str(), - " .dimensions { stroke : red; stroke-width : 0.1; }" + " .dimensions { stroke : red; stroke-width : 0.01; }" + " .block { fill-opacity : 0.93 }" " .blockRunner { fill : red; }" " .blockWall { fill : black; }" - " .blockGoal { fill : powderblue; }" + " .blockGoal { fill : url(#zebra-gradient) powderblue; }" " .blockA { fill : pink; }" " .blockB { fill : aqua; }" " .blockC { fill : blueviolet; }" @@ -404,17 +405,17 @@ void testPrintScan() { strResult << "\n---\n"; printSvg(Block({ 2, 3 }, { { 4, 5 }, { 6, 7 }, { 8, 9 } }, "A"), false, strResult); assert(compareString(strResult.str(), - "" + "\t" "" "" "" - "" + "\n" "\n---\n" - "" + "\t" "" "" "" - "" + "\n" )); } @@ -425,35 +426,35 @@ void testPrintScan() { strResult << "\n---\n"; printSvg(*(tetrisPuzzle.boardState), false, strResult); assert(compareString(strResult.str(), - "" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "\n---\n" - "" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" )); } @@ -465,61 +466,61 @@ void testPrintScan() { printSvg(tetrisPuzzle, false, strResult); assert(compareString(strResult.str(), "" - "" - "" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "" "\n---\n" "" - "" - "" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "" )); } @@ -530,60 +531,60 @@ void testPrintScan() { printSvg(std::list{ tetrisPuzzle, tetrisPuzzle}, "av", "ap", strResult); assert(compareString(strResult.str(), "av" - "" - "" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "apav" "" - "" - "" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "ap" )); } @@ -721,118 +722,121 @@ void testPrintScan() { }; std::stringstream strResult; - printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, false, 20, strResult); + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, 0, 20, strResult); strResult << "\n---\n"; - printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, true, 100, strResult); + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, 100, 0, strResult); assert(compareString(strResult.str(), "\n" "\n" "\n" - " 1" - "" - "" + " 1\n" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "\n" - " 2" + "\n" + "\n\n" + " 2\n" "" - "" - "" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "\n" - "" + "
\n" + "
\n\n" + "\n" "\n---\n" "\n" "\n" "\n" - "" - "" - "" + "\n" + "\n" + "\n" + "\t" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" - "" + "\n" + "\t" "" "" "" "" "" - "" + "\n" "\n" "\n" "\n" - "" + "\n" )); } From b2d93d37696d732e63469428f27c425f7c9d97b7 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Mon, 22 Nov 2021 01:54:21 +0100 Subject: [PATCH 07/10] add benchmark option in main.cpp --- BoardHasher.h | 9 ++--- MoveDiscovery.cpp | 4 +-- MoveDiscovery.h | 1 - MoveValidation.cpp | 84 ++++++++++++++++++++++------------------------ README.md | 4 +++ block.h | 3 +- main.cpp | 7 ++-- puzzle.h | 2 -- solver.cpp | 56 ++++++++++++++++--------------- solver.h | 7 ++-- test.cpp | 4 +-- 11 files changed, 88 insertions(+), 93 deletions(-) diff --git a/BoardHasher.h b/BoardHasher.h index 1d9f6c7..7bb968d 100644 --- a/BoardHasher.h +++ b/BoardHasher.h @@ -1,17 +1,14 @@ #pragma once #include "puzzle.h" -#include #include -#include #include // std::find // Need a hash that's both order invariant & block-id invariant // i.e. 2 blocks with different ids at the same position should still hash the same // i.e. hash should be the same regardless of the order in which the blocks on the board are hashed -// As we only update 1 block at a time, this would be perfect to update incrementally -// But i'll add this to the TODO list :-) ... +// TODO : As we only update 1 block at a time, this would be perfect to update incrementally template class BoardHasher { @@ -20,7 +17,7 @@ class BoardHasher { HashType result{}; result ^= runnerHash(boardState.runner); for (const auto& block : boardState.blocks) { - result ^= blockSetHash(block); + result ^= blockHash(block); } return result; }; @@ -45,7 +42,7 @@ class BoardHasher { } private: - int blockSetHash(const Block& block) { + int blockHash(const Block& block) { const auto blockPos = std::distance( begin(blockPointSetSet), std::find_if( diff --git a/MoveDiscovery.cpp b/MoveDiscovery.cpp index ea1c8d9..70f8b69 100644 --- a/MoveDiscovery.cpp +++ b/MoveDiscovery.cpp @@ -1,8 +1,6 @@ #include "MoveDiscovery.h" -#include "block.h" - -#include +#include "MoveValidation.h" std::vector MoveRunnerFirst::gatherMoves( const Point dimensions, diff --git a/MoveDiscovery.h b/MoveDiscovery.h index 36b0bb3..3d7d64a 100644 --- a/MoveDiscovery.h +++ b/MoveDiscovery.h @@ -1,6 +1,5 @@ #pragma once -#include "MoveValidation.h" #include "puzzle.h" #include diff --git a/MoveValidation.cpp b/MoveValidation.cpp index 44c9881..72631f7 100644 --- a/MoveValidation.cpp +++ b/MoveValidation.cpp @@ -1,52 +1,48 @@ #include "MoveValidation.h" -#include #include -namespace detail { +bool overlapsWithInvalidSpaces(const Block& block, const std::set& invalidSpotSet) { + return std::any_of( + begin(invalidSpotSet), + end(invalidSpotSet), + [&](const Point& invalidSpot) { + return block.overlaps(invalidSpot); + } + ); +} - bool overlapsWithInvalidSpaces(const Block& block, const std::set& invalidSpotSet) { - return std::any_of( - begin(invalidSpotSet), - end(invalidSpotSet), - [&](const Point& invalidSpot) { - return block.overlaps(invalidSpot); - } - ); +bool overlapsWithBorder(const Block& block, const Point& dims) { + if ( + (block.shift.x < 0) + || + (block.shift.y < 0) + ) { + return true; } - - bool overlapsWithBorder(const Block& block, const Point& dims) { - if ( - (block.shift.x < 0) - || - (block.shift.y < 0) - ) { - return true; + return std::any_of( + begin(block.pointSet), + end(block.pointSet), + [&](const Point& blockPoint) { + return + ((block.shift.x + blockPoint.x) >= dims.x) + || + ((block.shift.y + blockPoint.y) >= dims.y) + ; } - return std::any_of( - begin(block.pointSet), - end(block.pointSet), - [&](const Point& blockPoint) { - return - ((block.shift.x + blockPoint.x) >= dims.x) - || - ((block.shift.y + blockPoint.y) >= dims.y) - ; - } - ); - } + ); +} - bool overlapsWithOtherBlocks(const Block& block, const BoardState& boardState) { - return - ((block.id != boardState.runner.id) && block.overlaps(boardState.runner)) - || - std::any_of( - begin(boardState.blocks), - end(boardState.blocks), - [&](const auto& other) { return (other.id != block.id) && block.overlaps(other); } - ) - ; - } +bool overlapsWithOtherBlocks(const Block& block, const BoardState& boardState) { + return + ((block.id != boardState.runner.id) && block.overlaps(boardState.runner)) + || + std::any_of( + begin(boardState.blocks), + end(boardState.blocks), + [&](const auto& other) { return (other.id != block.id) && block.overlaps(other); } + ) + ; } bool validBlockPosition( @@ -55,9 +51,9 @@ bool validBlockPosition( const BoardState& boardState, const std::set invalidPositions ) { - return !detail::overlapsWithBorder(block, dims) - && !detail::overlapsWithInvalidSpaces(block, invalidPositions) - && !detail::overlapsWithOtherBlocks(block, boardState) + return !overlapsWithBorder(block, dims) + && !overlapsWithInvalidSpaces(block, invalidPositions) + && !overlapsWithOtherBlocks(block, boardState) ; } diff --git a/README.md b/README.md index f23c58a..75daca1 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ time "/tmp/build/solve" < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hard ### Windows `solve.exe` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +## Benchmark +### Linux +"/tmp/build/solve" benchmark < "in_hardPuzzle.txt" 1> /dev/null + # Notes `solve` is using : - standard input as puzzle to solve diff --git a/block.h b/block.h index fe355e3..7c95e44 100644 --- a/block.h +++ b/block.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -46,8 +45,8 @@ class Block { const std::string& anId ); - bool overlaps(const Block& other) const; bool overlaps(const Point& otherPoint) const; + bool overlaps(const Block& other) const; Block move(const Direction& dir) const; }; diff --git a/main.cpp b/main.cpp index 4919321..7227fd6 100644 --- a/main.cpp +++ b/main.cpp @@ -4,15 +4,16 @@ #include -int main(int /*argc*/, char* /*argv*/[]) { - const auto result = Solver(scanText(std::cin), MoveRunnerFirst()).solve(); +int main(int argc, char* /*argv*/[]) { + const bool benchmark = (1 < argc); + const auto result = Solver(scanText(std::cin), MoveRunnerFirst()).solve(benchmark ? &std::cerr : nullptr); if (result.size() == 0) { std::cerr << "Could not find a solution." << std::endl; return 1; } printHtml(result, 100, 20, std::cout); - printText(result, std::cerr); + if (!benchmark) { printText(result, std::cerr); } return 0; } diff --git a/puzzle.h b/puzzle.h index 6b5ba5f..33423fe 100644 --- a/puzzle.h +++ b/puzzle.h @@ -3,9 +3,7 @@ #include "block.h" #include -#include #include -#include struct BoardState { // Numer of moves made since the start position diff --git a/solver.cpp b/solver.cpp index b85ddeb..fff967f 100644 --- a/solver.cpp +++ b/solver.cpp @@ -22,12 +22,12 @@ Solver::Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery) } } -std::list Solver::solve(std::ostream* debugOut) { - return (nullptr == debugOut) ? solveFast() : solveDebug(debugOut); +std::list Solver::solve(std::ostream* benchmarkOut) { + return (nullptr == benchmarkOut) ? solveFast() : solveBenchmark(benchmarkOut); } -std::list Solver::solveDebug(std::ostream* debugOut) { - printText(puzzle, *debugOut); +std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { + printText(puzzle, *benchmarkOut); auto globalTime = std::chrono::high_resolution_clock::now(); auto pickMoveTime = std::chrono::high_resolution_clock::duration{}; @@ -40,34 +40,33 @@ std::list Solver::solveDebug(std::ostream* debugOut) { while (!possibleMoveStack.empty()) { auto start_time = std::chrono::high_resolution_clock::now(); - Move firstMove = *(begin(possibleMoveStack)); - // Note: invalidates firstMoveIt + Move currentMove = *(begin(possibleMoveStack)); possibleMoveStack.pop_front(); - std::shared_ptr boardStateAfterMove = firstMove.proceed(); + std::shared_ptr boardStateAfterMove = currentMove.proceed(); auto end_time = std::chrono::high_resolution_clock::now(); pickMoveTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); if (isSolution(*boardStateAfterMove, puzzle.goal)) { - *debugOut << "Solution is:" << std::endl; - printText(Puzzle{ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, boardStateAfterMove }, *debugOut); - *debugOut << "numberOfMoves: " << boardStateAfterMove->numberOfMoves << std::endl; + *benchmarkOut << "Solution is:" << std::endl; + printText(Puzzle{ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, boardStateAfterMove }, *benchmarkOut); + *benchmarkOut << "numberOfMoves: " << boardStateAfterMove->numberOfMoves << std::endl; const auto hash = hasher.hash(*boardStateAfterMove); - *debugOut << "Final hash: " << hash << std::endl; + *benchmarkOut << "Final hash: " << hash << std::endl; - auto result = solution(firstMove.boardState, boardStateAfterMove); + auto result = solution(currentMove.boardState, boardStateAfterMove); - *debugOut << hasher.hash(*(puzzle.boardState)) << std::endl; - printText(puzzle, *debugOut); - *debugOut << std::endl << "-------------- " << std::endl; + *benchmarkOut << hasher.hash(*(puzzle.boardState)) << std::endl; + printText(puzzle, *benchmarkOut); + *benchmarkOut << std::endl << "-------------- " << std::endl; const auto now = std::chrono::high_resolution_clock::now(); const auto totalTime = std::chrono::duration_cast(now - globalTime).count(); - *debugOut << "Total time was: " << totalTime << std::endl; + *benchmarkOut << "Total time was: " << totalTime << std::endl; if (0 < totalTime) { - *debugOut + *benchmarkOut << "pickMoveTime: " << (100 * std::chrono::duration_cast(pickMoveTime).count() / totalTime) << "%" << std::endl << "solutionCheckTime: " << (100 * std::chrono::duration_cast(solutionCheckTime).count() / totalTime) << "%" << std::endl << "hashTime: " << (100 * std::chrono::duration_cast(hashTime).count() / totalTime) << "%" << std::endl @@ -97,7 +96,7 @@ std::list Solver::solveDebug(std::ostream* debugOut) { if (numberOfMoves == 0) { numberOfMoves = boardStateAfterMove->numberOfMoves; - parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*currentMove.boardState), boardStateAfterMove }); start_time = std::chrono::high_resolution_clock::now(); @@ -131,14 +130,13 @@ std::list Solver::solveFast() { // a few already-known moves will be queued twice while (!possibleMoveStack.empty()) { //peek a move - Move firstMove = *(begin(possibleMoveStack)); - // Note: invalidates firstMoveIt + Move currentMove = *(begin(possibleMoveStack)); possibleMoveStack.pop_front(); - std::shared_ptr boardStateAfterMove(firstMove.proceed()); + std::shared_ptr boardStateAfterMove(currentMove.proceed()); if (isSolution(*boardStateAfterMove, puzzle.goal)) { - return solution(firstMove.boardState, boardStateAfterMove); + return solution(currentMove.boardState, boardStateAfterMove); } const auto boardStateAfterMoveHash = hasher.hash(*boardStateAfterMove); @@ -147,28 +145,30 @@ std::list Solver::solveFast() { //unknown paths to add numberOfMoves = boardStateAfterMove->numberOfMoves; - parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*firstMove.boardState), boardStateAfterMove }); + parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*currentMove.boardState), boardStateAfterMove }); // Queue follow-up moves - const auto newMoves = moveDiscovery.gatherMoves( + for (auto& move : moveDiscovery.gatherMoves( puzzle.dimensions, std::move(boardStateAfterMove), puzzle.forbiddenSpots - ); - - for (auto& move : newMoves) { + )) { possibleMoveStack.push_back(std::move(move)); } } } + //no result found return {}; } std::list Solver::solution(std::shared_ptr firstBoardState, std::shared_ptr lastBoardState) { std::list result; + + //add solved board (at front) result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, lastBoardState }); + //add each board step (at front) const auto initialHash = hasher.hash(*(puzzle.boardState)); HashType stopHash = hasher.hash(*firstBoardState); while (stopHash != 0 && stopHash != initialHash) { @@ -178,6 +178,8 @@ std::list Solver::solution(std::shared_ptr firstBoardState, stopHash = start[0].first; } } + + //add initial board (at front) result.push_front(puzzle); return result; } diff --git a/solver.h b/solver.h index bb3e885..eb6d7f0 100644 --- a/solver.h +++ b/solver.h @@ -14,11 +14,13 @@ class Solver { public: Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery); ~Solver() = default; - std::list solve(std::ostream* debugOut = nullptr); + std::list solve(std::ostream* benchmarkOut = nullptr); private: - std::list solveDebug(std::ostream* debugOut); + std::list solveBenchmark(std::ostream* benchmarkOut); std::list solveFast(); + + //format solution using solver data std::list solution(std::shared_ptr firstBoardState, std::shared_ptr lastBoardState); const Puzzle puzzle; @@ -30,7 +32,6 @@ class Solver { // Stores the number of moves from the starting state std::unordered_map knownPaths; - // Testing rermove me std::unordered_map>>> parentsOf; const MoveDiscovery& moveDiscovery; diff --git a/test.cpp b/test.cpp index b44fefc..72f8276 100644 --- a/test.cpp +++ b/test.cpp @@ -976,10 +976,10 @@ void testHashing() { assert(initialHasher.hash(swappedState) == initialHasher.hash(*(largePuzzle.boardState)) && "Hash should be the same for 2 same-sized blocks in swapped positions"); } -auto testSolverFx = [&](Solver solver, const bool& debug, std::string expectedOut = "") { +auto testSolverFx = [&](Solver solver, const bool& benchmark, std::string expectedOut = "") { std::stringstream out; std::list result; - if (debug) { + if (benchmark) { result = solver.solve(&out); } else { result = solver.solve(); From e5f5488df240a79f5bfbdadcad580e30d39a434c Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Mon, 22 Nov 2021 01:55:20 +0100 Subject: [PATCH 08/10] add runnerChar in board text definition --- in_hardPuzzle.txt | 2 +- in_largePuzzle.txt | 2 +- in_smallPuzzle.txt | 2 +- out_hardPuzzle.txt | 364 ++++++++++++++++++++++----------------------- printer.cpp | 27 ++-- test.cpp | 12 +- 6 files changed, 206 insertions(+), 203 deletions(-) diff --git a/in_hardPuzzle.txt b/in_hardPuzzle.txt index 6a1a15a..2298b9d 100644 --- a/in_hardPuzzle.txt +++ b/in_hardPuzzle.txt @@ -1,5 +1,5 @@ 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@ acd# diff --git a/in_largePuzzle.txt b/in_largePuzzle.txt index fd4e202..6d3ac7e 100644 --- a/in_largePuzzle.txt +++ b/in_largePuzzle.txt @@ -1,5 +1,5 @@ 4 6 -1 4 +1 4 @ ###### #A@@F# #A@@F# diff --git a/in_smallPuzzle.txt b/in_smallPuzzle.txt index c91742b..bf49ea5 100644 --- a/in_smallPuzzle.txt +++ b/in_smallPuzzle.txt @@ -1,5 +1,5 @@ 5 6 -0 0 +0 0 @ ####### # # # AA # diff --git a/out_hardPuzzle.txt b/out_hardPuzzle.txt index 993ab2e..31a23f1 100644 --- a/out_hardPuzzle.txt +++ b/out_hardPuzzle.txt @@ -1,7 +1,7 @@ -------------- 0 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@ acd# @@ -12,7 +12,7 @@ -------------- 1 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@a cd# @@ -23,7 +23,7 @@ -------------- 2 6 5 -4 3 +4 3 @ ######## #@@aab # #@@a cd# @@ -34,7 +34,7 @@ -------------- 3 6 5 -4 3 +4 3 @ ######## #@@aab # #@@ac d# @@ -45,7 +45,7 @@ -------------- 4 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -56,7 +56,7 @@ -------------- 5 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -67,7 +67,7 @@ -------------- 6 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -78,7 +78,7 @@ -------------- 7 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -89,7 +89,7 @@ -------------- 8 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -100,7 +100,7 @@ -------------- 9 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -111,7 +111,7 @@ -------------- 10 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -122,7 +122,7 @@ -------------- 11 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -133,7 +133,7 @@ -------------- 12 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -144,7 +144,7 @@ -------------- 13 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -155,7 +155,7 @@ -------------- 14 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -166,7 +166,7 @@ -------------- 15 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -177,7 +177,7 @@ -------------- 16 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -188,7 +188,7 @@ -------------- 17 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -199,7 +199,7 @@ -------------- 18 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -210,7 +210,7 @@ -------------- 19 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -221,7 +221,7 @@ -------------- 20 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -232,7 +232,7 @@ -------------- 21 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -243,7 +243,7 @@ -------------- 22 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -254,7 +254,7 @@ -------------- 23 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -265,7 +265,7 @@ -------------- 24 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -276,7 +276,7 @@ -------------- 25 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -287,7 +287,7 @@ -------------- 26 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -298,7 +298,7 @@ -------------- 27 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -309,7 +309,7 @@ -------------- 28 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -320,7 +320,7 @@ -------------- 29 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -331,7 +331,7 @@ -------------- 30 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -342,7 +342,7 @@ -------------- 31 6 5 -4 3 +4 3 @ ######## #@@aabd# #@@acdd# @@ -353,7 +353,7 @@ -------------- 32 6 5 -4 3 +4 3 @ ######## #@@aab # #@@ac d# @@ -364,7 +364,7 @@ -------------- 33 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@ac d# @@ -375,7 +375,7 @@ -------------- 34 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@a cd# @@ -386,7 +386,7 @@ -------------- 35 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@a d# @@ -397,7 +397,7 @@ -------------- 36 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@am d# @@ -408,7 +408,7 @@ -------------- 37 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amd # @@ -419,7 +419,7 @@ -------------- 38 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amd # @@ -430,7 +430,7 @@ -------------- 39 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -441,7 +441,7 @@ -------------- 40 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -452,7 +452,7 @@ -------------- 41 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -463,7 +463,7 @@ -------------- 42 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -474,7 +474,7 @@ -------------- 43 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -485,7 +485,7 @@ -------------- 44 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -496,7 +496,7 @@ -------------- 45 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@amdj# @@ -507,7 +507,7 @@ -------------- 46 6 5 -4 3 +4 3 @ ######## #@@aacb# #@@am j# @@ -518,7 +518,7 @@ -------------- 47 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@amcj# @@ -529,7 +529,7 @@ -------------- 48 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@a cj# @@ -540,7 +540,7 @@ -------------- 49 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@ acj# @@ -551,7 +551,7 @@ -------------- 50 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@iacj# @@ -562,7 +562,7 @@ -------------- 51 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@iacj# @@ -573,7 +573,7 @@ -------------- 52 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iacj# @@ -584,7 +584,7 @@ -------------- 53 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iacj# @@ -595,7 +595,7 @@ -------------- 54 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iacj# @@ -606,7 +606,7 @@ -------------- 55 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iacj# @@ -617,7 +617,7 @@ -------------- 56 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iac # @@ -628,7 +628,7 @@ -------------- 57 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@ia c# @@ -639,7 +639,7 @@ -------------- 58 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@ia c# @@ -650,7 +650,7 @@ -------------- 59 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -661,7 +661,7 @@ -------------- 60 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -672,7 +672,7 @@ -------------- 61 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -683,7 +683,7 @@ -------------- 62 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -694,7 +694,7 @@ -------------- 63 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -705,7 +705,7 @@ -------------- 64 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -716,7 +716,7 @@ -------------- 65 6 5 -4 3 +4 3 @ ######## #@@iaab# #@@iadc# @@ -727,7 +727,7 @@ -------------- 66 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@iadc# @@ -738,7 +738,7 @@ -------------- 67 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@iadc# @@ -749,7 +749,7 @@ -------------- 68 6 5 -4 3 +4 3 @ ######## #@@ aab# #@@ adc# @@ -760,7 +760,7 @@ -------------- 69 6 5 -4 3 +4 3 @ ######## #@@aa b# #@@a dc# @@ -771,7 +771,7 @@ -------------- 70 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -782,7 +782,7 @@ -------------- 71 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -793,7 +793,7 @@ -------------- 72 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -804,7 +804,7 @@ -------------- 73 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -815,7 +815,7 @@ -------------- 74 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -826,7 +826,7 @@ -------------- 75 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -837,7 +837,7 @@ -------------- 76 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -848,7 +848,7 @@ -------------- 77 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -859,7 +859,7 @@ -------------- 78 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -870,7 +870,7 @@ -------------- 79 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -881,7 +881,7 @@ -------------- 80 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -892,7 +892,7 @@ -------------- 81 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -903,7 +903,7 @@ -------------- 82 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -914,7 +914,7 @@ -------------- 83 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -925,7 +925,7 @@ -------------- 84 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -936,7 +936,7 @@ -------------- 85 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -947,7 +947,7 @@ -------------- 86 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -958,7 +958,7 @@ -------------- 87 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -969,7 +969,7 @@ -------------- 88 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -980,7 +980,7 @@ -------------- 89 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@addc# @@ -991,7 +991,7 @@ -------------- 90 6 5 -4 3 +4 3 @ ######## #@@aadb# #@@add # @@ -1002,7 +1002,7 @@ -------------- 91 6 5 -4 3 +4 3 @ ######## #@@aad # #@@addb# @@ -1013,7 +1013,7 @@ -------------- 92 6 5 -4 3 +4 3 @ ######## #@@aad # #@@addb# @@ -1024,7 +1024,7 @@ -------------- 93 6 5 -4 3 +4 3 @ ######## #@@aad # #@@addb# @@ -1035,7 +1035,7 @@ -------------- 94 6 5 -4 3 +4 3 @ ######## #@@aad # #@@addb# @@ -1046,7 +1046,7 @@ -------------- 95 6 5 -4 3 +4 3 @ ######## #@@aad # #@@add # @@ -1057,7 +1057,7 @@ -------------- 96 6 5 -4 3 +4 3 @ ######## #@@aa d# #@@a dd# @@ -1068,7 +1068,7 @@ -------------- 97 6 5 -4 3 +4 3 @ ######## #@@ aad# #@@ add# @@ -1079,7 +1079,7 @@ -------------- 98 6 5 -4 3 +4 3 @ ######## # @@aad# # @@add# @@ -1090,7 +1090,7 @@ -------------- 99 6 5 -4 3 +4 3 @ ######## # @@aad# #g@@add# @@ -1101,7 +1101,7 @@ -------------- 100 6 5 -4 3 +4 3 @ ######## #g@@aad# # @@add# @@ -1112,7 +1112,7 @@ -------------- 101 6 5 -4 3 +4 3 @ ######## #g@@aad# # @@add# @@ -1123,7 +1123,7 @@ -------------- 102 6 5 -4 3 +4 3 @ ######## #g@@aad# # @@add# @@ -1134,7 +1134,7 @@ -------------- 103 6 5 -4 3 +4 3 @ ######## #g@@aad# # @@add# @@ -1145,7 +1145,7 @@ -------------- 104 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1156,7 +1156,7 @@ -------------- 105 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1167,7 +1167,7 @@ -------------- 106 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1178,7 +1178,7 @@ -------------- 107 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1189,7 +1189,7 @@ -------------- 108 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1200,7 +1200,7 @@ -------------- 109 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1211,7 +1211,7 @@ -------------- 110 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1222,7 +1222,7 @@ -------------- 111 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1233,7 +1233,7 @@ -------------- 112 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1244,7 +1244,7 @@ -------------- 113 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1255,7 +1255,7 @@ -------------- 114 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1266,7 +1266,7 @@ -------------- 115 6 5 -4 3 +4 3 @ ######## #g@@aad# #m@@add# @@ -1277,7 +1277,7 @@ -------------- 116 6 5 -4 3 +4 3 @ ######## #g@@aa # #m@@a d# @@ -1288,7 +1288,7 @@ -------------- 117 6 5 -4 3 +4 3 @ ######## #g@@ aa# #m@@ ad# @@ -1299,7 +1299,7 @@ -------------- 118 6 5 -4 3 +4 3 @ ######## #g @@aa# #m @@ad# @@ -1310,7 +1310,7 @@ -------------- 119 6 5 -4 3 +4 3 @ ######## # g@@aa# #m @@ad# @@ -1321,7 +1321,7 @@ -------------- 120 6 5 -4 3 +4 3 @ ######## #mg@@aa# # @@ad# @@ -1332,7 +1332,7 @@ -------------- 121 6 5 -4 3 +4 3 @ ######## #mg@@aa# #kk@@ad# @@ -1343,7 +1343,7 @@ -------------- 122 6 5 -4 3 +4 3 @ ######## #mg@@aa# #kk@@ad# @@ -1354,7 +1354,7 @@ -------------- 123 6 5 -4 3 +4 3 @ ######## #mg@@aa# #kk@@ad# @@ -1365,7 +1365,7 @@ -------------- 124 6 5 -4 3 +4 3 @ ######## #mg@@aa# #kk@@ad# @@ -1376,7 +1376,7 @@ -------------- 125 6 5 -4 3 +4 3 @ ######## #mg@@aa# #kk@@ad# @@ -1387,7 +1387,7 @@ -------------- 126 6 5 -4 3 +4 3 @ ######## #mg aa# #kk@@ad# @@ -1398,7 +1398,7 @@ -------------- 127 6 5 -4 3 +4 3 @ ######## #m g aa# #kk@@ad# @@ -1409,7 +1409,7 @@ -------------- 128 6 5 -4 3 +4 3 @ ######## #m gaa# #kk@@ad# @@ -1420,7 +1420,7 @@ -------------- 129 6 5 -4 3 +4 3 @ ######## # m gaa# #kk@@ad# @@ -1431,7 +1431,7 @@ -------------- 130 6 5 -4 3 +4 3 @ ######## # mgaa# #kk@@ad# @@ -1442,7 +1442,7 @@ -------------- 131 6 5 -4 3 +4 3 @ ######## #kkmgaa# # @@ad# @@ -1453,7 +1453,7 @@ -------------- 132 6 5 -4 3 +4 3 @ ######## #kkmgaa# # b@@ad# @@ -1464,7 +1464,7 @@ -------------- 133 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb@@ad# @@ -1475,7 +1475,7 @@ -------------- 134 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb@@ad# @@ -1486,7 +1486,7 @@ -------------- 135 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb@@ad# @@ -1497,7 +1497,7 @@ -------------- 136 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb@@ad# @@ -1508,7 +1508,7 @@ -------------- 137 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb@@ad# @@ -1519,7 +1519,7 @@ -------------- 138 6 5 -4 3 +4 3 @ ######## #kkmgaa# #cb ad# @@ -1530,7 +1530,7 @@ -------------- 139 6 5 -4 3 +4 3 @ ######## #kkm aa# #cb gad# @@ -1541,7 +1541,7 @@ -------------- 140 6 5 -4 3 +4 3 @ ######## #kkm aa# #cbg ad# @@ -1552,7 +1552,7 @@ -------------- 141 6 5 -4 3 +4 3 @ ######## #kkmaa # #cbga d# @@ -1563,7 +1563,7 @@ -------------- 142 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1574,7 +1574,7 @@ -------------- 143 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1585,7 +1585,7 @@ -------------- 144 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1596,7 +1596,7 @@ -------------- 145 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1607,7 +1607,7 @@ -------------- 146 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1618,7 +1618,7 @@ -------------- 147 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1629,7 +1629,7 @@ -------------- 148 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1640,7 +1640,7 @@ -------------- 149 6 5 -4 3 +4 3 @ ######## #kkmaad# #cbgadd# @@ -1651,7 +1651,7 @@ -------------- 150 6 5 -4 3 +4 3 @ ######## #kkmaad# #cb add# @@ -1662,7 +1662,7 @@ -------------- 151 6 5 -4 3 +4 3 @ ######## #kkmaad# #c badd# @@ -1673,7 +1673,7 @@ -------------- 152 6 5 -4 3 +4 3 @ ######## #kkmaad# # cbadd# @@ -1684,7 +1684,7 @@ -------------- 153 6 5 -4 3 +4 3 @ ######## #kkmaad# # cbadd# @@ -1695,7 +1695,7 @@ -------------- 154 6 5 -4 3 +4 3 @ ######## #kkmaad# # c add# @@ -1706,7 +1706,7 @@ -------------- 155 6 5 -4 3 +4 3 @ ######## #kkmaad# # cadd# @@ -1717,7 +1717,7 @@ -------------- 156 6 5 -4 3 +4 3 @ ######## # maad# #kkcadd# @@ -1728,7 +1728,7 @@ -------------- 157 6 5 -4 3 +4 3 @ ######## # m aad# #kkcadd# @@ -1739,7 +1739,7 @@ -------------- 158 6 5 -4 3 +4 3 @ ######## # mcaad# #kk add# @@ -1750,7 +1750,7 @@ -------------- 159 6 5 -4 3 +4 3 @ ######## #m caad# #kk add# @@ -1761,7 +1761,7 @@ -------------- 160 6 5 -4 3 +4 3 @ ######## #mc aad# #kk add# @@ -1772,7 +1772,7 @@ -------------- 161 6 5 -4 3 +4 3 @ ######## #mcaa d# #kka dd# @@ -1783,7 +1783,7 @@ -------------- 162 6 5 -4 3 +4 3 @ ######## #mcaad # #kkadd # @@ -1794,7 +1794,7 @@ -------------- 163 6 5 -4 3 +4 3 @ ######## #mcaad # #kkaddj# @@ -1805,7 +1805,7 @@ -------------- 164 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1816,7 +1816,7 @@ -------------- 165 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1827,7 +1827,7 @@ -------------- 166 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1838,7 +1838,7 @@ -------------- 167 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1849,7 +1849,7 @@ -------------- 168 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1860,7 +1860,7 @@ -------------- 169 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1871,7 +1871,7 @@ -------------- 170 6 5 -4 3 +4 3 @ ######## #mcaadj# #kkaddj# @@ -1882,7 +1882,7 @@ -------------- 171 6 5 -4 3 +4 3 @ ######## #mcaadj# # addj# @@ -1893,7 +1893,7 @@ -------------- 172 6 5 -4 3 +4 3 @ ######## #m aadj# # caddj# @@ -1904,7 +1904,7 @@ -------------- 173 6 5 -4 3 +4 3 @ ######## #m aadj# #c addj# @@ -1915,7 +1915,7 @@ -------------- 174 6 5 -4 3 +4 3 @ ######## #maa dj# #ca ddj# @@ -1926,7 +1926,7 @@ -------------- 175 6 5 -4 3 +4 3 @ ######## #maad j# #cadd j# @@ -1937,7 +1937,7 @@ -------------- 176 6 5 -4 3 +4 3 @ ######## #maadj # #caddj # @@ -1948,7 +1948,7 @@ -------------- 177 6 5 -4 3 +4 3 @ ######## #maadj # #caddji# @@ -1959,7 +1959,7 @@ -------------- 178 6 5 -4 3 +4 3 @ ######## #maadji# #caddji# @@ -1970,7 +1970,7 @@ -------------- 179 6 5 -4 3 +4 3 @ ######## #maadji# #caddji# @@ -1981,7 +1981,7 @@ -------------- 180 6 5 -4 3 +4 3 @ ######## #maadji# #caddji# @@ -1992,7 +1992,7 @@ -------------- 181 6 5 -4 3 +4 3 @ ######## #maadji# #caddji# diff --git a/printer.cpp b/printer.cpp index 9431865..e3c8739 100644 --- a/printer.cpp +++ b/printer.cpp @@ -215,6 +215,7 @@ void printHtml(const std::list& puzzleList, const size_t& animatedScale, out << "\n"; } +const char goalChar = '^'; void printText(const Puzzle& puzzle, std::ostream& out) { //init layout @@ -229,18 +230,19 @@ void printText(const Puzzle& puzzle, std::ostream& out) { } // Print border blocks + const char borderChar = '#'; for (auto x = 0; x < puzzle.dimensions.x + 2; ++x) { - layout[x][0] = '#'; - layout[x][puzzle.dimensions.y + 1] = '#'; + layout[x][0] = borderChar; + layout[x][puzzle.dimensions.y + 1] = borderChar; } for (auto y = 1; y < puzzle.dimensions.y + 1; ++y) { - layout[0][y] = '#'; - layout[puzzle.dimensions.x + 1][y] = '#'; + layout[0][y] = borderChar; + layout[puzzle.dimensions.x + 1][y] = borderChar; } // print content for (const auto &forbiddenPoint : puzzle.forbiddenSpots) { - layout[forbiddenPoint.x + 1][forbiddenPoint.y + 1] = '#'; + layout[forbiddenPoint.x + 1][forbiddenPoint.y + 1] = borderChar; } auto fillBlock = [&](const Block& block) { @@ -249,7 +251,7 @@ void printText(const Puzzle& puzzle, std::ostream& out) { } }; - fillBlock({ puzzle.goal, puzzle.boardState->runner.pointSet, "^" }); + fillBlock({ puzzle.goal, puzzle.boardState->runner.pointSet, toString(goalChar) }); //fill runner block fillBlock(puzzle.boardState->runner); @@ -261,7 +263,7 @@ void printText(const Puzzle& puzzle, std::ostream& out) { //prepare output out << puzzle.dimensions.x << " " << puzzle.dimensions.y << "\n"; - out << puzzle.goal.x << " " << puzzle.goal.y << "\n"; + out << puzzle.goal.x << " " << puzzle.goal.y << " " << puzzle.boardState->runner.id << "\n"; for (auto y = 0; y < puzzle.dimensions.y + 2; ++y) { for (auto x = 0; x < puzzle.dimensions.x + 2; ++x) { out << layout[x][y]; @@ -281,8 +283,9 @@ void printText(const std::list& puzzleList, std::ostream& out) { Puzzle scanText(std::istream& in) { Point dimension; Point goal; - in >> dimension.x >> dimension.y >> goal.x >> goal.y; - //std::cout << dimension.x << "\n" << dimension.y << "\n" << goal.x << "\n" << goal.y << "\n"; + char runnerChar; + in >> dimension.x >> dimension.y >> goal.x >> goal.y >> runnerChar; + //std::cout << dimension.x << "\n" << dimension.y << "\n" << goal.x << "\n" << goal.y << "\n" << runnerChar << '\n'; std::string line; std::getline(in, line); std::getline(in, line); @@ -304,10 +307,10 @@ Puzzle scanText(std::istream& in) { if ((' ' == objPair.first)) { //forget blanc place - } else if ('^' == objPair.first) { - //orget goal + } else if (goalChar == objPair.first) { + //forget goal - } else if ('@' == objPair.first) { + } else if (runnerChar == objPair.first) { runnerPointSet = objPair.second; runnerId = toString(objPair.first); diff --git a/test.cpp b/test.cpp index 72f8276..7ce6d58 100644 --- a/test.cpp +++ b/test.cpp @@ -285,7 +285,7 @@ void testPrintScan() { assert(checkPrintScan( tetrisPuzzle, "5 6\n" - "0 0\n" + "0 0 @\n" "#######\n" "#^^ #\n" "# ^AA #\n" @@ -299,7 +299,7 @@ void testPrintScan() { assert(checkPrintScan( largePuzzle, "4 6\n" - "1 4\n" + "1 4 @\n" "######\n" "#A@@F#\n" "#A@@F#\n" @@ -1002,7 +1002,7 @@ void testSolver() { "\n" "-------------- 0\n" "3 3\n" - "1 1\n" + "1 1 @\n" "#####\n" "#@ #\n" "# A #\n" @@ -1011,7 +1011,7 @@ void testSolver() { "\n" "-------------- 1\n" "3 3\n" - "1 1\n" + "1 1 @\n" "#####\n" "# #\n" "#@A #\n" @@ -1020,7 +1020,7 @@ void testSolver() { "\n" "-------------- 2\n" "3 3\n" - "1 1\n" + "1 1 @\n" "#####\n" "# #\n" "#@^ #\n" @@ -1029,7 +1029,7 @@ void testSolver() { "\n" "-------------- 3\n" "3 3\n" - "1 1\n" + "1 1 @\n" "#####\n" "# #\n" "# @ #\n" From 980f6a3a03ae3af517fc46cfa6329758f67592b5 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Mon, 22 Nov 2021 23:37:33 +0100 Subject: [PATCH 09/10] prioritize moves according to last moved block --- MoveDiscovery.cpp | 6 +- MoveDiscovery.h | 6 +- README.md | 18 +- main.cpp | 2 +- out_hardPuzzle.html | 2560 ++++++++++++++---------------------------- out_hardPuzzle.txt | 1328 +++++++++++----------- out_smallPuzzle.html | 62 +- printer.cpp | 55 +- printer.h | 9 +- puzzle.cpp | 7 +- puzzle.h | 9 +- solver.cpp | 81 +- solver.h | 10 +- test.cpp | 65 +- 14 files changed, 1689 insertions(+), 2529 deletions(-) diff --git a/MoveDiscovery.cpp b/MoveDiscovery.cpp index 70f8b69..012d1d4 100644 --- a/MoveDiscovery.cpp +++ b/MoveDiscovery.cpp @@ -5,11 +5,13 @@ std::vector MoveRunnerFirst::gatherMoves( const Point dimensions, const std::shared_ptr& boardState, - const std::set& invalidPositions + const std::set& invalidPositions, + const Block* lastMovedBlock ) const { std::vector result{}; auto moveBlockIfPossible = [&](const Block& block) { + const size_t moveEffort = ((nullptr != lastMovedBlock) && (lastMovedBlock->id == block.id)) ? 0 : 1; for (auto dir = 0; dir < static_cast(Direction::Number_of_dirs); ++dir) { if (validBlockPosition( block.move(static_cast(dir)), @@ -17,7 +19,7 @@ std::vector MoveRunnerFirst::gatherMoves( *boardState, invalidPositions )) { - result.emplace_back(boardState, block, static_cast(dir)); + result.emplace_back(boardState, block, moveEffort, static_cast(dir)); } } }; diff --git a/MoveDiscovery.h b/MoveDiscovery.h index 3d7d64a..6268b37 100644 --- a/MoveDiscovery.h +++ b/MoveDiscovery.h @@ -10,7 +10,8 @@ class MoveDiscovery { virtual std::vector gatherMoves( const Point dimensions, const std::shared_ptr& boardState, - const std::set& invalidPositions + const std::set& invalidPositions, + const Block* lastMovedBlock ) const = 0; }; @@ -19,7 +20,8 @@ class MoveRunnerFirst : public MoveDiscovery { virtual std::vector gatherMoves( const Point dimensions, const std::shared_ptr& boardState, - const std::set& invalidPositions + const std::set& invalidPositions, + const Block* lastMovedBlock ) const; }; diff --git a/README.md b/README.md index 75daca1..a4d7178 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # klotski-solver -a klotski-solver written in C++ -No external libraries used. Not even for UTests. -text input. -text, svg, animated html output. +a klotski-solver written in C++ +No external libraries used. Not even for UTests. +text input. +text, svg, animated html output. # Build instructions ## Linux @@ -10,7 +10,7 @@ rm -frv "/tmp/build"; mkdir -pv "/tmp/build" && cmake -B "/tmp/build" -S . && make -j --directory="/tmp/build" && echo done ## Windows -mkdir build && cd build && cmake .. +mkdir build && cd build && cmake .. Build with Visual studio 2017 # Run @@ -23,10 +23,10 @@ run `unit-tests.exe` in debug build ## Solve ### Linux -"/tmp/build/solve" < "in_smallPuzzle.txt" 1> out_smallPuzzle.html -"/tmp/build/solve" < "in_smallPuzzle.txt" 2> /dev/null -"/tmp/build/solve" < "in_largePuzzle.txt" -time "/tmp/build/solve" < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt +"/tmp/build/solve" < "in_smallPuzzle.txt" 1> out_smallPuzzle.html +"/tmp/build/solve" < "in_smallPuzzle.txt" 2> /dev/null +"/tmp/build/solve" < "in_largePuzzle.txt" +time "/tmp/build/solve" < "in_hardPuzzle.txt" 1> out_hardPuzzle.html 2> out_hardPuzzle.txt ### Windows `solve.exe` < "in_smallPuzzle.txt" 1> out_smallPuzzle.html diff --git a/main.cpp b/main.cpp index 7227fd6..921f743 100644 --- a/main.cpp +++ b/main.cpp @@ -12,7 +12,7 @@ int main(int argc, char* /*argv*/[]) { return 1; } - printHtml(result, 100, 20, std::cout); + printHtml(result, false, 100, 20, std::cout); if (!benchmark) { printText(result, std::cerr); } return 0; } diff --git a/out_hardPuzzle.html b/out_hardPuzzle.html index d9263b7..8a18c2c 100644 --- a/out_hardPuzzle.html +++ b/out_hardPuzzle.html @@ -27,184 +27,188 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- 1 + 0 @@ -224,7 +228,7 @@ - 2 + 1 @@ -244,7 +248,7 @@ - 3 + 2 @@ -264,7 +268,7 @@ - 4 + 3 @@ -284,7 +288,7 @@ - 5 + 4 @@ -304,27 +308,7 @@ - 6 - - - - - - - - - - - - - - - - - - - - 7 + 5 @@ -344,7 +328,7 @@ - 8 + 6 @@ -355,56 +339,16 @@ - + - - - - - - - - 9 - - - - - - - - - - - - - - - - - - - - 10 - - - - - - - - - - - - - + - 11 + 7 @@ -415,16 +359,16 @@ - - - + + + - 12 + 8 @@ -435,16 +379,16 @@ - - - + + + - 13 + 9 @@ -456,15 +400,15 @@ - - + + - 14 + 10 @@ -484,7 +428,7 @@ - 15 + 11 @@ -500,51 +444,11 @@ - - - - - 16 - - - - - - - - - - - - - - - - - - - - 17 - - - - - - - - - - - - - - - - 18 + 12 @@ -564,7 +468,7 @@ - 19 + 13 @@ -584,7 +488,7 @@ - 20 + 14 @@ -604,7 +508,7 @@ - 21 + 15 @@ -624,27 +528,7 @@ - 22 - - - - - - - - - - - - - - - - - - - - 23 + 16 @@ -655,8 +539,8 @@ - - + + @@ -664,7 +548,7 @@ - 24 + 17 @@ -675,16 +559,16 @@ - - + + - + - 25 + 18 @@ -695,16 +579,16 @@ - - + + - + - 26 + 19 @@ -715,16 +599,16 @@ - - + + - + - 27 + 20 @@ -735,16 +619,16 @@ - - + + - + - 28 + 21 @@ -755,16 +639,16 @@ - - + + - + - 29 + 22 @@ -775,16 +659,16 @@ - - + + - - + + - 30 + 23 @@ -795,16 +679,16 @@ - - + + - - + + - 31 + 24 @@ -812,139 +696,79 @@ - + - - + + - - + + - 32 + 25 - + - + - - + + - + - 33 + 26 - - + + - - + + - + - 34 + 27 - + - - - - - - - - - - 35 - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - 37 - - - - - - - - - - - - + + - + - 38 + 28 @@ -955,36 +779,16 @@ - - + + - - - - - 39 - - - - - - - - - - - - - - - - + - 40 + 29 @@ -995,76 +799,16 @@ - - + + - - - - - 41 - - - - - - - - - - - - - - - - - - - - 42 - - - - - - - - - - - - - - - - - - - - 43 - - - - - - - - - - - - - - - - 44 + 30 @@ -1075,16 +819,16 @@ - - + + - + - 45 + 31 @@ -1095,16 +839,16 @@ - - + + - - + + - 46 + 32 @@ -1115,16 +859,16 @@ - - + + - - + + - 47 + 33 @@ -1135,16 +879,16 @@ - - + + - - + + - 48 + 34 @@ -1155,16 +899,16 @@ - - + + - - + + - 49 + 35 @@ -1175,16 +919,16 @@ - - + + - - + + - 50 + 36 @@ -1195,16 +939,16 @@ - - + + - - + + - 51 + 37 @@ -1215,16 +959,16 @@ - - - + + + - - + + - 52 + 38 @@ -1235,16 +979,16 @@ - - - + + + - - + + - 53 + 39 @@ -1255,16 +999,16 @@ - - + + - - + + - 54 + 40 @@ -1275,16 +1019,16 @@ - - + + - - + + - 55 + 41 @@ -1295,16 +1039,16 @@ - - + + - - + + - 56 + 42 @@ -1315,36 +1059,36 @@ - - + + - - - + + + - 57 + 43 - + - - + + - - + + - 58 + 44 @@ -1355,36 +1099,16 @@ - - + + - - - + + + - 59 - - - - - - - - - - - - - - - - - - - - 60 + 45 @@ -1395,16 +1119,16 @@ - - + + - - + + - 61 + 46 @@ -1415,16 +1139,16 @@ - - + + - - + + - 62 + 47 @@ -1435,16 +1159,16 @@ - - + + - - + + - 63 + 48 @@ -1455,16 +1179,16 @@ - - + + - + - 64 + 49 @@ -1475,16 +1199,16 @@ - - + + - - + + - 65 + 50 @@ -1495,16 +1219,16 @@ - - + + - + - 66 + 51 @@ -1515,56 +1239,16 @@ - - + + - - - - - 67 - - - - - - - - - - - - - - - - - - - - 68 - - - - - - - - - - - - - - - - + - 69 + 52 @@ -1575,16 +1259,16 @@ - - + + - + - 70 + 53 @@ -1595,16 +1279,16 @@ - - + + - + - 71 + 54 @@ -1615,36 +1299,16 @@ - - + + - - - - - 72 - - - - - - - - - - - - - - - - + - 73 + 55 @@ -1655,16 +1319,16 @@ - - + + - + - 74 + 56 @@ -1675,16 +1339,16 @@ - - + + - + - 75 + 57 @@ -1695,16 +1359,16 @@ - - + + - + - 76 + 58 @@ -1715,16 +1379,16 @@ - - + + - + - 77 + 59 @@ -1735,16 +1399,16 @@ - - + + - + - 78 + 60 @@ -1755,16 +1419,16 @@ - - - + + + - + - 79 + 61 @@ -1775,16 +1439,16 @@ - - - + + + - - + + - 80 + 62 @@ -1795,16 +1459,16 @@ - - - + + + - - + + - 81 + 63 @@ -1815,16 +1479,16 @@ - - - + + + - - + + - 82 + 64 @@ -1835,16 +1499,16 @@ - - - + + + - - + + - 83 + 65 @@ -1855,16 +1519,16 @@ - - - + + + - + - 84 + 66 @@ -1874,17 +1538,17 @@ - - - + + + - + - 85 + 67 @@ -1893,18 +1557,18 @@ - + - - + + - + - 86 + 68 @@ -1915,16 +1579,16 @@ - - + + - + - 87 + 69 @@ -1935,16 +1599,16 @@ - - + + - - + + - 88 + 70 @@ -1955,156 +1619,36 @@ - - - - - - - - - - 89 - - - - - - - - - - - - - - - - - - - - 90 - - - - - - - - - - - - - - - - - - - - 91 - - - - - - - - - - - - - - - - - - - - 92 - - - - - - - - - - - - - - - - - - - - 93 - - - - - - - - - - - - - - - - - - - - 94 - - - - - - - - - - - - + + - + - 95 + 71 - + - - + + - + - 96 + 72 @@ -2115,16 +1659,16 @@ - - + + - + - 97 + 73 @@ -2135,16 +1679,16 @@ - - + + - + - 98 + 74 @@ -2155,36 +1699,16 @@ - - - - - - - - - - 99 - - - - - - - - - - - - + + - + - 100 + 75 @@ -2195,16 +1719,16 @@ - - + + - + - 101 + 76 @@ -2215,16 +1739,16 @@ - - + + - + - 102 + 77 @@ -2235,96 +1759,36 @@ - - + + - - - - - 103 - - - - - - - - - - - - - - - - - - - - 104 - - - - - - - - - - - - - - - - - - - - 105 - - - - - - - - - - - - - - - - + - 106 + 78 - + - - + + - + - 107 + 79 @@ -2335,16 +1799,16 @@ - - + + - + - 108 + 80 @@ -2355,16 +1819,16 @@ - - - + + + - + - 109 + 81 @@ -2375,16 +1839,16 @@ - - - + + + - + - 110 + 82 @@ -2395,16 +1859,16 @@ - - - + + + - + - 111 + 83 @@ -2415,96 +1879,36 @@ - + - - - - - - - - 112 - - - - - - - - - - - - - - - - - - - - 113 - - - - - - - - - - - - - - - - - - - - 114 - - - - - - - - - - - - - + - 115 + 84 - + - - + + - + - 116 + 85 @@ -2515,256 +1919,156 @@ - - - - - - - - - - 117 - - - - - - - - - - - - - - - - - - - - 118 - - - - - - - - - - - - - - - - - - - - 119 - - - - - - - - - - - - - - - - - - - - 120 - - - - - - - - - - - - - - - - - - - - 121 - - - - - - - - - - - - + + - - + + - 122 + 86 - - + + - - + + - - - + + + - 123 + 87 - + - + - - + + - - - + + + - 124 + 88 - - + + - - + + - - - + + + - 125 + 89 - - + + - - + + - - - + + + - 126 + 90 - - + + - - + + - - + + - 127 + 91 - + - + - - + + - - + + - 128 + 92 - + - - + + - - + + - 129 + 93 @@ -2775,16 +2079,16 @@ - - + + - - + + - 130 + 94 @@ -2795,16 +2099,16 @@ - - + + - - + + - 131 + 95 @@ -2815,16 +2119,16 @@ - - + + - - + + - 132 + 96 @@ -2835,16 +2139,16 @@ - - + + - - + + - 133 + 97 @@ -2855,16 +2159,16 @@ - - + + - - + + - 134 + 98 @@ -2875,16 +2179,16 @@ - - + + - - + + - 135 + 99 @@ -2895,36 +2199,16 @@ - - - - - - - - - - 136 - - - - - - - - - - - - + + - - + + - 137 + 100 @@ -2935,16 +2219,16 @@ - - + + - - + + - 138 + 101 @@ -2955,36 +2239,16 @@ - - - - - - - - - - 139 - - - - - - - - - - - - + + - - + + - 140 + 102 @@ -2995,16 +2259,16 @@ - - + + - - + + - 141 + 103 @@ -3015,16 +2279,16 @@ - - + + - - + + - 142 + 104 @@ -3035,116 +2299,16 @@ - - - - - - - - - - 143 - - - - - - - - - - - - + + - - - - - 144 - - - - - - - - - - - - - - - - - - - - 145 - - - - - - - - - - - - - - - - - - - - 146 - - - - - - - - - - - - - - - - - - - - 147 - - - - - - - - - - - - - - - - - + + - 148 + 105 @@ -3155,16 +2319,16 @@ - + - - + + - - + + - 149 + 106 @@ -3175,176 +2339,176 @@ - - + + - + - - + + - 150 + 107 - + - + - + - - + + - 151 + 108 - + - + - + - - + + - 152 + 109 - + - + - + - - + + - 153 + 110 - + - - + + - - + + - - + + - 154 + 111 - + - - + + - - + + - - + + - 155 + 112 - - + + - - + + - - + + - 156 + 113 - - + + - - + + - - + + - 157 + 114 - + - - + + - - - + + + - 158 + 115 @@ -3355,56 +2519,56 @@ - - + + - - - + + + - 159 + 116 - + - - + + - - + + - 160 + 117 - + - - + + - - + + - 161 + 118 @@ -3415,16 +2579,16 @@ - - + + - - + + - 162 + 119 @@ -3435,16 +2599,16 @@ - - + + - - + + - 163 + 120 @@ -3455,36 +2619,16 @@ - - + + - - - - - 164 - - - - - - - - - - - - - - - - - + + - 165 + 121 @@ -3495,36 +2639,16 @@ - - + + - - - - - 166 - - - - - - - - - - - - - - - - - + + - 167 + 122 @@ -3535,16 +2659,16 @@ - - + + - - + + - 168 + 123 @@ -3555,16 +2679,16 @@ - - + + - - + + - 169 + 124 @@ -3575,16 +2699,16 @@ - - + + - - + + - 170 + 125 @@ -3595,16 +2719,16 @@ - - + + - - + + - 171 + 126 @@ -3615,16 +2739,16 @@ - - + + - - + + - 172 + 127 @@ -3635,36 +2759,16 @@ - - - - - - - - - - 173 - - - - - - - - - - - - + + - - + + - 174 + 128 @@ -3675,16 +2779,16 @@ - - + + - - + + - 175 + 129 @@ -3695,16 +2799,16 @@ - - + + - - + + - 176 + 130 @@ -3715,16 +2819,16 @@ - - + + - - + + - 177 + 131 @@ -3735,56 +2839,16 @@ - - + + - - - - - 178 - - - - - - - - - - - - - - - - - - - - 179 - - - - - - - - - - - - - - - - - + + - 180 + 132 @@ -3795,16 +2859,16 @@ - - + + - - + + - 181 + 133 @@ -3815,16 +2879,16 @@ - - + + - - + + - 182 + 134 @@ -3835,13 +2899,13 @@ - - + + - - + + diff --git a/out_hardPuzzle.txt b/out_hardPuzzle.txt index 31a23f1..89b8c3c 100644 --- a/out_hardPuzzle.txt +++ b/out_hardPuzzle.txt @@ -1,5 +1,5 @@ --------------- 0 +-------------- step:0 move:0 6 5 4 3 @ ######## @@ -10,7 +10,7 @@ #effhij# ######## --------------- 1 +-------------- step:1 move:1 6 5 4 3 @ ######## @@ -21,7 +21,7 @@ #effhij# ######## --------------- 2 +-------------- step:2 move:2 6 5 4 3 @ ######## @@ -32,7 +32,7 @@ #effhij# ######## --------------- 3 +-------------- step:3 move:3 6 5 4 3 @ ######## @@ -43,7 +43,7 @@ #effhij# ######## --------------- 4 +-------------- step:4 move:4 6 5 4 3 @ ######## @@ -54,7 +54,7 @@ #effhij# ######## --------------- 5 +-------------- step:5 move:5 6 5 4 3 @ ######## @@ -65,7 +65,7 @@ #effhij# ######## --------------- 6 +-------------- step:6 move:5 6 5 4 3 @ ######## @@ -76,73 +76,95 @@ #effhij# ######## --------------- 7 +-------------- step:7 move:6 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkl im# -#eefgij# -#effh^j# +#kklg m# +#eef ij# +#effhij# ######## --------------- 8 +-------------- step:8 move:6 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkl im# -#eefgij# -#eff hj# +#kkl gm# +#eef ij# +#effhij# +######## + +-------------- step:9 move:7 +6 5 +4 3 @ +######## +#@@aabd# +#@@acdd# +#kkl gm# +#eefhij# +#eff ij# ######## --------------- 9 +-------------- step:10 move:7 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkl im# +#kklhgm# #eef ij# -#effghj# +#eff ij# ######## --------------- 10 +-------------- step:11 move:8 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkli m# +#kklhgm# #eefi^j# -#effghj# +#effi^j# ######## --------------- 11 +-------------- step:12 move:9 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkli m# -#eefihj# -#effg^j# +#kklh m# +#eefigj# +#effi^j# ######## --------------- 12 +-------------- step:13 move:9 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#kkli m# -#eefihj# -#eff gj# +#kklh m# +#eefi^j# +#effigj# +######## + +-------------- step:14 move:10 +6 5 +4 3 @ +######## +#@@aabd# +#@@acdd# +#kkl hm# +#eefi^j# +#effigj# ######## --------------- 13 +-------------- step:15 move:10 6 5 4 3 @ ######## @@ -153,7 +175,7 @@ #effigj# ######## --------------- 14 +-------------- step:16 move:11 6 5 4 3 @ ######## @@ -164,18 +186,18 @@ #effigj# ######## --------------- 15 +-------------- step:17 move:11 6 5 4 3 @ ######## #@@aabd# #@@acdd# -# kkl m# +#kk lm# #eefihj# #effigj# ######## --------------- 16 +-------------- step:18 move:12 6 5 4 3 @ ######## @@ -186,7 +208,7 @@ #effigj# ######## --------------- 17 +-------------- step:19 move:12 6 5 4 3 @ ######## @@ -197,7 +219,7 @@ #effigj# ######## --------------- 18 +-------------- step:20 move:13 6 5 4 3 @ ######## @@ -208,7 +230,7 @@ # ffigj# ######## --------------- 19 +-------------- step:21 move:14 6 5 4 3 @ ######## @@ -219,7 +241,7 @@ #ff igj# ######## --------------- 20 +-------------- step:22 move:15 6 5 4 3 @ ######## @@ -230,18 +252,18 @@ #ffi gj# ######## --------------- 21 +-------------- step:23 move:16 6 5 4 3 @ ######## #@@aabd# #@@acdd# #eekklm# -#efi hj# -#ffig^j# +#efih^j# +#ffi gj# ######## --------------- 22 +-------------- step:24 move:16 6 5 4 3 @ ######## @@ -249,10 +271,10 @@ #@@acdd# #eekklm# #efi ^j# -#ffighj# +#ffihgj# ######## --------------- 23 +-------------- step:25 move:17 6 5 4 3 @ ######## @@ -260,54 +282,54 @@ #@@acdd# #eekk m# #efi lj# -#ffighj# +#ffihgj# ######## --------------- 24 +-------------- step:26 move:17 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#ee kkm# -#efi lj# -#ffighj# +#eekk m# +#efil^j# +#ffihgj# ######## --------------- 25 +-------------- step:27 move:18 6 5 4 3 @ ######## #@@aabd# #@@acdd# -#eeikkm# -#efi lj# -#ff ghj# +#ee kkm# +#efil^j# +#ffihgj# ######## --------------- 26 +-------------- step:28 move:19 6 5 4 3 @ ######## #@@aabd# #@@acdd# #eeikkm# -#efi lj# -#ffg hj# +#efil^j# +#ff hgj# ######## --------------- 27 +-------------- step:29 move:20 6 5 4 3 @ ######## #@@aabd# #@@acdd# #eeikkm# -#efi lj# -#ffgh^j# +#efil^j# +#ffh gj# ######## --------------- 28 +-------------- step:30 move:21 6 5 4 3 @ ######## @@ -315,10 +337,10 @@ #@@acdd# #eeikkm# #efi ^j# -#ffghlj# +#ffhlgj# ######## --------------- 29 +-------------- step:31 move:22 6 5 4 3 @ ######## @@ -326,10 +348,10 @@ #@@acdd# #eei m# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 30 +-------------- step:32 move:23 6 5 4 3 @ ######## @@ -337,10 +359,10 @@ #@@acdd# #eei m # #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 31 +-------------- step:33 move:23 6 5 4 3 @ ######## @@ -348,10 +370,10 @@ #@@acdd# #eeim # #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 32 +-------------- step:34 move:24 6 5 4 3 @ ######## @@ -359,10 +381,10 @@ #@@ac d# #eeimdd# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 33 +-------------- step:35 move:25 6 5 4 3 @ ######## @@ -370,10 +392,10 @@ #@@ac d# #eeimdd# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 34 +-------------- step:36 move:26 6 5 4 3 @ ######## @@ -381,10 +403,10 @@ #@@a cd# #eeimdd# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 35 +-------------- step:37 move:26 6 5 4 3 @ ######## @@ -392,10 +414,10 @@ #@@a d# #eeimdd# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 36 +-------------- step:38 move:27 6 5 4 3 @ ######## @@ -403,10 +425,10 @@ #@@am d# #eei dd# #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 37 +-------------- step:39 move:28 6 5 4 3 @ ######## @@ -414,10 +436,10 @@ #@@amd # #eeidd # #efikkj# -#ffghlj# +#ffhlgj# ######## --------------- 38 +-------------- step:40 move:29 6 5 4 3 @ ######## @@ -425,10 +447,10 @@ #@@amd # #eeiddj# #efikkj# -#ffghl^# +#ffhlg^# ######## --------------- 39 +-------------- step:41 move:29 6 5 4 3 @ ######## @@ -436,274 +458,274 @@ #@@amdj# #eeiddj# #efikk^# -#ffghl^# -######## - --------------- 40 -6 5 -4 3 @ -######## -#@@aacb# -#@@amdj# -#eeiddj# -#efi kk# -#ffghl^# +#ffhlg^# ######## --------------- 41 +-------------- step:42 move:30 6 5 4 3 @ ######## #@@aacb# #@@amdj# #eeiddj# -#efihkk# -#ffg l^# +#efikk^# +#ffhl^g# ######## --------------- 42 +-------------- step:43 move:30 6 5 4 3 @ ######## #@@aacb# #@@amdj# #eeiddj# -#efihkk# -#ffgl^^# +#efikkg# +#ffhl^^# ######## --------------- 43 +-------------- step:44 move:31 6 5 4 3 @ ######## #@@aacb# #@@amdj# #eeiddj# -#efih^^# -#ffglkk# +#efikkg# +#ffh l^# ######## --------------- 44 +-------------- step:45 move:31 6 5 4 3 @ ######## #@@aacb# #@@amdj# #eeiddj# -#efi h^# -#ffglkk# +#efikkg# +#ffh ^l# ######## --------------- 45 +-------------- step:46 move:32 6 5 4 3 @ ######## #@@aacb# #@@amdj# #eeiddj# -#efi ^h# -#ffglkk# +#efi ^g# +#ffhkkl# ######## --------------- 46 +-------------- step:47 move:33 6 5 4 3 @ ######## #@@aacb# #@@am j# #eei dj# -#efiddh# -#ffglkk# +#efiddg# +#ffhkkl# ######## --------------- 47 +-------------- step:48 move:34 6 5 4 3 @ ######## #@@aa b# #@@amcj# #eei dj# -#efiddh# -#ffglkk# +#efiddg# +#ffhkkl# ######## --------------- 48 +-------------- step:49 move:35 6 5 4 3 @ ######## #@@aa b# #@@a cj# #eeimdj# -#efiddh# -#ffglkk# +#efiddg# +#ffhkkl# ######## --------------- 49 +-------------- step:50 move:36 6 5 4 3 @ ######## #@@ aab# #@@ acj# #eeimdj# -#efiddh# -#ffglkk# +#efiddg# +#ffhkkl# ######## --------------- 50 +-------------- step:51 move:37 6 5 4 3 @ ######## #@@ aab# #@@iacj# #eeimdj# -#ef ddh# -#ffglkk# +#ef ddg# +#ffhkkl# ######## --------------- 51 +-------------- step:52 move:37 6 5 4 3 @ ######## -#@@ aab# +#@@iaab# #@@iacj# -#eeimdj# -#efgddh# -#ff lkk# +#ee mdj# +#ef ddg# +#ffhkkl# ######## --------------- 52 +-------------- step:53 move:38 6 5 4 3 @ ######## #@@iaab# #@@iacj# #ee mdj# -#efgddh# -#ff lkk# +#efhddg# +#ff kkl# ######## --------------- 53 +-------------- step:54 move:39 6 5 4 3 @ ######## #@@iaab# #@@iacj# #ee mdj# -#efgddh# -#ffl kk# +#efhddg# +#ffkk^l# ######## --------------- 54 +-------------- step:55 move:40 6 5 4 3 @ ######## #@@iaab# #@@iacj# #ee mdj# -#efgddh# -#fflkk^# +#efhddg# +#ffkkl^# ######## --------------- 55 +-------------- step:56 move:41 6 5 4 3 @ ######## #@@iaab# #@@iacj# #ee mdj# -#efgdd^# -#fflkkh# +#efhdd^# +#ffkklg# ######## --------------- 56 +-------------- step:57 move:42 6 5 4 3 @ ######## #@@iaab# #@@iac # #ee mdj# -#efgddj# -#fflkkh# +#efhddj# +#ffkklg# ######## --------------- 57 +-------------- step:58 move:43 6 5 4 3 @ ######## #@@iaab# #@@ia c# #ee mdj# -#efgddj# -#fflkkh# +#efhddj# +#ffkklg# ######## --------------- 58 +-------------- step:59 move:44 6 5 4 3 @ ######## #@@iaab# #@@ia c# #eem dj# -#efgddj# -#fflkkh# +#efhddj# +#ffkklg# ######## --------------- 59 +-------------- step:60 move:45 6 5 4 3 @ ######## #@@iaab# #@@iadc# #eemddj# -#efg ^j# -#fflkkh# +#efh ^j# +#ffkklg# ######## --------------- 60 +-------------- step:61 move:46 6 5 4 3 @ ######## #@@iaab# #@@iadc# #eemddj# -#efgkkj# -#ffl ^h# +#ef h^j# +#ffkklg# ######## --------------- 61 +-------------- step:62 move:46 6 5 4 3 @ ######## #@@iaab# #@@iadc# #eemddj# -#efgkkj# -#ff l^h# +#ef hj# +#ffkklg# ######## --------------- 62 +-------------- step:63 move:47 6 5 4 3 @ ######## #@@iaab# #@@iadc# #eemddj# -#ef kkj# -#ffgl^h# +#efkkhj# +#ff lg# ######## --------------- 63 +-------------- step:64 move:48 6 5 4 3 @ ######## #@@iaab# #@@iadc# #eemddj# -#ef kkj# -#ffg lh# +#efkkhj# +#ff l^g# +######## + +-------------- step:65 move:49 +6 5 +4 3 @ +######## +#@@iaab# +#@@iadc# +#eemddj# +#efkk^j# +#ff lhg# ######## --------------- 64 +-------------- step:66 move:50 6 5 4 3 @ ######## @@ -711,10 +733,10 @@ #@@iadc# #eemddj# #ef kkj# -#ff glh# +#ff lhg# ######## --------------- 65 +-------------- step:67 move:51 6 5 4 3 @ ######## @@ -722,21 +744,21 @@ #@@iadc# #ee ddj# #efmkkj# -#ff glh# +#ff lhg# ######## --------------- 66 +-------------- step:68 move:51 6 5 4 3 @ ######## -#@@ aab# +#@@iaab# #@@iadc# -#eeiddj# -#efmkkj# -#ff glh# +#ee ddj# +#ef kkj# +#ffmlhg# ######## --------------- 67 +-------------- step:69 move:52 6 5 4 3 @ ######## @@ -744,10 +766,10 @@ #@@iadc# #eeiddj# #ef kkj# -#ffmglh# +#ffmlhg# ######## --------------- 68 +-------------- step:70 move:52 6 5 4 3 @ ######## @@ -755,10 +777,10 @@ #@@ adc# #eeiddj# #efikkj# -#ffmglh# +#ffmlhg# ######## --------------- 69 +-------------- step:71 move:53 6 5 4 3 @ ######## @@ -766,10 +788,10 @@ #@@a dc# #eeiddj# #efikkj# -#ffmglh# +#ffmlhg# ######## --------------- 70 +-------------- step:72 move:54 6 5 4 3 @ ######## @@ -777,10 +799,10 @@ #@@addc# #eei j# #efikkj# -#ffmglh# +#ffmlhg# ######## --------------- 71 +-------------- step:73 move:55 6 5 4 3 @ ######## @@ -788,1215 +810,1237 @@ #@@addc# #eeikkj# #efi ^j# -#ffmglh# +#ffmlhg# ######## --------------- 72 +-------------- step:74 move:56 6 5 4 3 @ ######## #@@aadb# #@@addc# #eeikkj# -#efig^j# -#ffm lh# +#efi hj# +#ffml^g# ######## --------------- 73 +-------------- step:75 move:57 6 5 4 3 @ ######## #@@aadb# #@@addc# #eeikkj# -#efiglj# -#ffm ^h# +#efi hj# +#ffmlg^# ######## --------------- 74 +-------------- step:76 move:58 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeikkj# -#efiglj# -#ffm h^# +#eeikk # +#efi hj# +#ffmlgj# ######## --------------- 75 +-------------- step:77 move:59 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeikk # -#efiglj# -#ffm hj# +#eei kk# +#efi hj# +#ffmlgj# ######## --------------- 76 +-------------- step:78 move:60 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eei kk# -#efiglj# -#ffm hj# +#ee ikk# +#ef ihj# +#ffmlgj# ######## --------------- 77 +-------------- step:79 move:61 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeigkk# -#efi lj# -#ffm hj# +#ee ikk# +#efmihj# +#ff lgj# ######## --------------- 78 +-------------- step:80 move:61 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeigkk# -#efi lj# -#ff mhj# +#eemikk# +#ef ihj# +#ff lgj# ######## --------------- 79 +-------------- step:81 move:62 6 5 4 3 @ ######## #@@aadb# #@@addc# -#ee gkk# -#efi lj# -#ffimhj# +#eemikk# +#ef ihj# +#ffl gj# ######## --------------- 80 +-------------- step:82 move:62 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeg kk# -#efi lj# -#ffimhj# +#eemikk# +#eflihj# +#ff gj# ######## --------------- 81 +-------------- step:83 move:63 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eeg kk# -#efimlj# -#ffi hj# +#eem kk# +#eflihj# +#ff igj# ######## --------------- 82 +-------------- step:84 move:64 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eegmkk# -#efi lj# -#ffi hj# +#ee mkk# +#eflihj# +#ff igj# ######## --------------- 83 +-------------- step:85 move:65 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eegmkk# -#ef ilj# -#ff ihj# +#eelmkk# +#ef ihj# +#ff igj# ######## --------------- 84 +-------------- step:86 move:66 6 5 4 3 @ ######## #@@aadb# #@@addc# -#eegmkk# -#e filj# -# ffihj# +#eelmkk# +#e fihj# +# ffigj# ######## --------------- 85 +-------------- step:87 move:67 6 5 4 3 @ ######## #@@aadb# #@@addc# -# gmkk# -#eefilj# -#effihj# +# lmkk# +#eefihj# +#effigj# ######## --------------- 86 +-------------- step:88 move:68 6 5 4 3 @ ######## #@@aadb# #@@addc# -# g mkk# -#eefilj# -#effihj# +# l mkk# +#eefihj# +#effigj# ######## --------------- 87 +-------------- step:89 move:68 6 5 4 3 @ ######## #@@aadb# #@@addc# -#g mkk# -#eefilj# -#effihj# +#l mkk# +#eefihj# +#effigj# ######## --------------- 88 +-------------- step:90 move:69 6 5 4 3 @ ######## #@@aadb# #@@addc# -#g m kk# -#eefilj# -#effihj# +#l m kk# +#eefihj# +#effigj# ######## --------------- 89 +-------------- step:91 move:69 6 5 4 3 @ ######## #@@aadb# #@@addc# -#g mkk # -#eefilj# -#effihj# +#lm kk# +#eefihj# +#effigj# ######## --------------- 90 +-------------- step:92 move:70 6 5 4 3 @ ######## #@@aadb# -#@@add # -#g mkkc# -#eefilj# -#effihj# +#@@addc# +#lm kk # +#eefihj# +#effigj# ######## --------------- 91 +-------------- step:93 move:70 6 5 4 3 @ ######## -#@@aad # -#@@addb# -#g mkkc# -#eefilj# -#effihj# +#@@aadb# +#@@addc# +#lmkk # +#eefihj# +#effigj# ######## --------------- 92 +-------------- step:94 move:71 6 5 4 3 @ ######## -#@@aad # -#@@addb# -#gm kkc# -#eefilj# -#effihj# +#@@aadb# +#@@add # +#lmkk c# +#eefihj# +#effigj# ######## --------------- 93 +-------------- step:95 move:71 6 5 4 3 @ ######## -#@@aad # -#@@addb# -#gmkk c# -#eefilj# -#effihj# +#@@aadb# +#@@add # +#lmkkc # +#eefihj# +#effigj# ######## --------------- 94 +-------------- step:96 move:72 6 5 4 3 @ ######## #@@aad # #@@addb# -#gmkkc # -#eefilj# -#effihj# +#lmkkc # +#eefihj# +#effigj# ######## --------------- 95 +-------------- step:97 move:72 6 5 4 3 @ ######## #@@aad # #@@add # -#gmkkcb# -#eefilj# -#effihj# +#lmkkcb# +#eefihj# +#effigj# ######## --------------- 96 +-------------- step:98 move:73 6 5 4 3 @ ######## #@@aa d# #@@a dd# -#gmkkcb# -#eefilj# -#effihj# +#lmkkcb# +#eefihj# +#effigj# ######## --------------- 97 +-------------- step:99 move:74 6 5 4 3 @ ######## #@@ aad# #@@ add# -#gmkkcb# -#eefilj# -#effihj# +#lmkkcb# +#eefihj# +#effigj# ######## --------------- 98 +-------------- step:100 move:75 6 5 4 3 @ ######## # @@aad# # @@add# -#gmkkcb# -#eefilj# -#effihj# +#lmkkcb# +#eefihj# +#effigj# ######## --------------- 99 +-------------- step:101 move:76 6 5 4 3 @ ######## # @@aad# -#g@@add# +#l@@add# # mkkcb# -#eefilj# -#effihj# +#eefihj# +#effigj# ######## --------------- 100 +-------------- step:102 move:76 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# # @@add# # mkkcb# -#eefilj# -#effihj# +#eefihj# +#effigj# ######## --------------- 101 +-------------- step:103 move:77 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# # @@add# #m kkcb# -#eefilj# -#effihj# +#eefihj# +#effigj# ######## --------------- 102 +-------------- step:104 move:77 6 5 4 3 @ ######## -#g@@aad# -# @@add# -#mkk cb# -#eefilj# -#effihj# +#l@@aad# +#m@@add# +# kkcb# +#eefihj# +#effigj# ######## --------------- 103 +-------------- step:105 move:78 6 5 4 3 @ ######## -#g@@aad# -# @@add# -#mkkc b# -#eefilj# -#effihj# +#l@@aad# +#m@@add# +# kk cb# +#eefihj# +#effigj# ######## --------------- 104 +-------------- step:106 move:78 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -# kkc b# -#eefilj# -#effihj# +#kk cb# +#eefihj# +#effigj# ######## --------------- 105 +-------------- step:107 move:79 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# #kk c b# -#eefilj# -#effihj# +#eefihj# +#effigj# ######## --------------- 106 +-------------- step:108 move:79 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# #kkc b# -#eefilj# -#effihj# +#eefihj# +#effigj# +######## + +-------------- step:109 move:80 +6 5 +4 3 @ +######## +#l@@aad# +#m@@add# +#kkc hb# +#eefi^j# +#effigj# ######## --------------- 107 +-------------- step:110 move:80 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkci b# -#eefilj# -#eff hj# +#kkch b# +#eefi^j# +#effigj# ######## --------------- 108 +-------------- step:111 move:81 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkci b# -#eefilj# -#effh^j# +#kkch b# +#eefigj# +#effi^j# ######## --------------- 109 +-------------- step:112 move:81 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkci b# +#kkchgb# #eefi^j# -#effhlj# +#effi^j# ######## --------------- 110 +-------------- step:113 move:82 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkc ib# +#kkchgb# #eef ij# -#effhlj# +#eff ij# ######## --------------- 111 +-------------- step:114 move:83 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkc ib# +#kkc gb# #eefhij# -#eff lj# +#eff ij# ######## --------------- 112 +-------------- step:115 move:83 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# -#kkc ib# -#eefhij# -#effl^j# +#kkc gb# +#eef ij# +#effhij# +######## + +-------------- step:116 move:84 +6 5 +4 3 @ +######## +#l@@aad# +#m@@add# +#kkcg b# +#eef ij# +#effhij# ######## --------------- 113 +-------------- step:117 move:84 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# #kkc b# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 114 +-------------- step:118 move:85 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# #kkc b # -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 115 +-------------- step:119 move:85 6 5 4 3 @ ######## -#g@@aad# +#l@@aad# #m@@add# #kkcb # -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 116 +-------------- step:120 move:86 6 5 4 3 @ ######## -#g@@aa # +#l@@aa # #m@@a d# #kkcbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 117 +-------------- step:121 move:87 6 5 4 3 @ ######## -#g@@ aa# +#l@@ aa# #m@@ ad# #kkcbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 118 +-------------- step:122 move:88 6 5 4 3 @ ######## -#g @@aa# +#l @@aa# #m @@ad# #kkcbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 119 +-------------- step:123 move:89 6 5 4 3 @ ######## -# g@@aa# -#m @@ad# +#l @@aa# +# m@@ad# #kkcbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 120 +-------------- step:124 move:89 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# # @@ad# #kkcbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 121 +-------------- step:125 move:90 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# #kk@@ad# # cbdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 122 +-------------- step:126 move:91 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# #kk@@ad# # c bdd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 123 +-------------- step:127 move:91 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# #kk@@ad# -# cb dd# -#eefhij# -#efflij# +#c bdd# +#eefgij# +#effhij# ######## --------------- 124 +-------------- step:128 move:92 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# #kk@@ad# #c b dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 125 +-------------- step:129 move:92 6 5 4 3 @ ######## -#mg@@aa# +#lm@@aa# #kk@@ad# #cb dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 126 +-------------- step:130 move:93 6 5 4 3 @ ######## -#mg aa# +#lm aa# #kk@@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 127 +-------------- step:131 move:94 6 5 4 3 @ ######## -#m g aa# +#l m aa# #kk@@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 128 +-------------- step:132 move:94 6 5 4 3 @ ######## -#m gaa# +#l maa# #kk@@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 129 +-------------- step:133 move:95 6 5 4 3 @ ######## -# m gaa# +# l maa# #kk@@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 130 +-------------- step:134 move:95 6 5 4 3 @ ######## -# mgaa# +# lmaa# #kk@@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 131 +-------------- step:135 move:96 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# # @@ad# #cb@@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 132 +-------------- step:136 move:97 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# # b@@ad# #c @@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 133 +-------------- step:137 move:98 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb@@ad# # @@dd# -#eefhij# -#efflij# +#eefgij# +#effhij# ######## --------------- 134 +-------------- step:138 move:99 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb@@ad# #ee@@dd# -#e fhij# -# fflij# +#e fgij# +# ffhij# ######## --------------- 135 +-------------- step:139 move:100 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb@@ad# #ee@@dd# -#ef hij# -#ff lij# +#ef gij# +#ff hij# ######## --------------- 136 +-------------- step:140 move:101 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb@@ad# #ee@@dd# -#efh ij# -#ff lij# +#efg ij# +#ff hij# ######## --------------- 137 +-------------- step:141 move:101 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb@@ad# #ee@@dd# #ef ij# -#ffhlij# +#ffghij# ######## --------------- 138 +-------------- step:142 move:102 6 5 4 3 @ ######## -#kkmgaa# +#kklmaa# #cb ad# #ee@@dd# #ef@@ij# -#ffhlij# +#ffghij# ######## --------------- 139 +-------------- step:143 move:103 6 5 4 3 @ ######## -#kkm aa# -#cb gad# +#kkl aa# +#cb mad# #ee@@dd# #ef@@ij# -#ffhlij# +#ffghij# ######## --------------- 140 +-------------- step:144 move:103 6 5 4 3 @ ######## -#kkm aa# -#cbg ad# +#kkl aa# +#cbm ad# #ee@@dd# #ef@@ij# -#ffhlij# +#ffghij# ######## --------------- 141 +-------------- step:145 move:104 6 5 4 3 @ ######## -#kkmaa # -#cbga d# +#kklaa # +#cbma d# #ee@@dd# #ef@@ij# -#ffhlij# +#ffghij# ######## --------------- 142 +-------------- step:146 move:105 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee@@ # #ef@@ij# -#ffhlij# +#ffghij# ######## --------------- 143 +-------------- step:147 move:106 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee@@i # #ef@@ij# -#ffhl^j# +#ffgh^j# ######## --------------- 144 +-------------- step:148 move:107 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# -#ee@@ij# +#kklaad# +#cbmadd# +#ee@@i # #ef@@ij# -#ffhl^^# +#ffg hj# ######## --------------- 145 +-------------- step:149 move:108 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# -#ee@@ij# +#kklaad# +#cbmadd# +#ee@@i # #ef@@ij# -#ffh l^# +#ff ghj# ######## --------------- 146 +-------------- step:150 move:109 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee@@ij# #ef@@ij# -#ff hl^# +#ff gh^# ######## --------------- 147 +-------------- step:151 move:110 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee@@ij# #ef@@ij# -#ff h^l# +#ff g^h# ######## --------------- 148 +-------------- step:152 move:111 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee@@ij# #ef@@ij# -#ff hl# +#ff gh# ######## --------------- 149 +-------------- step:153 move:112 6 5 4 3 @ ######## -#kkmaad# -#cbgadd# +#kklaad# +#cbmadd# #ee ij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 150 +-------------- step:154 move:113 6 5 4 3 @ ######## -#kkmaad# +#kklaad# #cb add# -#eeg ij# +#eem ij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 151 +-------------- step:155 move:113 6 5 4 3 @ ######## -#kkmaad# -#c badd# -#eeg ij# +#kklaad# +#cb add# +#ee mij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 152 +-------------- step:156 move:114 6 5 4 3 @ ######## -#kkmaad# -# cbadd# -#eeg ij# +#kklaad# +#c badd# +#ee mij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 153 +-------------- step:157 move:114 6 5 4 3 @ ######## -#kkmaad# -# cbadd# -#ee gij# +#kklaad# +#c add# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 154 +-------------- step:158 move:115 6 5 4 3 @ ######## -#kkmaad# +#kklaad# # c add# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 155 +-------------- step:159 move:115 6 5 4 3 @ ######## -#kkmaad# +#kklaad# # cadd# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 156 +-------------- step:160 move:116 6 5 4 3 @ ######## -# maad# +# laad# #kkcadd# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 157 +-------------- step:161 move:117 6 5 4 3 @ ######## -# m aad# +# l aad# #kkcadd# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 158 +-------------- step:162 move:117 6 5 4 3 @ ######## -# mcaad# -#kk add# -#eebgij# +#l aad# +#kkcadd# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 159 +-------------- step:163 move:118 6 5 4 3 @ ######## -#m caad# +#l caad# #kk add# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 160 +-------------- step:164 move:118 6 5 4 3 @ ######## -#mc aad# +#lc aad# #kk add# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 161 +-------------- step:165 move:119 6 5 4 3 @ ######## -#mcaa d# +#lcaa d# #kka dd# -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 162 +-------------- step:166 move:120 6 5 4 3 @ ######## -#mcaad # +#lcaad # #kkadd # -#eebgij# +#eebmij# #ef@@ij# -#ff@@hl# +#ff@@gh# ######## --------------- 163 +-------------- step:167 move:121 6 5 4 3 @ ######## -#mcaad # +#lcaad # #kkaddj# -#eebgij# +#eebmij# #ef@@i^# -#ff@@hl# +#ff@@gh# ######## --------------- 164 +-------------- step:168 move:121 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebgi # +#eebmi # #ef@@i^# -#ff@@hl# +#ff@@gh# ######## --------------- 165 +-------------- step:169 move:122 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebg i# +#eebm i# #ef@@^i# -#ff@@hl# +#ff@@gh# ######## --------------- 166 +-------------- step:170 move:123 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebg i# -#ef@@hi# -#ff@@^l# +#eebm i# +#ef@@gi# +#ff@@^h# ######## --------------- 167 +-------------- step:171 move:123 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebghi# +#eebmgi# #ef@@^i# -#ff@@^l# +#ff@@^h# ######## --------------- 168 +-------------- step:172 move:124 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebghi# +#eebmgi# #ef @@i# -#ff @@l# +#ff @@h# ######## --------------- 169 +-------------- step:173 move:125 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -#eebghi# +#eebmgi# #e f@@i# -# ff@@l# +# ff@@h# ######## --------------- 170 +-------------- step:174 move:126 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# #kkaddj# -# bghi# +# bmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 171 +-------------- step:175 move:127 6 5 4 3 @ ######## -#mcaadj# +#lcaadj# # addj# -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 172 +-------------- step:176 move:128 6 5 4 3 @ ######## -#m aadj# +#l aadj# # caddj# -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 173 +-------------- step:177 move:128 6 5 4 3 @ ######## -#m aadj# +#l aadj# #c addj# -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 174 +-------------- step:178 move:129 6 5 4 3 @ ######## -#maa dj# +#laa dj# #ca ddj# -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 175 +-------------- step:179 move:130 6 5 4 3 @ ######## -#maad j# +#laad j# #cadd j# -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 176 +-------------- step:180 move:131 6 5 4 3 @ ######## -#maadj # +#laadj # #caddj # -#kkbghi# +#kkbmgi# #eef@@i# -#eff@@l# +#eff@@h# ######## --------------- 177 +-------------- step:181 move:132 6 5 4 3 @ ######## -#maadj # +#laadj # #caddji# -#kkbghi# +#kkbmgi# #eef@@^# -#eff@@l# +#eff@@h# ######## --------------- 178 +-------------- step:182 move:132 6 5 4 3 @ ######## -#maadji# +#laadji# #caddji# -#kkbgh # +#kkbmg # #eef@@^# -#eff@@l# +#eff@@h# ######## --------------- 179 +-------------- step:183 move:133 6 5 4 3 @ ######## -#maadji# +#laadji# #caddji# -#kkbgh # -#eef@@l# +#kkbmg # +#eef@@h# #eff@@^# ######## --------------- 180 +-------------- step:184 move:133 6 5 4 3 @ ######## -#maadji# +#laadji# #caddji# -#kkbghl# +#kkbmgh# #eef@@^# #eff@@^# ######## --------------- 181 +-------------- step:185 move:134 6 5 4 3 @ ######## -#maadji# +#laadji# #caddji# -#kkbghl# +#kkbmgh# #eef @@# #eff @@# ######## diff --git a/out_smallPuzzle.html b/out_smallPuzzle.html index acda089..41b2eae 100644 --- a/out_smallPuzzle.html +++ b/out_smallPuzzle.html @@ -10,16 +10,16 @@
- - - - + + + +
- 1 + 0 @@ -27,63 +27,15 @@ - 2 + 1 - - - - 3 - - - - - - - - 4 - - - - - - - - 5 - - - - - - - - 6 - - - - - - - - 7 - - - - - 8 - - - - - - - - 9 + 2 diff --git a/printer.cpp b/printer.cpp index e3c8739..426e5bb 100644 --- a/printer.cpp +++ b/printer.cpp @@ -82,13 +82,43 @@ void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out) { out << ""; } -void printSvg(const std::list& puzzleList, std::string preffix, std::string suffix, std::ostream& out) { +void printSvg( + const std::list& puzzleList, + const bool printAll, + std::string preffix, + std::string suffix, + std::ostream& out +) { + static auto replaceTag = [&](const std::string& text, const std::string& tag, const std::string& value) { + return std::regex_replace(text, std::regex(tag), value, std::regex_constants::match_any); + }; + static auto replaceTags = [&](const std::string& text, const std::string& step, const std::string& move) { + return replaceTag(replaceTag(text, "\\{step\\}", step), "\\{move\\}", move); + }; + size_t i = 0; - for (const Puzzle& puzzleStep : puzzleList) { - const std::string pos(toString(++i)); - out << std::regex_replace(preffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); - printSvg(puzzleStep, false, out); - out << std::regex_replace(suffix, std::regex("\\{pos\\}"), pos, std::regex_constants::match_any); + const auto puzzleStepEnd = puzzleList.end(); + auto puzzleStepIt = puzzleList.begin(); + const Puzzle* previousPuzzleStep = &*puzzleStepIt; + ++puzzleStepIt; + while (true) { + if ( + printAll + || + (puzzleStepEnd == puzzleStepIt) + || + (previousPuzzleStep->boardState->moveNumber != puzzleStepIt->boardState->moveNumber) + ) { + const std::string step(toString(i)); + const std::string moveNumber(toString(previousPuzzleStep->boardState->moveNumber)); + out << replaceTags(preffix, step, moveNumber); + printSvg(*previousPuzzleStep, false, out); + out << replaceTags(suffix, step, moveNumber); + } + if (puzzleStepEnd == puzzleStepIt) { break; } + previousPuzzleStep = &*puzzleStepIt; + ++i; + ++puzzleStepIt; } } @@ -163,7 +193,13 @@ void printSvgAnimate(const std::list& puzzleList, std::ostream& out) { } } -void printHtml(const std::list& puzzleList, const size_t& animatedScale, const size_t& staticScale, std::ostream& out) { +void printHtml( + const std::list& puzzleList, + const bool printAll, + const size_t& animatedScale, + const size_t& staticScale, + std::ostream& out +) { Puzzle firstPuzzle = *(puzzleList.begin()); out << "\n" @@ -203,7 +239,8 @@ void printHtml(const std::list& puzzleList, const size_t& animatedScale, } printSvg( puzzleList, - toString(" {pos}\n" @@ -275,7 +312,7 @@ void printText(const Puzzle& puzzle, std::ostream& out) { void printText(const std::list& puzzleList, std::ostream& out) { int pos = -1; for (const Puzzle& puzzleStep : puzzleList) { - out << std::endl << "-------------- " << ++pos << "\n"; + out << std::endl << "-------------- step:" << ++pos << " move:"<< puzzleStep.boardState->moveNumber << "\n"; printText(puzzleStep, out); } } diff --git a/printer.h b/printer.h index 505720e..7d8e051 100644 --- a/printer.h +++ b/printer.h @@ -8,7 +8,13 @@ void printSvg(const Point& point, std::ostream& out); void printSvg(const Block& block, const bool& displayId, std::ostream& out); void printSvg(const BoardState& boardState, const bool& displayId, std::ostream& out); void printSvg(const Puzzle& puzzle, const bool& displayId, std::ostream& out); -void printSvg(const std::list& puzzleList, std::string preffix, std::string suffix, std::ostream& out); +void printSvg( + const std::list& puzzleList, + const bool printAll, + std::string preffix, + std::string suffix, + std::ostream& out +); void printSvgAnimate( const std::string& id, @@ -23,6 +29,7 @@ void printSvgAnimate(const std::list& puzzleList, std::ostream& out); void printHtml( const std::list& puzzleList, + const bool printAll, const size_t& animatedScale, const size_t& staticScale, std::ostream& out diff --git a/puzzle.cpp b/puzzle.cpp index c6689e5..7b654e4 100644 --- a/puzzle.cpp +++ b/puzzle.cpp @@ -4,7 +4,7 @@ std::shared_ptr Move::proceed() const { if (block.id == boardState->runner.id) { // Block to move is the runner return std::make_shared(BoardState { - boardState->numberOfMoves + 1, + boardState->moveNumber + effort, boardState->runner.move(directionToMove), boardState->blocks, }); @@ -19,15 +19,16 @@ std::shared_ptr Move::proceed() const { newBlocks[blockIndex] = block.move(directionToMove); return std::make_shared(BoardState { - boardState->numberOfMoves + 1, + boardState->moveNumber + effort, boardState->runner, std::move(newBlocks), }); } -Move::Move(std::shared_ptr boardState, const Block& block, Direction dir) +Move::Move(std::shared_ptr boardState, const Block& block, const size_t effort, const Direction dir) : boardState{ boardState } , block{ block } + , effort{ effort } , directionToMove{ dir } { } diff --git a/puzzle.h b/puzzle.h index 33423fe..e37a72d 100644 --- a/puzzle.h +++ b/puzzle.h @@ -7,7 +7,7 @@ struct BoardState { // Numer of moves made since the start position - const int numberOfMoves; + const size_t moveNumber; // Puzzle piece to be moved to the goal const Block runner; @@ -24,13 +24,16 @@ class Move { // Block to be moved const Block& block; + // move effort + const size_t effort; + // Direction in which to move block - Direction directionToMove; + const Direction directionToMove; // Returns the BoardState after the move std::shared_ptr proceed() const; - Move(std::shared_ptr boardState, const Block& block, Direction dir); + Move(std::shared_ptr boardState, const Block& block, const size_t effort, const Direction dir); }; enum PuzzleValidation { diff --git a/solver.cpp b/solver.cpp index fff967f..f9c3a2d 100644 --- a/solver.cpp +++ b/solver.cpp @@ -15,10 +15,15 @@ Solver::Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery) const auto initialMoves = moveDiscovery.gatherMoves( puzzle.dimensions, puzzle.boardState, - puzzle.forbiddenSpots + puzzle.forbiddenSpots, + nullptr ); for (auto& move : initialMoves) { - possibleMoveStack.push_back(std::move(move)); + if (0 == move.effort) { + movesToExploreSoon.push_back(std::move(move)); + } else { + movesToExploreLater.push_back(std::move(move)); + } } } @@ -37,11 +42,12 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { auto gatherMovesTime = std::chrono::high_resolution_clock::duration{}; auto insertMovesTime = std::chrono::high_resolution_clock::duration{}; - while (!possibleMoveStack.empty()) { + while (!(movesToExploreSoon.empty() && movesToExploreLater.empty())) { auto start_time = std::chrono::high_resolution_clock::now(); - Move currentMove = *(begin(possibleMoveStack)); - possibleMoveStack.pop_front(); + auto& movesToExplore = (movesToExploreSoon.empty() ? movesToExploreLater : movesToExploreSoon); + Move currentMove = *(begin(movesToExplore)); + movesToExplore.pop_front(); std::shared_ptr boardStateAfterMove = currentMove.proceed(); @@ -52,7 +58,7 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { if (isSolution(*boardStateAfterMove, puzzle.goal)) { *benchmarkOut << "Solution is:" << std::endl; printText(Puzzle{ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, boardStateAfterMove }, *benchmarkOut); - *benchmarkOut << "numberOfMoves: " << boardStateAfterMove->numberOfMoves << std::endl; + *benchmarkOut << "moveNumber: " << boardStateAfterMove->moveNumber << std::endl; const auto hash = hasher.hash(*boardStateAfterMove); *benchmarkOut << "Final hash: " << hash << std::endl; @@ -88,15 +94,15 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { hashTime += (end_time - start_time); start_time = std::chrono::high_resolution_clock::now(); - auto& numberOfMoves = knownPaths[boardStateAfterMoveHash]; + auto& parent = parentOf[boardStateAfterMoveHash]; end_time = std::chrono::high_resolution_clock::now(); lookupTime += (end_time - start_time); - if (numberOfMoves == 0) { - numberOfMoves = boardStateAfterMove->numberOfMoves; - - parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*currentMove.boardState), boardStateAfterMove }); + if (parent.first == 0) { + //unknown paths + parent.first = hasher.hash(*currentMove.boardState); + parent.second = boardStateAfterMove; start_time = std::chrono::high_resolution_clock::now(); @@ -104,7 +110,8 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { const auto newMoves = moveDiscovery.gatherMoves( puzzle.dimensions, std::move(boardStateAfterMove), - puzzle.forbiddenSpots + puzzle.forbiddenSpots, + nullptr ); end_time = std::chrono::high_resolution_clock::now(); @@ -112,7 +119,11 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { start_time = std::chrono::high_resolution_clock::now(); for (auto& move : newMoves) { - possibleMoveStack.push_back(std::move(move)); + if (0 == move.effort) { + movesToExploreSoon.push_back(std::move(move)); + } else { + movesToExploreLater.push_back(std::move(move)); + } } end_time = std::chrono::high_resolution_clock::now(); @@ -123,15 +134,17 @@ std::list Solver::solveBenchmark(std::ostream* benchmarkOut) { return {}; } +#include std::list Solver::solveFast() { // Note: This can be distributed over multiple threads - // Just lock the datastructure possibleMoveStack when popping moves & reinserting moves - // It's not necessary to check the latest state of possibleMoveStack, worst case scenario + // Just lock the datastructure movesToExplore when popping moves & reinserting moves + // It's not necessary to check the latest state of movesToExplore, worst case scenario // a few already-known moves will be queued twice - while (!possibleMoveStack.empty()) { + while (!(movesToExploreSoon.empty() && movesToExploreLater.empty())) { //peek a move - Move currentMove = *(begin(possibleMoveStack)); - possibleMoveStack.pop_front(); + auto& movesToExplore = (movesToExploreSoon.empty() ? movesToExploreLater : movesToExploreSoon); + Move currentMove = *(begin(movesToExplore)); + movesToExplore.pop_front(); std::shared_ptr boardStateAfterMove(currentMove.proceed()); @@ -140,20 +153,24 @@ std::list Solver::solveFast() { } const auto boardStateAfterMoveHash = hasher.hash(*boardStateAfterMove); - auto& numberOfMoves = knownPaths[boardStateAfterMoveHash]; - if (numberOfMoves == 0) { - //unknown paths to add - numberOfMoves = boardStateAfterMove->numberOfMoves; - - parentsOf[boardStateAfterMoveHash].push_back({ hasher.hash(*currentMove.boardState), boardStateAfterMove }); + auto& parent = parentOf[boardStateAfterMoveHash]; + if (parent.first == 0) { + //unknown paths + parent.first = hasher.hash(*currentMove.boardState); + parent.second = boardStateAfterMove; // Queue follow-up moves for (auto& move : moveDiscovery.gatherMoves( puzzle.dimensions, std::move(boardStateAfterMove), - puzzle.forbiddenSpots + puzzle.forbiddenSpots, + ¤tMove.block )) { - possibleMoveStack.push_back(std::move(move)); + if (0 == move.effort) { + movesToExploreSoon.push_back(std::move(move)); + } else { + movesToExploreLater.push_back(std::move(move)); + } } } } @@ -170,12 +187,12 @@ std::list Solver::solution(std::shared_ptr firstBoardState, //add each board step (at front) const auto initialHash = hasher.hash(*(puzzle.boardState)); - HashType stopHash = hasher.hash(*firstBoardState); - while (stopHash != 0 && stopHash != initialHash) { - auto start = parentsOf[stopHash]; - if (start.size() > 0 && start[0].first != 0) { - result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, start[0].second }); - stopHash = start[0].first; + HashType nextHash = hasher.hash(*firstBoardState); + while (nextHash != 0 && nextHash != initialHash) { + auto parent = parentOf[nextHash]; + if (parent.first != 0) { + result.push_front({ puzzle.dimensions, puzzle.goal, puzzle.forbiddenSpots, parent.second }); + nextHash = parent.first; } } diff --git a/solver.h b/solver.h index eb6d7f0..7f461e4 100644 --- a/solver.h +++ b/solver.h @@ -9,7 +9,7 @@ class Solver { public: using HashType = int; - using NumberOfMovesType = typename std::remove_const::type; + using MoveNumberType = typename std::remove_const::type; public: Solver(const Puzzle& puzzle, const MoveDiscovery& moveDiscovery); @@ -27,12 +27,10 @@ class Solver { BoardHasher hasher; // Stores all possible moves to explore - std::list possibleMoveStack; + std::list movesToExploreSoon; + std::list movesToExploreLater; - // Stores the number of moves from the starting state - std::unordered_map knownPaths; - - std::unordered_map>>> parentsOf; + std::unordered_map>> parentOf; const MoveDiscovery& moveDiscovery; }; diff --git a/test.cpp b/test.cpp index 7ce6d58..c498d5a 100644 --- a/test.cpp +++ b/test.cpp @@ -528,7 +528,9 @@ void testPrintScan() { { //print svg Puzzle list std::stringstream strResult; - printSvg(std::list{ tetrisPuzzle, tetrisPuzzle}, "av", "ap", strResult); + printSvg(std::list{ tetrisPuzzle, tetrisPuzzle }, true, "av", "ap", strResult); + strResult << "\n---\n"; + printSvg(std::list{ tetrisPuzzle, tetrisPuzzle }, false, "av", "ap", strResult); assert(compareString(strResult.str(), "av" "\n" @@ -586,6 +588,35 @@ void testPrintScan() { "" "\n" "ap" + "\n---\n" + "av" + "\n" + "\t" + "" + "" + "\n" + "\t" + "" + "" + "" + "" + "" + "\n" + "\t" + "" + "" + "" + "" + "" + "\n" + "\t" + "" + "" + "" + "" + "" + "\n" + "ap" )); } @@ -650,7 +681,7 @@ void testPrintScan() { strResult << "\n---\n"; printSvgAnimate( smallPuzzle, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->moveNumber, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, 7, strResult ); @@ -675,8 +706,8 @@ void testPrintScan() { printSvgAnimate( { smallPuzzle, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, - { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->numberOfMoves, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 1 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->moveNumber, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 0 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, + { smallPuzzle.dimensions, smallPuzzle.goal, smallPuzzle.forbiddenSpots, std::make_shared(BoardState{ smallPuzzle.boardState->moveNumber, { { 0, 0 }, smallPuzzle.boardState->runner.pointSet, "anOtherId" }, { Block({ 1, 1 }, { { 0, 0 } }, "A"), Block({ 0, 0 }, { { 0, 0 } }, "B") } }) }, }, strResult ); @@ -722,9 +753,9 @@ void testPrintScan() { }; std::stringstream strResult; - printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, 0, 20, strResult); + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, true, 0, 20, strResult); strResult << "\n---\n"; - printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, 100, 0, strResult); + printHtml(std::list{ tetrisPuzzle, tetrisPuzzle2}, true, 100, 0, strResult); assert(compareString(strResult.str(), "\n" "\n" "\n" - " 1\n" + " 0\n" "\n" "\t" "" @@ -766,7 +797,7 @@ void testPrintScan() { "" "\n" "\n\n" - " 2\n" + " 1\n" "" "\n" "\t" @@ -908,7 +939,8 @@ void testMoveDiscovery() { const auto newMoves = moveDiscovery.gatherMoves( tinyPuzzle.dimensions, tinyPuzzle.boardState, - tinyPuzzle.forbiddenSpots + tinyPuzzle.forbiddenSpots, + nullptr ); assert(!newMoves.empty() && "At least some moves should be possible"); assert(newMoves.size() == (runnerMoves + blockMoves) && "We should have 6 moves discovered"); @@ -919,7 +951,8 @@ void testMoveDiscovery() { auto newMoves = moveDiscovery.gatherMoves( largePuzzle.dimensions, largePuzzle.boardState, - largePuzzle.forbiddenSpots + largePuzzle.forbiddenSpots, + nullptr ); assert(!newMoves.empty() && "At least some moves should be possible"); //std::cout << "discover " << newMoves.size() << " moves" << std::endl; @@ -930,7 +963,7 @@ void testMoveDiscovery() { void testMoving() { using BoardType = std::remove_const::type; - Move moveRight{ largePuzzle.boardState, largePuzzle.boardState->blocks[0], Direction::Right }; + Move moveRight{ largePuzzle.boardState, largePuzzle.boardState->blocks[0], 1, Direction::Right }; assert(largePuzzle.boardState.get() == moveRight.boardState.get() && "A move should not copy the state, but only reference the original state"); const auto afterMoveRight = moveRight.proceed(); @@ -940,7 +973,7 @@ void testMoving() { assert(largePuzzle.boardState->blocks[0].move(Direction::Down) != afterMoveRight->blocks[0]); assert(largePuzzle.boardState->blocks[0].id == afterMoveRight->blocks[0].id); - assert(largePuzzle.boardState->numberOfMoves + 1 == afterMoveRight->numberOfMoves); + assert(largePuzzle.boardState->moveNumber + 1 == afterMoveRight->moveNumber); { Block middle({ 2, 2 }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, "blockMid"); @@ -1000,7 +1033,7 @@ void testSolver() { assert( 4 == testSolverFx(Solver(tinyPuzzle, moveDiscovery), false, "\n" - "-------------- 0\n" + "-------------- step:0 move:0\n" "3 3\n" "1 1 @\n" "#####\n" @@ -1009,7 +1042,7 @@ void testSolver() { "# #\n" "#####\n" "\n" - "-------------- 1\n" + "-------------- step:1 move:1\n" "3 3\n" "1 1 @\n" "#####\n" @@ -1018,7 +1051,7 @@ void testSolver() { "# #\n" "#####\n" "\n" - "-------------- 2\n" + "-------------- step:2 move:2\n" "3 3\n" "1 1 @\n" "#####\n" @@ -1027,7 +1060,7 @@ void testSolver() { "# A #\n" "#####\n" "\n" - "-------------- 3\n" + "-------------- step:3 move:3\n" "3 3\n" "1 1 @\n" "#####\n" From 0b2c3fa6932168d9f1f0660ffbf93b056a4c7c33 Mon Sep 17 00:00:00 2001 From: Patrick GARCIA Date: Sat, 27 Nov 2021 15:31:10 +0100 Subject: [PATCH 10/10] fix css --- printer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/printer.cpp b/printer.cpp index 426e5bb..627dc3b 100644 --- a/printer.cpp +++ b/printer.cpp @@ -142,7 +142,7 @@ void printSvgAnimate( " to='{to}'" " dur='1s'" " begin='{step}s'" - "fill='freeze'" + " fill='freeze'" "/>\n", std::regex("\\{id\\}"), id