模拟立方体的滚动并记录路径

立方体滚动

一个立方体每个面都有一种颜色,颜色分别用 1,2,3,4,5,6 表示,立方体在一块 n*n 的方格棋盘上滚动,棋盘上的格子会被立方体的底面染色,给出棋盘的维度大小及立方体在棋盘上的滚动路径,输出路径上格子的颜色。

立方体初始状态及下面示例的输入对应路径如下图:

cube-roll.png

输入:

5
S # # # .
. . . # .
E # . # #
. # . . #
. # # # #

说明:

第一行输入一个整数 n ,代表棋盘的维度是 n*n

之后有 n 行输入,表示棋盘上的占位符,各符号有如下含义:

  • S ,表示起点
  • # ,表示立方体经过该格子
  • . ,表示棋盘上其他的格子(不在立方体路径上)

注意:由于只用字符表示路径上的位置,并不知道滚动位置的先后顺序,故必须对输入有要求:只能够由输入推断得到一条路径,不能产生歧义,否则视为不合法的输入

代码:


import java.util.Scanner;

class Cube {
    int up = 1;
    int down = 6;
    int left = 5;
    int right = 2;
    int front = 3;
    int back = 4;

    public void rollRight() { // 向右滚动

        int t1 = 0, t2 = 0; // 临时变量,用于保存被覆盖的值

        t1 = down;
        down = right; // 底面由之前的右面替代
        t2 = left;
        left = t1; // 左面由之前的下面替代
        t1 = up;
        up = t2; // 上面由之前的左面替代
        right = t1; // 右面由之前的上面替代

        // 前面和后面都不会变

    }
    // 下面的滚动与上面的操作是类似的,不再注释

    public void rollLeft() {

        int t1 = 0, t2 = 0;

        t1 = down;
        down = left;
        t2 = right;
        right = t1;
        t1 = up;
        up = t2;
        left = t1;

    }

    public void rollUp() {

        int t1 = 0, t2 = 0;

        t1 = down;
        down = back;
        t2 = front;
        front = t1;
        t1 = up;
        up = t2;
        back = t1;

    }

    public void rollDown() {

        int t1 = 0, t2 = 0;

        t1 = down;
        down = front;
        t2 = back;
        back = t1;
        t1 = up;
        up = t2;
        front = t1;

    }

    // 用于测试,方便打印立方体
    @Override
    public String toString() {
        return "Cube [up=" + up + ", down=" + down + ", left=" + left + ", right=" + right + ", front=" + front
                + ", back=" + back + "]";
    }

}

class Position { // 棋盘上坐标的抽象

    int x = 0;
    int y = 0;

    Position(int x, int y) {
        this.x = x;
        this.y = y;

    }

    // 用于测试,方便打印位置
    @Override
    public String toString() {
        return "Position [x=" + x + ", y=" + y + "]";
    }

}

class Board { // 棋盘抽象

    char[][] board; // 使用二维数组表示棋盘
    boolean[][] visited; // 用于表示棋盘上的位置是否被访问过,visited[i][j]=true 表示坐标 (i,j) 被访问过,否则没访问过
    // up:1
    // down:2
    // left:3
    // right:4
    short[][] nextDirection; // 棋盘上每个位置上的下一个滚动的方向,nextDirection[i][j]=1 表示在 (i,j) 时下一个方向要向上滚动
    int dimension = 0; // 棋盘的维度

    Board(int n) { // 初始化
        board = new char[n][n];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {

                board[i][j] = '.';

            }

        visited = new boolean[n][n];
        nextDirection = new short[n][n];
        dimension = n;
    }

    Position getStartPosition() { // 找出起始位置

        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++) {
                if (board[i][j] == 'S') {
                    visited[i][j] = true;
                    return new Position(i, j);
                }

            }
        }

        throw new RuntimeException("invalid rolling path : no start");
    }

    Position getNextPosition(Position pos) { // 在位置 pos 时,其下一个滚动到的位置

        int i = pos.x, j = pos.y;

        Position resPosition = null;

        // 检查 pos 的右侧是否是下一个位置
        if (j < board.length - 1 && board[i][j + 1] != '.' && visited[i][j + 1] == false) {
            nextDirection[i][j] = 4; // 当前位置 pos 的下一个方向就是向右
            resPosition = new Position(i, j + 1);
        } else if (j > 0 && board[i][j - 1] != '.' && visited[i][j - 1] == false) {
            nextDirection[i][j] = 3;
            resPosition = new Position(i, j - 1);
        } else if (i < board.length - 1 && board[i + 1][j] != '.' && visited[i + 1][j] == false) {
            nextDirection[i][j] = 2;
            resPosition = new Position(i + 1, j);
        } else if (i > 0 && board[i - 1][j] != '.' && visited[i - 1][j] == false) {
            nextDirection[i][j] = 1;
            resPosition = new Position(i - 1, j);
        } else {
            throw new RuntimeException("invalid rolling path");
        }

        visited[i][j] = true; // 标记当前位置 pos 被访问过

        return resPosition;

    }

    void printBoard() { // 打印棋盘
        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++) {
                System.out.print(board[i][j] + " ");
            }
            System.out.println();

        }

    }

}

public class RollingCube {

    public static void main(String[] args) {

        Cube cube = new Cube();

        Board board;

        Scanner in = new Scanner(System.in);
        int n = in.nextInt(); // 棋盘维度从键盘输入获取

        board = new Board(n);

        // 将输入的路径记录在棋盘中
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                board.board[i][j] = in.next().charAt(0);
            }

        }

        board.printBoard();

        Position pos = board.getStartPosition(); // 找到起始位置

        int x = pos.x, y = pos.y;

        while (board.board[x][y] != 'E') { // 只要没到终点,一直滚动

            board.board[x][y] = String.valueOf(cube.down).charAt(0); // 将立方体的下面(底面)的值记录到棋盘上

            pos = board.getNextPosition(pos); // 下一个滚动位置

            switch (board.nextDirection[x][y]) { // 下一个方向往哪滚动
            case 1:
                cube.rollUp();
                break;
            case 2:
                cube.rollDown();
                break;
            case 3:
                cube.rollLeft();
                break;
            case 4:
                cube.rollRight();
                break;
            }

            // 滚动到下一个位置
            x = pos.x;
            y = pos.y;

        }

        // 上面while循环跳出时,立方体在终点没有将底面的值记录到棋盘上
        // 在这里记录
        board.board[x][y] = String.valueOf(cube.down).charAt(0);

        board.printBoard();

    }

}

示例输入的结果:

6 2 1 5 . 
. . . 3 . 
1 2 . 2 6 
. 4 . . 4 
. 5 6 2 1 

测试用例输入:

5
# # # # #
# . . . #
# . S # #
# . . . .
# # # # E

预期输出:

6 5 1 2 6
4 . . . 4
1 . 6 2 1
3 . . . .
6 5 1 2 6

程序输出:

6 5 1 2 6 
4 . . . 4 
1 . 6 2 1 
3 . . . . 
6 5 1 2 6 

你可能感兴趣的:(模拟立方体的滚动并记录路径)