国际象棋:运动验证中的重复代码 - Java
Chess: Duplicate code in movement validations - Java
我目前正在学习 Java 并正在做一项 class 作业。我们应该制作 "weird version" 国际象棋。
与原始国际象棋一样,如果有棋子挡住它们,棋子就不能移动,明显的例外是马,它可以跳过所有棋子 除了国王 。
我有一个摘要class Piece
,它被所有棋子类型继承,每个棋子都有自己的运动规则。他们中的大多数都有这种移动限制,所以我在这个 class:
中定义了方法
public boolean freeWayHorizontally(int xO, int yO, int xD) {
//RIGHT
if (xO < xD) {
for (int x = xO + 1; x < xD; x++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null){
return false;
}
}
//LEFT
} else if (xO > xD) {
for (int x = xO - 1; x > xD; x--) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null){
return false;
}
}
}
return true;
}
public boolean freeWayVertically(int xO, int yO, int yD) {
//UP
if (yO < yD) {
for (int y = yO + 1; y < yD; y++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(xO, y);
if (thereIsPiece != null){
return false;
}
}
//DOWN
} else if (yO > yD) {
for (int y = yO - 1; y > yD; y--) {
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
if (thereIsPiece != null){
return false;
}
}
}
return true;
}
thereIsPiece(int x, int y)
是国际象棋 Simulator
class 中的一个函数,给定棋盘上的位置,returns 棋子处于该位置。
很明显,这两个接收相同的参数(起始坐标和目标坐标,其中一个目标坐标是棋子的起始坐标之一),所以唯一真正改变的是 thereIsPiece()
被调用。 编辑: 因此,它们被标记为重复,据我所知,这非常糟糕!
但是,我似乎无法仅使用其中一种方法来解决这个问题; 另外一个编辑: 我试过重载它,但它只能垂直或水平工作(可能做错了)。
问题是我需要单独完成这些以实现马的运动,这会覆盖这些方法:
public boolean freeWayHorizontally(int xO, int yO, int xD) { //Overriden by the Horse class
//RIGHT
if (xO < xD) {
for (int x = xO + 1; x <= xD; x++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
//LEFT
} else if (xO > xD) {
for (int x = xO - 1; x >= xD; x--) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
}
return true;
}
public boolean freeWayVertically(int xO, int yO, int yD) { //Overriden by the Horse class
//UP
if (yO < yD) {
for (int y = yO + 1; y <= yD; y++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(xO, y);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
//DOWN
} else if (yO > yD) {
for (int y = yO - 1; y >= yD; y--) {
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
}
return true;
}
然后调用自己类型的运动检查,同样定义在Piece
class:
public boolean freeWayL(int xO, int yO, int xD, int yD) {
boolean fH, fV;
//Horizontal -> Vertical
fH = this.freeWayHorizontally(xO, yO, xD);
if (fH) {
fV = this.freeWayVertically(xD, yO, yD);
if (fV) {
return true;
}
}
//Vertical -> Horizontal
fV = this.freeWayVertically(xO, yO, yD);
if (dV) {
fH = this.freeWayHorizontally(xO, yD, xD);
if (fH) {
return true;
}
}
return false;
}
我能做些什么来避免所有这些重复,甚至使这些验证变得更好?
您的代码的第一个问题是您在 Simulador
class 上使用不同的方法来检查位置:
// When is checking horizontally
CrazyPiece thereIsPiece = Simulador.pegaPecaPorCoordenada(x, yO);
// When is checking vertically
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
我看不出这不应该是单一方法的原因。
我可以在这里看到 2 个不同的改进点:
- 以一种只有一个循环的方式重写改变开始和结束的循环。
举个例子:
public boolean freeWayHorizontally(int xO, int yO, int xD) {
int destination = xD;
int origin = xO + 1;
if (xO > xD) {
destination = xO - 1;
origin = xD;
}
for (int x = origin; x < destination; x++) {
CrazyPiece thereIsPiece = Simulador.pegaPecaPorCoordenada(x, yO);
if (thereIsPiece != null){
return false;
}
}
return true;
}
当起点在终点之前时,您可以从起点直接移动到终点。
当目的地在起点之前时,您只需交换并从目的地移动到起点。
- 第二点是检查条件
我认为你应该添加一个方法:
private boolean checkPositionIsFree(int x, int y) {
return Simulador.pegaPecaPorCoordenada(x, y) != null;
}
现在你需要一种用于水平,一种用于垂直,直到你不能合并这两种方法。
然后你可以像这样重写你的方法:
public boolean freeWayHorizontally(int xO, int yO, int xD) {
int destination = xD;
int origin = xO + 1;
if (xO > xD) {
destination = xO - 1;
origin = xD;
}
for (int x = origin; x < destination; x++) {
if (checkPositionIsFree(x, yO)){
return false;
}
}
return true;
}
对于马,您只需 @Override
具有适当条件的 checkPositionIsFree()
方法(添加对国王的检查),一切都应该有效。
更新
要完全涵盖马的情况,您可以使用一种处理输入数据的方法:
@Override
public boolean freeWayHorizontally(int xO, int yO, int xD) {
return super.freeWayHorizontally(xO, yO, xD + 1);
}
这样可以避免重写所有代码。
By the way, your code here have some typos, maybe you rewrite it. It's better to check those kind of things, and have working code (in your case) or the exact code is failing, to avoid lost vouluntiers time following the wrong bug.
我目前正在学习 Java 并正在做一项 class 作业。我们应该制作 "weird version" 国际象棋。 与原始国际象棋一样,如果有棋子挡住它们,棋子就不能移动,明显的例外是马,它可以跳过所有棋子 除了国王 。
我有一个摘要class Piece
,它被所有棋子类型继承,每个棋子都有自己的运动规则。他们中的大多数都有这种移动限制,所以我在这个 class:
public boolean freeWayHorizontally(int xO, int yO, int xD) {
//RIGHT
if (xO < xD) {
for (int x = xO + 1; x < xD; x++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null){
return false;
}
}
//LEFT
} else if (xO > xD) {
for (int x = xO - 1; x > xD; x--) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null){
return false;
}
}
}
return true;
}
public boolean freeWayVertically(int xO, int yO, int yD) {
//UP
if (yO < yD) {
for (int y = yO + 1; y < yD; y++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(xO, y);
if (thereIsPiece != null){
return false;
}
}
//DOWN
} else if (yO > yD) {
for (int y = yO - 1; y > yD; y--) {
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
if (thereIsPiece != null){
return false;
}
}
}
return true;
}
thereIsPiece(int x, int y)
是国际象棋 Simulator
class 中的一个函数,给定棋盘上的位置,returns 棋子处于该位置。
很明显,这两个接收相同的参数(起始坐标和目标坐标,其中一个目标坐标是棋子的起始坐标之一),所以唯一真正改变的是 thereIsPiece()
被调用。 编辑: 因此,它们被标记为重复,据我所知,这非常糟糕!
但是,我似乎无法仅使用其中一种方法来解决这个问题; 另外一个编辑: 我试过重载它,但它只能垂直或水平工作(可能做错了)。
问题是我需要单独完成这些以实现马的运动,这会覆盖这些方法:
public boolean freeWayHorizontally(int xO, int yO, int xD) { //Overriden by the Horse class
//RIGHT
if (xO < xD) {
for (int x = xO + 1; x <= xD; x++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
//LEFT
} else if (xO > xD) {
for (int x = xO - 1; x >= xD; x--) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(x, yO);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
}
return true;
}
public boolean freeWayVertically(int xO, int yO, int yD) { //Overriden by the Horse class
//UP
if (yO < yD) {
for (int y = yO + 1; y <= yD; y++) {
CrazyPiece thereIsPiece = Simulador.checkIfTheresPiece(xO, y);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
//DOWN
} else if (yO > yD) {
for (int y = yO - 1; y >= yD; y--) {
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
if (thereIsPiece != null && thereIsPiece.isKing){
return false;
}
}
}
return true;
}
然后调用自己类型的运动检查,同样定义在Piece
class:
public boolean freeWayL(int xO, int yO, int xD, int yD) {
boolean fH, fV;
//Horizontal -> Vertical
fH = this.freeWayHorizontally(xO, yO, xD);
if (fH) {
fV = this.freeWayVertically(xD, yO, yD);
if (fV) {
return true;
}
}
//Vertical -> Horizontal
fV = this.freeWayVertically(xO, yO, yD);
if (dV) {
fH = this.freeWayHorizontally(xO, yD, xD);
if (fH) {
return true;
}
}
return false;
}
我能做些什么来避免所有这些重复,甚至使这些验证变得更好?
您的代码的第一个问题是您在 Simulador
class 上使用不同的方法来检查位置:
// When is checking horizontally
CrazyPiece thereIsPiece = Simulador.pegaPecaPorCoordenada(x, yO);
// When is checking vertically
CrazyPiece thereIsPiece = Simulador.checkIfThereIsPiece(xO, y);
我看不出这不应该是单一方法的原因。
我可以在这里看到 2 个不同的改进点:
- 以一种只有一个循环的方式重写改变开始和结束的循环。
举个例子:
public boolean freeWayHorizontally(int xO, int yO, int xD) {
int destination = xD;
int origin = xO + 1;
if (xO > xD) {
destination = xO - 1;
origin = xD;
}
for (int x = origin; x < destination; x++) {
CrazyPiece thereIsPiece = Simulador.pegaPecaPorCoordenada(x, yO);
if (thereIsPiece != null){
return false;
}
}
return true;
}
当起点在终点之前时,您可以从起点直接移动到终点。
当目的地在起点之前时,您只需交换并从目的地移动到起点。
- 第二点是检查条件
我认为你应该添加一个方法:
private boolean checkPositionIsFree(int x, int y) {
return Simulador.pegaPecaPorCoordenada(x, y) != null;
}
现在你需要一种用于水平,一种用于垂直,直到你不能合并这两种方法。
然后你可以像这样重写你的方法:
public boolean freeWayHorizontally(int xO, int yO, int xD) {
int destination = xD;
int origin = xO + 1;
if (xO > xD) {
destination = xO - 1;
origin = xD;
}
for (int x = origin; x < destination; x++) {
if (checkPositionIsFree(x, yO)){
return false;
}
}
return true;
}
对于马,您只需 @Override
具有适当条件的 checkPositionIsFree()
方法(添加对国王的检查),一切都应该有效。
更新
要完全涵盖马的情况,您可以使用一种处理输入数据的方法:
@Override
public boolean freeWayHorizontally(int xO, int yO, int xD) {
return super.freeWayHorizontally(xO, yO, xD + 1);
}
这样可以避免重写所有代码。
By the way, your code here have some typos, maybe you rewrite it. It's better to check those kind of things, and have working code (in your case) or the exact code is failing, to avoid lost vouluntiers time following the wrong bug.