俄罗斯方块棋子旋转算法

发布于 2024-07-08 01:07:22 字数 487 浏览 5 评论 0原文

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

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

http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris

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

http://www.codeplex.com/wintris

有没有一种方法可以使用数学来做到这一点(不确定这是否适用于基于单元的主板)?

What are the best algorithms (and explanations) for representing and rotating the pieces of a tetris game? I always find the piece rotation and representation schemes confusing.

Most tetris games seem to use a naive "remake the array of blocks" at each rotation:

http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris

However, some use pre-built encoded numbers and bit shifting to represent each piece:

http://www.codeplex.com/wintris

Is there a method to do this using mathematics (not sure that would work on a cell based board)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

兮颜 2024-07-15 01:07:23

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

Mat A = [1,1,1]
        [0,0,1]
        [0,0,0]

要旋转它,将其乘以它的转置,然后乘以这个矩阵([I]dentity [H]orizo​​ntaly [M]irrored):

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]

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

You can rotate a matrix only by applying mathematical operations to it. If you have a matrix, say:

Mat A = [1,1,1]
        [0,0,1]
        [0,0,0]

To rotate it, multiply it by its transpose and then by this matrix ([I]dentity [H]orizontaly [M]irrored):

IHM(A) = [0,0,1]
         [0,1,0]
         [1,0,0]

Then you'll have:

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]

Note: Center of rotation will be the center of the matrix, in this case at (2,2).

£冰雨忧蓝° 2024-07-15 01:07:23

表示

表示最小矩阵中的每个部分,其中 1 代表四方体占据的空间,0 代表空的空间。 例子:

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]

输入图像描述这里

Representation

Represent each piece in the minimum matrix where 1's represent spaces occupied by the tetriminoe and 0's represent empty space. Example:

originalMatrix = 
[0,   0,   1]
[1,   1,   1]

enter image description here

Rotation Formula

clockwise90DegreesRotatedMatrix = reverseTheOrderOfColumns(Transpose(originalMatrix))

anticlockwise90DegreesRotatedMatrix = reverseTheOrderOfRows(Transpose(originalMatrix))

Illustration

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]

enter image description here

clockwise90DegreesRotated = reverseTheOrderOfColumns(transposed)
  b   a
x[1,  0]
y[1,  0]
z[1,  1]

enter image description here

我不吻晚风 2024-07-15 01:07:23

由于每个形状只有 4 个可能的方向,为什么不使用形状的状态数组,并按 CW 或 CCW 旋转简单地增加或减少形状状态的索引(对索引进行环绕)? 我认为这可能比执行旋转计算等更快。

Since there are only 4 possible orientations for each shape, why not use an array of states for the shape and rotating CW or CCW simply increments or decrements the index of the shape state (with wraparound for the index)? I would think that might be quicker than performing rotation calculations and whatnot.

如何视而不见 2024-07-15 01:07:23

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

 0123       012
0....      0.#.
1####  or  1###
2....      2...
3....

计算新坐标

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,O 块为 3 > 对于所有其他块。

I derived a rotation algorithm from matrix rotations here. To sum it up: If you have a list of coordinates for all cells that make up the block, e.g. [(0, 1), (1, 1), (2, 1), (3, 1)] or [(1, 0), (0, 1), (1, 1), (2, 1)]:

 0123       012
0....      0.#.
1####  or  1###
2....      2...
3....

you can calculate the new coordinates using

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

for clockwise rotation and

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

for counter-clockwise rotation. me is the maximum extent of the block, i.e. 4 for I-blocks, 2 for O-blocks and 3 for all other blocks.

苦笑流年记忆 2024-07-15 01:07:23

如果您在 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]])

If you're doing this in python, cell-based instead of coordinate pairs it's very simple to rotate a nested list.

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]])
白云不回头 2024-07-15 01:07:23

如果我们假设四格骨牌的中心方块的坐标 (x0, y0) 保持不变,那么 Java 中其他 3 个方块的旋转将如下所示:

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;
    }
}

If we assume that the central square of the tetromino has coordinates (x0, y0) which remains unchanged then the rotation of the other 3 squares in Java will look like this:

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;
    }
}
新雨望断虹 2024-07-15 01:07:23

适用于 3x3 大小的俄罗斯方块
翻转你的作品的 x 和 y
然后交换外列
这就是我有一段时间想出来的

for 3x3 sized tetris pieces
flip x and y of your piece
then swap the outer columns
that's what I figured out some time

筱果果 2024-07-15 01:07:23

我对所有形状中的四个点使用了形状位置和四个坐标集。 由于它位于 2D 空间中,因此您可以轻松地将 2D 旋转矩阵应用于这些点。

这些点是 div,因此它们的 css 类从关闭变为打开。 (这是在清除了上一轮的 css 类之后的结果。)

I have used a shape position and set of four coordinates for the four points in all the shapes. Since it's in 2D space, you can easy apply a 2D rotational matrice to the points.

The points are divs so their css class is turned from off to on. (this is after clearing the css class of where they were last turn.)

記憶穿過時間隧道 2024-07-15 01:07:23

如果数组大小为 3*3 ,则逆时针方向旋转它的最简单方法是:

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}};

*/ 

If array size is 3*3 ,than the simplest way to rotate it for example in anti-clockwise direction is:

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}};

*/ 
此岸叶落 2024-07-15 01:07:23

Python:

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

Python:

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
黑凤梨 2024-07-15 01:07:23

至少在 Ruby 中,您实际上可以使用矩阵。 将您的块形状表示为数组的嵌套数组,例如 [[0,1],[0,2],[0,3]]

require 'matrix'
shape = shape.map{|arr|(Matrix[arr] * Matrix[[0,-1],[1,0]]).to_a.flatten}

但是,我同意对形状进行硬编码是可行的,因为有 7 种形状和 4 种状态每行 = 28 行,而且永远不会超过这个数。

有关这方面的更多信息,请参阅我的博客文章:
https://content.pivotal。 io/blog/the-simplest-thing-that-c​​ould-possously-work-in-tetris 以及 https://github.com/andrewfader/Tetronimo

In Ruby, at least, you can actually use matrices. Represent your piece shapes as nested arrays of arrays like [[0,1],[0,2],[0,3]]

require 'matrix'
shape = shape.map{|arr|(Matrix[arr] * Matrix[[0,-1],[1,0]]).to_a.flatten}

However, I agree that hard-coding the shapes is feasible since there are 7 shapes and 4 states for each = 28 lines and it will never be any more than that.

For more on this see my blog post at
https://content.pivotal.io/blog/the-simplest-thing-that-could-possibly-work-in-tetris and a completely working implementation (with minor bugs) at https://github.com/andrewfader/Tetronimo

自我难过 2024-07-15 01:07:23

在 Java 中:

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;
}

作为 Java 中的单页应用程序的简单俄罗斯方块实现:
https://github.com/vadimv/rsp-tetris

In Java:

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;
}

A simple Tetris implementation as a single-page application in Java:
https://github.com/vadimv/rsp-tetris

那伤。 2024-07-15 01:07:22

当我试图弄清楚旋转如何适用于我的俄罗斯方块游戏时,这是我在堆栈溢出上发现的第一个问题。 尽管这个问题很老了,但我认为我的输入将帮助其他人尝试通过算法解决这个问题。 首先,我不同意对每个部分进行硬编码和旋转会更容易。 Gamecat的答案是正确的,但我想详细说明一下。 以下是我在 Java 中解决旋转问题的步骤。

  1. 对于每个形状,确定其原点在哪里。 我使用此页面中图表上的点来指定我的原点。 请记住,根据您的实现,您可能必须在用户每次移动该块时修改原点。

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

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

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

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

  5. 对于最后一步,我只是以相反的顺序执行了步骤 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());
}

此方法是将您的形状向左旋转所需的全部,结果证明它要小得多(取决于你的语言)而不是为每个形状定义每个旋转。

When I was trying to figure out how rotations would work for my tetris game, this was the first question that I found on stack overflow. Even though this question is old, I think my input will help others trying to figure this out algorithmically. First, I disagree that hard coding each piece and rotation will be easier. Gamecat's answer is correct, but I wanted to elaborate on it. Here are the steps I used to solve the rotation problem in Java.

  1. For each shape, determine where its origin will be. I used the points on the diagram from this page to assign my origin points. Keep in mind that, depending on your implementation, you may have to modify the origin every time the piece is moved by the user.

  2. Rotation assumes the origin is located at point (0,0), so you will have to translate each block before it can be rotated. For example, suppose your origin is currently at point (4, 5). This means that before the shape can be rotated, each block must be translated -4 in the x-coordinate and -5 in the y-coordinate to be relative to (0,0).

  3. In Java, a typical coordinate plane starts with point (0,0) in the upper left most corner and then increases to the right and down. To compensate for this in my implementation, I multiplied each point by -1 before rotation.

  4. Here are the formulae I used to figure out the new x and y coordinate after a counter-clockwise rotation. For more information on this, I would check out the Wikipedia page on Rotation Matrix. x' and y' are the new coordinates:

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

  5. For the last step, I just went through steps 2 and 3 in reverse order. So I multiplied my results by -1 again and then translated the blocks back to their original coordinates.

Here is the code that worked for me (in Java) to get an idea of how to do it in your language:

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());
}

This method is all that is needed to rotate your shape to the left, which turns out to be much smaller (depending on your language) than defining each rotation for every shape.

好菇凉咱不稀罕他 2024-07-15 01:07:22

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

但有旋转算法。

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

如果一个块从 (1,2) 开始,它会顺时针移动到 (2,-1) 和 (-1,-2) 和 (-1, 2)。
将其应用于每个块并旋转该块。

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

[  0   1 ]
[ -1   0 ]

对于逆时针旋转,请使用:

[  0  -1 ]
[  1   0 ]

There is a limited amount of shapes, so I would use a fixed table and no calculation. That saves time.

But there are rotation algorithms.

Chose a centerpoint and rotate pi/2.

If a block of a piece starts at (1,2) it moves clockwise to (2,-1) and (-1,-2) and (-1, 2).
Apply this for each block and the piece is rotated.

Each x is the previous y and each y - the previous x. Which gives the following matrix:

[  0   1 ]
[ -1   0 ]

For counterclockwise rotation, use:

[  0  -1 ]
[  1   0 ]
浮生面具三千个 2024-07-15 01:07:22

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

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

组成方块形状的每块砖块都会围绕该点旋转。
对于每个砖块,您可以应用以下计算...

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

x2 = (y1 + px - py)

y2 = (px + py - x1 - q)

反向旋转:

x2 = (px + py - y1 - q)

y2 = (x1 + py - px)

此计算基于 2D 仿射矩阵变换。
如果您对我是如何做到这一点感兴趣,请告诉我。

This is how I did it recently in a jQuery/CSS based tetris game.

Work out the centre of the block (to be used as a pivot point), i.e. the centre of the block shape.
Call that (px, py).

Each brick that makes up the block shape will rotate around that point.
For each brick, you can apply the following calculation...

Where each brick's width and height is q, the brick's current location (of the upper left corner) is (x1, y1) and the new brick location is (x2, y2):

x2 = (y1 + px - py)

y2 = (px + py - x1 - q)

To rotate the opposite direction:

x2 = (px + py - y1 - q)

y2 = (x1 + py - px)

This calculation is based on a 2D affine matrix transformation.
If you are interested in how I got to this let me know.

孤芳又自赏 2024-07-15 01:07:22

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

class Shape
{
    Color color;
    ShapeRotation[] rotations;
}

class ShapeRotation
{
    Point[4] points;
}

class Point
{
    int x, y;
}

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

Personally I've always just represented the rotations by hand - with very few shapes, it's easy to code that way. Basically I had (as pseudo-code)

class Shape
{
    Color color;
    ShapeRotation[] rotations;
}

class ShapeRotation
{
    Point[4] points;
}

class Point
{
    int x, y;
}

At least conceptually - a multi-dimensional array of points directly in shape would do the trick too :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文