Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 俄罗斯方块旋转算法_Algorithm_Rotation_Tetris - Fatal编程技术网

Algorithm 俄罗斯方块旋转算法

Algorithm 俄罗斯方块旋转算法,algorithm,rotation,tetris,Algorithm,Rotation,Tetris,代表和旋转俄罗斯方块游戏片段的最佳算法(和解释)是什么?我总是发现工件旋转和表示方案令人困惑 大多数俄罗斯方块游戏似乎在每次轮换时都会使用一种天真的“重制方块数组”: 但是,有些人使用预先构建的编码数字和位移位来表示每个片段: 有没有一种方法可以通过数学来实现这一点(不确定这种方法是否适用于基于单元的电路板)?形状数量有限,因此我会使用固定的表格,而不进行计算。这样可以节省时间 但也有旋转算法 选择一个中心点并旋转pi/2 如果一个块从(1,2)开始,它将顺时针移动到(2,-1)和(-1,-

代表和旋转俄罗斯方块游戏片段的最佳算法(和解释)是什么?我总是发现工件旋转和表示方案令人困惑

大多数俄罗斯方块游戏似乎在每次轮换时都会使用一种天真的“重制方块数组”:

但是,有些人使用预先构建的编码数字和位移位来表示每个片段:


有没有一种方法可以通过数学来实现这一点(不确定这种方法是否适用于基于单元的电路板)?

形状数量有限,因此我会使用固定的表格,而不进行计算。这样可以节省时间

但也有旋转算法

选择一个中心点并旋转pi/2

如果一个块从(1,2)开始,它将顺时针移动到(2,-1)和(-1,-2)和(-1,2)。 将此应用于每个块,然后旋转工件

每个x都是前一个y,每个y都是前一个x。其中给出了以下矩阵:

[  0   1 ]
[ -1   0 ]
对于逆时针旋转,请使用:

[  0  -1 ]
[  1   0 ]

我使用了一个形状位置和一组四个坐标来表示所有形状中的四个点。由于它位于二维空间中,因此可以轻松地将二维旋转矩阵应用于点


这些点是div,因此它们的css类从关闭变为打开。(这是在清除css类的上次旋转位置之后。)

就我个人而言,我总是用手来表示旋转-只有很少的形状,这样编码很容易。基本上我有(作为伪代码)


至少在概念上-直接在形状中的点的多维数组也可以做到这一点:)

因为每个形状只有4个可能的方向,为什么不为形状使用一个状态数组,而顺时针或逆时针旋转只是增加或减少形状状态的索引(索引为环绕)?我认为这可能比执行旋转计算之类的更快。

这就是我最近在基于jQuery/CSS的俄罗斯方块游戏中所做的

计算出块的中心(用作枢轴点),即块形状的中心。 称之为(px,py)

构成块形状的每个砖都将围绕该点旋转。 对于每个砖,可以应用以下计算

如果每个砖的宽度和高度为q,砖的当前位置(左上角)为(x1,y1),新砖的位置为(x2,y2):

要反向旋转,请执行以下操作:

x2 = (px + py - y1 - q)

y2 = (x1 + py - px)
此计算基于二维仿射矩阵变换。
如果您对我是如何做到这一点感兴趣,请告诉我。

如果您是在python中进行此操作的,则使用基于单元格的方法而不是坐标对,旋转嵌套列表非常简单

rotate = lambda tetrad: zip(*tetrad[::-1])

# S Tetrad
tetrad = rotate([[0,0,0,0], [0,0,0,0], [0,1,1,0], [1,1,0,0]])

我从矩阵旋转推导出一个旋转算法。总而言之:如果您有组成块的所有单元格的坐标列表,例如[(0,1),(1,1),(2,1),(3,1)]或[(1,0),(0,1),(1,1),(2,1)]:

您可以使用

x_new = y_old
y_new = 1 - (x_old - (me - 2))
用于顺时针旋转和

x_new = 1 - (y_old - (me - 2))
y_new = x_old

用于逆时针旋转
me
是块的最大范围,即i块为
4
,O块为
2
,所有其他块为
3

只能通过对矩阵应用数学运算来旋转矩阵。如果你有一个矩阵,说:

Mat A = [1,1,1]
        [0,0,1]
        [0,0,0]
若要旋转它,请将其乘以转置,然后再乘以该矩阵([I]dentity[H]orizontaly[M]irrored):

然后您将有:

Mat Rotation = Trn(A)*IHM(A) = [1,0,0]*[0,0,1] = [0,0,1]
                               [1,0,0] [0,1,0] = [0,0,1]
                               [1,1,0] [1,0,0] = [0,1,1]

注:旋转中心将是矩阵的中心,在本例中为(2,2)。

对于3x3大小的俄罗斯方块 翻转你作品的x和y 然后交换外部列
有一段时间,当我试图弄清楚轮换如何适用于我的俄罗斯方块游戏时,我发现了这个问题,这是我在堆栈溢出中发现的第一个问题。尽管这个问题已经很老了,但我认为我的输入将帮助其他试图从算法上解决这个问题的人。首先,我不同意硬编码每个片段和旋转会更容易。Gamecat的回答是正确的,但我想详细说明一下。以下是我在Java中用来解决旋转问题的步骤

  • 对于每个形状,确定其原点位置。我使用图表上的点来指定原点。请记住,根据您的实现,您可能必须在每次用户移动工件时修改原点

  • 旋转假定原点位于点(0,0),因此必须先平移每个块,然后才能旋转。例如,假设原点当前位于点(4,5)。这意味着在旋转形状之前,每个块必须在x坐标中平移-4,在y坐标中平移-5,才能相对于(0,0)进行平移

  • 在Java中,典型的坐标平面从最左上角的点(0,0)开始,然后向右和向下增加。为了在我的实现中对此进行补偿,我在旋转之前将每个点乘以-1

  • 下面是我用来计算逆时针旋转后新的x和y坐标的公式。有关这方面的更多信息,我想查看上的维基百科页面。x'和y'是新坐标:

    x'=x*cos(PI/2)-y*sin(PI/2)和y'=x*sin(PI/2)+y*cos(PI/2)

  • 对于最后一步,我只是按照相反的顺序完成了步骤2和步骤3。所以我再次将结果乘以-1,然后将块转换回它们的原始坐标

  • 下面是一些代码,这些代码对我(用Java)了解如何用您的语言实现这一点非常有用:

    public synchronized void rotateLeft(){
    
        Point[] rotatedCoordinates = new Point[MAX_COORDINATES];
    
        for(int i = 0; i < MAX_COORDINATES; i++){
    
            // Translates current coordinate to be relative to (0,0)
            Point translationCoordinate = new Point(coordinates[i].x - origin.x, coordinates[i].y - origin.y);
    
            // Java coordinates start at 0 and increase as a point moves down, so
            // multiply by -1 to reverse
            translationCoordinate.y *= -1;
    
            // Clone coordinates, so I can use translation coordinates
            // in upcoming calculation
            rotatedCoordinates[i] = (Point)translationCoordinate.clone();
    
            // May need to round results after rotation
            rotatedCoordinates[i].x = (int)Math.round(translationCoordinate.x * Math.cos(Math.PI/2) - translationCoordinate.y * Math.sin(Math.PI/2)); 
            rotatedCoordinates[i].y = (int)Math.round(translationCoordinate.x * Math.sin(Math.PI/2) + translationCoordinate.y * Math.cos(Math.PI/2));
    
            // Multiply y-coordinate by -1 again
            rotatedCoordinates[i].y *= -1;
    
            // Translate to get new coordinates relative to
            // original origin
            rotatedCoordinates[i].x += origin.x;
            rotatedCoordinates[i].y += origin.y;
    
            // Erase the old coordinates by making them black
            matrix.fillCell(coordinates[i].x, coordinates[i].y, Color.black);
    
        }
        // Set new coordinates to be drawn on screen
        setCoordinates(rotatedCoordinates.clone());
    }
    
    public-synchronized void rotateLeft(){
    点[]旋转坐标=新点[最大坐标];
    对于(int i=0;iMat A = [1,1,1]
            [0,0,1]
            [0,0,0]
    
    IHM(A) = [0,0,1]
             [0,1,0]
             [1,0,0]
    
    Mat Rotation = Trn(A)*IHM(A) = [1,0,0]*[0,0,1] = [0,0,1]
                                   [1,0,0] [0,1,0] = [0,0,1]
                                   [1,1,0] [1,0,0] = [0,1,1]
    
    public synchronized void rotateLeft(){
    
        Point[] rotatedCoordinates = new Point[MAX_COORDINATES];
    
        for(int i = 0; i < MAX_COORDINATES; i++){
    
            // Translates current coordinate to be relative to (0,0)
            Point translationCoordinate = new Point(coordinates[i].x - origin.x, coordinates[i].y - origin.y);
    
            // Java coordinates start at 0 and increase as a point moves down, so
            // multiply by -1 to reverse
            translationCoordinate.y *= -1;
    
            // Clone coordinates, so I can use translation coordinates
            // in upcoming calculation
            rotatedCoordinates[i] = (Point)translationCoordinate.clone();
    
            // May need to round results after rotation
            rotatedCoordinates[i].x = (int)Math.round(translationCoordinate.x * Math.cos(Math.PI/2) - translationCoordinate.y * Math.sin(Math.PI/2)); 
            rotatedCoordinates[i].y = (int)Math.round(translationCoordinate.x * Math.sin(Math.PI/2) + translationCoordinate.y * Math.cos(Math.PI/2));
    
            // Multiply y-coordinate by -1 again
            rotatedCoordinates[i].y *= -1;
    
            // Translate to get new coordinates relative to
            // original origin
            rotatedCoordinates[i].x += origin.x;
            rotatedCoordinates[i].y += origin.y;
    
            // Erase the old coordinates by making them black
            matrix.fillCell(coordinates[i].x, coordinates[i].y, Color.black);
    
        }
        // Set new coordinates to be drawn on screen
        setCoordinates(rotatedCoordinates.clone());
    }
    
    oldShapeMap[3][3] = {{1,1,0},
                         {0,1,0},
                         {0,1,1}};
    
    bool newShapeMap[3][3] = {0};
    int gridSize = 3;
    
    for(int i=0;i<gridSize;i++)
        for(int j=0;j<gridSize;j++)
            newShapeMap[i][j] = oldShapeMap[j][(gridSize-1) - i];
    /*newShapeMap now contain:    
                                   {{0,0,1},
                                    {1,1,1},
                                    {1,0,0}};
    
    */ 
    
    require 'matrix'
    shape = shape.map{|arr|(Matrix[arr] * Matrix[[0,-1],[1,0]]).to_a.flatten}
    
    private void rotateClockwise()
    {
        if(rotatable > 0)   //We don't rotate tetromino O. It doesn't have central square.
        {
            int i = y1 - y0;
            y1 = (y0 + x1) - x0;
            x1 = x0 - i;
            i = y2 - y0;
            y2 = (y0 + x2) - x0;
            x2 = x0 - i;
            i = y3 - y0;
            y3 = (y0 + x3) - x0;
            x3 = x0 - i;  
        }
    }
    
    private void rotateCounterClockwise()
    {
        if(rotatable > 0)
        {
            int i = y1 - y0;
            y1 = (y0 - x1) + x0;
            x1 = x0 + i;
            i = y2 - y0;
            y2 = (y0 - x2) + x0;
            x2 = x0 + i;
            i = y3 - y0;
            y3 = (y0 - x3) + x0;
            x3 = x0 + i;
        }
    }
    
    originalMatrix = 
    [0,   0,   1]
    [1,   1,   1]
    
    clockwise90DegreesRotatedMatrix = reverseTheOrderOfColumns(Transpose(originalMatrix))
    
    anticlockwise90DegreesRotatedMatrix = reverseTheOrderOfRows(Transpose(originalMatrix))
    
    originalMatrix = 
      x    y    z
    a[0,   0,   1]
    b[1,   1,   1]
    
    transposed = transpose(originalMatrix)
      a   b
    x[0,  1]
    y[0,  1]
    z[1,  1]
    
    counterClockwise90DegreesRotated = reverseTheOrderOfRows(transposed)
      a   b
    z[1,  1]
    y[0,  1]
    x[0,  1]
    
    clockwise90DegreesRotated = reverseTheOrderOfColumns(transposed)
      b   a
    x[1,  0]
    y[1,  0]
    z[1,  1]
    
    pieces = [
        [(0,0),(0,1),(0,2),(0,3)],
        [(0,0),(0,1),(1,0),(1,1)],
        [(1,0),(0,1),(1,1),(1,2)],
        [(0,0),(0,1),(1,0),(2,0)],
        [(0,0),(0,1),(1,1),(2,1)],
        [(0,1),(1,0),(1,1),(2,0)]
    ]
    
    def get_piece_dimensions(piece):
        max_r = max_c = 0
        for point in piece:
            max_r = max(max_r, point[0])
            max_c = max(max_c, point[1])
        return max_r, max_c
    
    def rotate_piece(piece):
        max_r, max_c = get_piece_dimensions(piece)
        new_piece = []
        for r in range(max_r+1):
            for c in range(max_c+1):
                if (r,c) in piece:
                    new_piece.append((c, max_r-r))
        return new_piece
    
    private static char[][] rotateMatrix(char[][] m) {
        final int h = m.length;
        final int w = m[0].length;
        final char[][] t = new char[h][w];
    
        for(int y = 0; y < h; y++) {
            for(int x = 0; x < w; x++) {
                t[w - x - 1][y]  = m[y][x];
            }
        }
        return t;
    }