java - 俄罗斯方 block 旋转算法不起作用

标签 java android algorithm

我正在使用俄罗斯方 block 旋转算法。不久前,我在另一个 winforms 应用程序中使用了该算法,效果很好。现在我想在Android中编写一个俄罗斯方 block 游戏,所以我又用Java编写了算法。

但是,这次不行了。我很久以前就写了这个算法,当时我还是一名初级程序员,所以代码有点糟糕。 Java 中的算法如下:

public static final int CLOCKWISE = 1;
public static final int ANTICLOCKWISE = -1;

public static Point rotateClockwise (int x, int y) {
    int temp;
    temp = y;
    y = x;
    x = -temp;
    return new Point (x, y);
}

public static Point rotateAnticlockwise (int x, int y) {
    int temp;
    temp = x;
    x = y;
    y = -temp;
    return new Point (x, y);
}

public static boolean tryRotateTetrimino (Tetrimino tetrimino,
        int rotationPointBlockIndex, int direction) {

    //Local variable declarations
    boolean a, b, c, d;
    TetrisBlock rotationBlock = tetrimino.blocks[rotationPointBlockIndex];
    int X1, Y1, X2, Y2, X3, Y3, X4, Y4;

    //Assign coordinates relative to the centre of rotation.
    X1 = tetrimino.blocks[0].getX () - rotationBlock.getX ();
    Y1 = tetrimino.blocks[0].getY () - rotationBlock.getY ();
    X2 = tetrimino.blocks[1].getX () - rotationBlock.getX ();
    Y2 = tetrimino.blocks[1].getY () - rotationBlock.getY ();
    X3 = tetrimino.blocks[2].getX () - rotationBlock.getX ();
    Y3 = tetrimino.blocks[2].getY () - rotationBlock.getY ();
    X4 = tetrimino.blocks[3].getX () - rotationBlock.getX ();
    Y4 = tetrimino.blocks[3].getY () - rotationBlock.getY ();

    //Rotate the coordinates.
    if (direction == CLOCKWISE) {
        X1 = rotateClockwise (X1, Y1).x;
        Y1 = rotateClockwise (X1, Y1).y;
        X2 = rotateClockwise (X2, Y2).x;
        Y2 = rotateClockwise (X2, Y2).y;
        X3 = rotateClockwise (X3, Y3).x;
        Y3 = rotateClockwise (X3, Y3).y;
        X4 = rotateClockwise (X4, Y4).x;
        Y4 = rotateClockwise (X4, Y4).y;
    } else {
        X1 = rotateAnticlockwise (X1, Y1).x;
        Y1 = rotateAnticlockwise (X1, Y1).y;
        X2 = rotateAnticlockwise (X2, Y2).x;
        Y2 = rotateAnticlockwise (X2, Y2).y;
        X3 = rotateAnticlockwise (X3, Y3).x;
        Y3 = rotateAnticlockwise (X3, Y3).y;
        X4 = rotateAnticlockwise (X4, Y4).x;
        Y4 = rotateAnticlockwise (X4, Y4).y;
    }

    //Declares two arrays of absolute x and y coordinates.
    int[] xArray = new int[] { rotationBlock.getX() + X1,
            rotationBlock.getX() + X2,
            rotationBlock.getX() + X3,
            rotationBlock.getX() + X4 };
    int[] yArray = new int[] { rotationBlock.getY() + Y1,
            rotationBlock.getY() + Y2,
            rotationBlock.getY() + Y3,
            rotationBlock.getY() + Y4 };

    //Check if the coordinates are valid
    a = tetrimino.checkPositionValid (xArray[0], yArray[0]);
    b = tetrimino.checkPositionValid (xArray[1], yArray[1]);
    c = tetrimino.checkPositionValid (xArray[2], yArray[2]);
    d = tetrimino.checkPositionValid (xArray[3], yArray[3]);

    //If the coordinates are valid, assign them to each of the blocks.
    if (a && b && c && d) {
        for (int i = 0 ; i < 4 ; i++) {
            tetrimino.blocks[i].setX (xArray[i]);
            tetrimino.blocks[i].setY (yArray[i]);
        }
        return true;
    }
    return false;

}

我认为这段代码对于除了我之外的所有人来说都很难理解。我曾经写过世界上最糟糕的代码。当终点可以旋转并且被旋转时,此方法返回 true。参数rotationPointBlockIndex表示旋转中心。因此,我可以尝试围绕每个俄罗斯方 block block 旋转俄罗斯方 block ,如下所示:

if (TetrisUtility.tryRotateTetrimino (this, 0, TetrisUtility.CLOCKWISE))
        TetrisUtility.addRotationIndex (this);
    else if (TetrisUtility.tryRotateTetrimino (this, 1, TetrisUtility.CLOCKWISE))
        TetrisUtility.addRotationIndex (this);
    else if (TetrisUtility.tryRotateTetrimino (this, 2, TetrisUtility.CLOCKWISE))
        TetrisUtility.addRotationIndex (this);
    else if (TetrisUtility.tryRotateTetrimino (this, 3, TetrisUtility.CLOCKWISE))
        TetrisUtility.addRotationIndex (this);

请注意,setX 和 setY 方法将更改俄罗斯方 block block 的物理位置。

我做了与以前完全相同的事情,但它不起作用。 例如:

O
O
O O

旋转,变成

O
  O
    O

看起来两个俄罗斯方 block block 重叠了。

如果您认为我的算法是错误的并想建议另一种算法,您能用 Tetrimino 类和 TetrisBlock 类来解释它吗?

Tetrimino.java

public abstract class Tetrimino {
public TetrisBlock[] blocks;

protected int interval = 1000;
protected boolean paused = false;
protected Handler handler;
protected TetrisBlock[][] tetrisBlockMatrix;
protected ArrayList<ITetrisEventListener> landedEventListeners;
protected Runnable task = new TimerTask () {
    @Override
    public void run() {
        if (!paused) {
            moveDown ();
            if (handler != null)
                handler.postDelayed (task, interval);
        }
    }
};

public static final int LEFT = -1;
public static final int RIGHT = 1;

protected abstract TetrisBlock[] getTouchingSides();

protected void landed () {
    for (int i = 0 ; i < landedEventListeners.size () ; i++) {
        landedEventListeners.get (i).onLanded (this);
    }
}

public void registerLandedListeners (ITetrisEventListener listener) {
    landedEventListeners.add (listener);
}

public void moveDown () {
    if (!checkLanded ()) {
        for (TetrisBlock block:blocks) {
            block.moveDown ();
        }
    } else {
        handler = null;
        landed ();
    }
}

protected boolean checkLanded () {
    TetrisBlock[] touchingSides = getTouchingSides ();
    for (TetrisBlock block:touchingSides) {
        if (block.getY () >= 21) {
            return true;
        }

        if (tetrisBlockMatrix[block.getX ()][block.getY () + 1] != null) {
            return true;
        }
    }
    return false;
}

public boolean checkPositionValid (int x, int y) {
    if (x < 0 || y < 0 ||
            x > 15 || y > 21)
        return false;
    if (tetrisBlockMatrix[x][y] == null)
        return true;
    return false;
}

public void move (int side) {
    if (side == 1 || side == -1) {
        for (TetrisBlock block:blocks) {
            block.setX (block.getX () + side);
        }

        for (TetrisBlock block:blocks) {
            if (!checkPositionValid (block.getX (), block.getY ())) {
                if (side == LEFT)
                    move (RIGHT);
                else
                    move (LEFT);
            }
        }
    } else {
        throw new IllegalArgumentException ();
    }
}

public void addTetrisBlocksToMatrix (TetrisBlock[][] matrix) {
    for (TetrisBlock block:blocks) {
        if (matrix[block.getX ()][block.getY ()] == null) {
            matrix[block.getX ()][block.getY ()] = block;
        } else {
            throw new IllegalArgumentException ();
        }
    }
}

public void setTimerEnabled (boolean value) {
    if (value && paused) {
        handler.post (task);
    } else {
        paused = true;
    }
}

public void setTimerInterval (int milliseconds) {
    interval = milliseconds;
}

protected Tetrimino (TetrisBlock[][] matrix, TetrisActivity activity) {
    this.tetrisBlockMatrix = matrix;
    handler = new Handler ();
    handler.post (task);
    landedEventListeners = new ArrayList<> ();
    blocks = new TetrisBlock[4];
}

}

俄罗斯方 block block .java

public class TetrisBlock {
private static final int LENGTH_IN_DP = 20;
private TetrisActivity activity;
private ImageView picture;
private int color;
private int x;
private int y;

private AbsoluteLayout.LayoutParams getLayoutParams () {
    return (AbsoluteLayout.LayoutParams) picture.getLayoutParams ();
}

public TetrisActivity getActivity() {
    return activity;
}

public ImageView getPicture() {
    return picture;
}

public int getY() {
    AbsoluteLayout.LayoutParams params = getLayoutParams ();
    return params.y / getLengthInPixels ();
}

public void setY(int y) {
    this.y = y;
    AbsoluteLayout.LayoutParams params = getLayoutParams ();
    params.y = y * getLengthInPixels ();
    picture.setLayoutParams (params);
}

public int getX() {
    AbsoluteLayout.LayoutParams params = getLayoutParams ();
    return params.x / getLengthInPixels ();
}

public void setX(int x) {
    this.x = x;
    AbsoluteLayout.LayoutParams params = getLayoutParams ();
    params.x = x * getLengthInPixels ();
    picture.setLayoutParams (params);
}

public int getColor() {
    return color;
}

public void setColor(int color) {
    this.color = color;
    picture.setBackgroundColor (color);
}

public TetrisBlock (int color, int x, int y, TetrisActivity activity) {
    this.activity = activity;
    picture = new ImageView (activity);
    setColor (color);
    picture.setImageResource (R.drawable.tetrisblock);

    int w, h;
    w = getLengthInPixels ();
    h = getLengthInPixels ();
    AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams (w,
            h, x * getLengthInPixels (), y * getLengthInPixels ());

    picture.setLayoutParams (params);
    picture.setScaleType (ImageView.ScaleType.FIT_CENTER);

    ((AbsoluteLayout)activity.findViewById (R.id.main_frame)).addView (picture);
}

public void moveDown () {
    setY (getY () + 1);
}

public int getLengthInPixels () {
    return (int)(LENGTH_IN_DP * activity.getScale () + 0.5F);
}
}

最佳答案

问题是,当您旋转时,您将 X 坐标设置为新值并覆盖旧值,而第二次调用旋转函数时仍然需要它。例如,当您应该传递原始值时,X1 的旋转值会传递到此处的第二次调用 rotateClockwise:

X1 = rotateClockwise (X1, Y1).x;
Y1 = rotateClockwise (X1, Y1).y;

只需调用一次,然后将 x 和 y 值分配给变量:

Point point1 = rotateClockwise (X1, Y1);
X1 = point1.x; Y1 = point1.y;

关于java - 俄罗斯方 block 旋转算法不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31530354/

相关文章:

php - fatal error : require_once() [function. require]:无法打开所需的 '__DIR__

algorithm - 从运行时分析中推导出时间复杂度

java - 使用 BorderLayout 时如何防止 JPanel 中的内容拉伸(stretch)?

java - Proguard 不支持 Java 8?

java - RestTemplate UTF-8 编码与交换不起作用

java - If语句与 boolean android

Java enum int 值只能用 JPA 顺序存储?

java - Android 将声音保存为铃声 - 铃声列表中未使用标题

algorithm - 取决于相关种子的可预测随机序列

algorithm - 移动和删除 head 元素的最佳大 O 时间复杂度是多少?