首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >2048游戏:逻辑实现

2048游戏:逻辑实现
EN

Code Review用户
提问于 2018-09-03 18:04:18
回答 2查看 1.5K关注 0票数 8

下面的代码实现了在游戏2048中移动瓷砖的逻辑。“移动”(游戏板::moveRight(),游戏板::moveUp(),等等)方法似乎在重复实现。对于消除“移动”方法中的重复,有何想法?我希望每个“移动”方法的时间复杂度是相等的。我认为,一个轮转板以促进可重用运动的实现会导致非等效的时间复杂性。

代码语言:javascript
复制
#include "GameBoard.h"

GameBoard::GameBoard(std::vector<std::vector<double>> _board) :
    board(std::move(_board)),
    N(board.size())
{
    if (N == 0)
        throw std::runtime_error("Empty board.");
    for (const auto &row : board)
        if (row.size() != N)
            throw std::runtime_error("Invalid board dimensions.");
}

const std::vector<std::vector<double>> &GameBoard::getBoard()
{
    return board;
}

void GameBoard::moveRight()
{
    for (size_t row = 0; row < N; ++row)
    {
        std::vector<bool> hasBeenCombined(N, false);
        for (size_t adjacentCol = N - 1; adjacentCol > 0; --adjacentCol)
        {
            const auto col = adjacentCol - 1;
            const auto value = board[row][col];
            const auto nextNonzeroOrLastColumn = getNextNonzeroOrLastColumn(row, col);
            if (board[row][nextNonzeroOrLastColumn] == 0)
                board[row].back() = value;
            else if (
                board[row][nextNonzeroOrLastColumn] == value &&
                !hasBeenCombined[nextNonzeroOrLastColumn])
            {
                board[row][nextNonzeroOrLastColumn] += value;
                hasBeenCombined[nextNonzeroOrLastColumn] = true;
            }
            else if (nextNonzeroOrLastColumn != adjacentCol)
                board[row][nextNonzeroOrLastColumn - 1] = value;
            else
                continue;
            board[row][col] = 0;
        }
    }
}

void GameBoard::moveLeft()
{
    for (size_t row = 0; row < N; ++row)
    {
        std::vector<bool> hasBeenCombined(N, false);
        for (size_t adjacentCol = 0; adjacentCol < N - 1; ++adjacentCol)
        {
            const auto col = adjacentCol + 1;
            const auto value = board[row][col];
            const auto previousNonzeroOrFirstColumn = getPreviousNonzeroOrFirstColumn(row, col);
            if (board[row][previousNonzeroOrFirstColumn] == 0)
                board[row].front() = value;
            else if (
                board[row][previousNonzeroOrFirstColumn] == value &&
                !hasBeenCombined[previousNonzeroOrFirstColumn])
            {
                board[row][previousNonzeroOrFirstColumn] += value;
                hasBeenCombined[previousNonzeroOrFirstColumn] = true;
            }
            else if (previousNonzeroOrFirstColumn != adjacentCol)
                board[row][previousNonzeroOrFirstColumn + 1] = value;
            else
                continue;
            board[row][col] = 0;
        }
    }
}

void GameBoard::moveDown()
{
    for (size_t col = 0; col < N; ++col)
    {
        std::vector<bool> hasBeenCombined(N, false);
        for (size_t adjacentRow = N - 1; adjacentRow > 0; --adjacentRow)
        {
            const auto row = adjacentRow - 1;
            const auto value = board[row][col];
            const auto nextNonzeroOrLastRow = getNextNonzeroOrLastRow(row, col);
            if (board[nextNonzeroOrLastRow][col] == 0)
                board.back()[col] = value;
            else if (
                board[nextNonzeroOrLastRow][col] == value &&
                !hasBeenCombined[nextNonzeroOrLastRow])
            {
                board[nextNonzeroOrLastRow][col] += value;
                hasBeenCombined[nextNonzeroOrLastRow] = true;
            }
            else if (nextNonzeroOrLastRow != adjacentRow)
                board[nextNonzeroOrLastRow - 1][col] = value;
            else
                continue;
            board[row][col] = 0;
        }
    }
}

void GameBoard::moveUp()
{
    for (size_t col = 0; col < N; ++col)
    {
        std::vector<bool> hasBeenCombined(N, false);
        for (size_t adjacentRow = 0; adjacentRow < N - 1; ++adjacentRow)
        {
            const auto row = adjacentRow + 1;
            const auto value = board[row][col];
            const auto previousNonzeroOrFirstRow = getPreviousNonzeroOrFirstRow(row, col);
            if (board[previousNonzeroOrFirstRow][col] == 0)
                board.front()[col] = value;
            else if (
                board[previousNonzeroOrFirstRow][col] == value &&
                !hasBeenCombined[previousNonzeroOrFirstRow])
            {
                board[previousNonzeroOrFirstRow][col] += value;
                hasBeenCombined[previousNonzeroOrFirstRow] = true;
            }
            else if (previousNonzeroOrFirstRow != adjacentRow)
                board[previousNonzeroOrFirstRow + 1][col] = value;
            else
                continue;
            board[row][col] = 0;
        }
    }
}

size_t GameBoard::getNextNonzeroOrLastColumn(size_t row, size_t col)
{
    while (col < N - 1 && board[row][++col] == 0)
        ;
    return col;
}

size_t GameBoard::getPreviousNonzeroOrFirstColumn(size_t row, size_t col)
{
    while (col > 0 && board[row][--col] == 0)
        ;
    return col;
}

size_t GameBoard::getNextNonzeroOrLastRow(size_t row, size_t col)
{
    while (row < N - 1 && board[++row][col] == 0)
        ;
    return row;
}

size_t GameBoard::getPreviousNonzeroOrFirstRow(size_t row, size_t col)
{
    while (row > 0 && board[--row][col] == 0)
        ;
    return row;
}

相应的标题:

代码语言:javascript
复制
#pragma once

#include <vector>

#ifdef GAME_EXPORTS
    #define GAME_API __declspec(dllexport)
#else
    #define GAME_API __declspec(dllimport)
#endif

class GameBoard
{
    // Order important for construction.
    std::vector<std::vector<double>> board;
    const size_t N;
public:
    GAME_API GameBoard(std::vector<std::vector<double>> board);
    GAME_API const std::vector<std::vector<double>> &getBoard();
    GAME_API void moveRight();
    GAME_API void moveLeft();
    GAME_API void moveDown();
    GAME_API void moveUp();

private:
    size_t getNextNonzeroOrLastColumn(size_t row, size_t col);
    size_t getPreviousNonzeroOrFirstColumn(size_t row, size_t col);
    size_t getNextNonzeroOrLastRow(size_t row, size_t col);
    size_t getPreviousNonzeroOrFirstRow(size_t row, size_t col);
};

以下测试演示了预期的使用:

代码语言:javascript
复制
#include "stdafx.h"
#include "CppUnitTest.h"
#include <GameBoard.h>
#include "assert_utility.h"
#include "test_board_utility.h"

namespace MSTest
{
    TEST_CLASS(GameBoardTester)
    {
    public:
        TEST_METHOD(testInvalidBoardThrows)
        {
            using namespace Microsoft::VisualStudio::CppUnitTestFramework;
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({}); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ {}, {} }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ { 0 }, {} }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ {}, { 0 } }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ { 0 }, { 0 } }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ { 0, 0 }, {} }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ {}, { 0, 0 } }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ { 0, 0 }, { 0 } }); });
            Assert::ExpectException<std::runtime_error>([]() { GameBoard({ { 0 }, { 0, 0 } }); });
            GameBoard(
                {
                    { 0 }
                }
            );
            GameBoard(
                { 
                    { 0, 0 }, 
                    { 0, 0 } 
                });
            GameBoard(
                { 
                    { 0, 0, 0 }, 
                    { 0, 0, 0 },
                    { 0, 0, 0 }
                });
            GameBoard(
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testAllZeros)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

    private:
        void assertAllRotatedTransformTransitions(
            std::vector<std::vector<double>> initial,
            std::string movement,
            std::vector<std::vector<double>> final
        )
        {
            for (int i = 0; i < 4; i++) {
                assertBoardTransition(initial, movement, final);
                initial = rotateClockwise(std::move(initial));
                movement = clockwiseMovementTransform(std::move(movement));
                final = rotateClockwise(std::move(final));
            }
        }

        void assertBoardTransition(
            const std::vector<std::vector<double>> &initial,
            const std::string &movement,
            const std::vector<std::vector<double>> &final
        )
        {
            GameBoard board(initial);
            for (const auto &c : movement)
                switch (c)
                {
                case 'r':
                case 'R':
                    board.moveRight();
                    break;
                case 'd':
                case 'D':
                    board.moveDown();
                    break;
                case 'l':
                case 'L':
                    board.moveLeft();
                    break;
                case 'u':
                case 'U':
                    board.moveUp();
                    break;
                }
            assertAreEqual(final, board.getBoard());
        }

        std::string clockwiseMovementTransform(std::string movement)
        {
            for (auto &c : movement)
                switch (c)
                {
                case 'r':
                case 'R':
                    c = 'd';
                    break;
                case 'd':
                case 'D':
                    c = 'l';
                    break;
                case 'l':
                case 'L':
                    c = 'u';
                    break;
                case 'u':
                case 'U':
                    c = 'r';
                    break;
                }
            return movement;
        }

    public:
        TEST_METHOD(testOneTwo)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 2, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testTwoTwos)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 2, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 2, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 2, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testThreeTwos)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 2, 2, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 2, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testFourTwos)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 2, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 4, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testTwoUnequals)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 4, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 4, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 4, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 0, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 2, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testThreeUnequals)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 4, 8, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 2, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 4, 0, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 2, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 2, 0, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 2, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 2, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 2, 4, 8 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testFourUnequals)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 4, 8, 16 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 2, 4, 8, 16 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testCombinesOnlyOnce)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 4, 2, 2, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 4, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 4, 2, 0, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 4, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 4, 0, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 4, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
            assertAllRotatedTransformTransitions(
                {
                    { 0, 4, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "r",
                {
                    { 0, 0, 4, 4 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testTwiceAllZeros)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "rr",
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testThreeCombos)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 8, 4, 2, 2 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                "rrr",
                {
                    { 0, 0, 0, 16 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }

        TEST_METHOD(testUnfortunateBoard)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 4, 2, 4 },
                    { 4, 2, 4, 2 },
                    { 2, 4, 2, 4 },
                    { 4, 2, 4, 2 }
                },
                "rdlu",
                {
                    { 2, 4, 2, 4 },
                    { 4, 2, 4, 2 },
                    { 2, 4, 2, 4 },
                    { 4, 2, 4, 2 }
                });
        }

        TEST_METHOD(testVeryFortunateBoard)
        {
            assertAllRotatedTransformTransitions(
                {
                    { 2, 2, 2, 2 },
                    { 2, 2, 2, 2 },
                    { 2, 2, 2, 2 },
                    { 2, 2, 2, 2 }
                },
                "rdlu",
                {
                    { 32, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                });
        }
    };
};

包含测试的存储库可以找到这里

EN

回答 2

Code Review用户

回答已采纳

发布于 2018-09-06 04:02:50

廷塔法尔中汲取灵感,我实现了一个方法(游戏板::moveAlong),它结合了每个方向共有的平铺运动逻辑,以消除重复。

代码语言:javascript
复制
#include "GameBoard.h"

GameBoard::GameBoard(std::vector<std::vector<double>> _board) :
    board(std::move(_board)),
    N(board.size())
{
    if (N == 0)
        throw std::runtime_error("Empty board.");
    for (const auto &row : board)
        if (row.size() != N)
            throw std::runtime_error("Invalid board dimensions.");
}

const std::vector<std::vector<double>> &GameBoard::getBoard()
{
    return board;
}

void GameBoard::moveRight()
{
    moveAlong(&GameBoard::toTheRight);
}

void GameBoard::moveLeft()
{
    moveAlong(&GameBoard::toTheLeft);
}

void GameBoard::moveDown()
{
    moveAlong(&GameBoard::downwards);
}

void GameBoard::moveUp()
{
    moveAlong(&GameBoard::upwards);
}

void GameBoard::moveAlong(double &(GameBoard::*direction)(size_t slice, size_t element))
{
    for (size_t slice = 0; slice < N; ++slice) {
        std::vector<bool> hasBeenCombined(N, false);
        for (size_t adjacentElement = N - 1; adjacentElement > 0; --adjacentElement)
        {
            const auto element = adjacentElement - 1;
            const auto value = (this->*direction)(slice, element);
            auto nextNonzeroOrLastElement = element;
            while (nextNonzeroOrLastElement < N - 1 && (this->*direction)(slice, ++nextNonzeroOrLastElement) == 0)
                ;
            if ((this->*direction)(slice, nextNonzeroOrLastElement) == 0)
                (this->*direction)(slice, N - 1) = value;
            else if (
                (this->*direction)(slice, nextNonzeroOrLastElement) == value &&
                !hasBeenCombined[nextNonzeroOrLastElement])
            {
                (this->*direction)(slice, nextNonzeroOrLastElement) += value;
                hasBeenCombined[nextNonzeroOrLastElement] = true;
            }
            else if (nextNonzeroOrLastElement != adjacentElement)
                (this->*direction)(slice, nextNonzeroOrLastElement - 1) = value;
            else
                continue;
            (this->*direction)(slice, element) = 0;
        }
    }
}

double & GameBoard::toTheRight(size_t slice, size_t element)
{
    return board[slice][element];
}

double & GameBoard::toTheLeft(size_t slice, size_t element)
{
    return board[slice][N - 1 - element];
}

double & GameBoard::upwards(size_t slice, size_t element)
{
    return board[N - 1 - element][slice];
}

double & GameBoard::downwards(size_t slice, size_t element)
{
    return board[element][slice];
}

这实现了我消除“迁移”方法之间的重复(至少是一些)的初衷。然而,非静态成员函数的传递似乎很奇怪,但我发现它在访问板时很有用。我认为代码将受益于帕帕加加的回答中演示的一些标准算法库函数,但我对这些函数还不太熟悉。

票数 0
EN

Code Review用户

发布于 2018-09-04 00:24:55

要做到这一点,一种方法是拥有一个Cell类。通过这种方式,您可以使您的板成为一个vector<vector<Cell*>>,您可以拥有一个按行组织的集合和一个按列组织的集合。开销最小,因为它们是作为指针存储的。

现在,一个函数可以通过传递对集合的引用和使用集合的正向或反向迭代器的指示来完成所有的移动。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/203041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档