我正在做一个可以选择和Al对战的项目,所以我开始在一个单独的类中完成,我只是扩展了主类,它有一个GUI类的对象,它可以绘制按钮和框架。
我的算法工作如下:
一旦一个按钮被点击:
我想知道是否有任何更新/更改,以改进我的代码,无论是在算法或代码本身。
public class Al extends main implements ActionListener{
int turn=0;
public void actionPerformed(ActionEvent e)
{
JButton temp=(JButton)e.getSource();
temp.setEnabled(false);
temp.setText(turn%2==0?"X":"O");
if(checkWin(turn%2==0?"X":"O"))
gui.banner.setText("You won!");
else{
if(isClose(turn%2==0?"O":"X",turn%2==0?"O":"X")==false && isClose(turn%2==0?"X":"O", turn%2==0?"O":"X")==false)
rand(turn%2==0?"O":"X");
if(checkWin(turn%2==0?"O":"X"))
gui.banner.setText("You Lost!");
}
}
Al()
{
gui.addbanner("Your Turn");
gui.addnewbutton();
gui.newgame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
for(int i = 0;i < 9 ; i++){
gui.buttons[i].setEnabled(true);
gui.buttons[i].setBorder(BorderFactory.createBevelBorder(1,Color.black,Color.black));
gui.buttons[i].setText("");
}
gui.banner.setText("Your Turn");
turn++;
if(turn%2==1)
rand("O");
}
});
for(int i=0;i<9;i++){
gui.buttons[i].addActionListener(this);
gui.buttons[i].setText("");
}
}
public Boolean isClose(String me, String al)
{
for(int i=0;i<9;i++)
{
if(i%3==0)
{
if(gui.buttons[i].getText()==gui.buttons[i+1].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+2].getText()=="")
{
gui.buttons[i+2].setText(al);
gui.buttons[i+2].setEnabled(false);
return true;
}
if(gui.buttons[i+1].getText()==gui.buttons[i+2].getText()&&gui.buttons[i+1].getText()==me&&gui.buttons[i].getText()=="")
{
gui.buttons[i].setText(al);
gui.buttons[i].setEnabled(false);
return true;
}
if(gui.buttons[i].getText()==gui.buttons[i+2].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+1].getText()=="")
{
gui.buttons[i+1].setText(al);
gui.buttons[i+1].setEnabled(false);
return true;
}
}
if(i<=2)
{
if(gui.buttons[i].getText()==gui.buttons[i+3].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+6].getText()=="")
{
gui.buttons[i+6].setText(al);
gui.buttons[i+6].setEnabled(false);
return true;
}
if(gui.buttons[i+3].getText()==gui.buttons[i+6].getText()&&gui.buttons[i+3].getText()==me&&gui.buttons[i].getText()=="")
{
gui.buttons[i].setText(al);
gui.buttons[i].setEnabled(false);
return true;
}
if(gui.buttons[i].getText()==gui.buttons[i+6].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+3].getText()=="")
{
gui.buttons[i+3].setText(al);
gui.buttons[i+3].setEnabled(false);
return true;
}
}
if(i==0)
{
if(gui.buttons[i].getText()==gui.buttons[i+4].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+8].getText()=="")
{
gui.buttons[i+8].setText(al);
gui.buttons[i+8].setEnabled(false);
return true;
}
if(gui.buttons[i+4].getText()==gui.buttons[i+8].getText()&&gui.buttons[i+4].getText()==me&&gui.buttons[i].getText()=="")
{
gui.buttons[i].setText(al);
gui.buttons[i].setEnabled(false);
return true;
}
if(gui.buttons[i].getText()==gui.buttons[i+8].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+4].getText()=="")
{
gui.buttons[i+4].setText(al);
gui.buttons[i+4].setEnabled(false);
return true;
}
}
if(i==2)
{
if(gui.buttons[i].getText()==gui.buttons[i+2].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+4].getText()=="")
{
gui.buttons[i+4].setText(al);
gui.buttons[i+4].setEnabled(false);
return true;
}
if(gui.buttons[i+2].getText()==gui.buttons[i+4].getText()&&gui.buttons[i+2].getText()==me&&gui.buttons[i].getText()=="")
{
gui.buttons[i].setText(al);
gui.buttons[i].setEnabled(false);
return true;
}
if(gui.buttons[i].getText()==gui.buttons[i+4].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+2].getText()=="")
{
gui.buttons[i+2].setText(al);
gui.buttons[i+2].setEnabled(false);
return true;
}
}
}
return false;
}
public void rand(String al)
{
int x;
Random random=new Random();
do
{
x=random.nextInt(9)-0;
}
while(gui.buttons[x].getText()!="" && isFull()==false);
if(isFull()==false)
{
gui.buttons[x].setText(al);
gui.buttons[x].setEnabled(false);
}
}
public Boolean isFull()
{
for(int i=0;i<9;i++)
{
if(gui.buttons[i].getText()=="")
return false;
}
return true;
}
public boolean lineWin(String player, int i, int j, int k) {
return gui.buttons[i].getText().equals(player) && gui.buttons[j].getText().equals(player) && gui.buttons[k].getText().equals(player);
}
public void finish(int i, int j, int k)
{
gui.buttons[i].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
gui.buttons[j].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
gui.buttons[k].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
for(int m=0;m<9;m++)
{
gui.buttons[m].setEnabled(false);
}
}
public Boolean checkWin(String chr){
if(lineWin(chr,0,1,2))
{
finish(0, 1, 2);
return true;
}
if(lineWin(chr,3,4,5))
{
finish(3, 4, 5);
return true;
}
if(lineWin(chr,6,7,8))
{
finish(6, 7, 8);
return true;
}
if(lineWin(chr,0,3,6))
{
finish(0,3,6);
return true;
}
if(lineWin(chr,1,4,7))
{
finish(1,4,7);
return true;
}
if(lineWin(chr,0,1,2))
{
finish(0, 1, 2);
return true;
}
if(lineWin(chr,2,5,8))
{
finish(2,5,8);
return true;
}
if(lineWin(chr,0,4,8))
{
finish(0,4,8);
return true;
}
if(lineWin(chr,2,4,6))
{
finish(2,4,6);
return true;
}
return false; }}发布于 2016-10-22 13:55:24
我还没有尝试过这些更改,因为如果没有更多的上下文,您的代码就无法运行。如果你提供了其他的课程,我可以运行它们,看看发生了什么。然后,我可以在本地IDE中进行更改,并对它们进行测试(至少最低限度)。实际上,我甚至不能保证这些更改会编译。
对于这样的小程序,请考虑包括问题中的所有代码。对于较大的程序,请考虑链接到具有更多上下文的外部存储库。
temp.setText(turn%2==0?"X":"O"); if(checkWin(turn%2==0?"X":"O")) gui.banner.setText("You won!"); else{ if(isClose(turn%2==0?"O":"X",turn%2==0?"O":"X")==false && isClose(turn%2==0?"X":"O", turn%2==0?"O":"X")==false) rand(turn%2==0?"O":"X"); if(checkWin(turn%2==0?"O":"X")) gui.banner.setText("You Lost!"); }
您可以使用并行逻辑多次计算当前和其他播放器。相反,考虑一下
Player current = (turn % 2 == 0) ? Player.X : Player.O;
Player other = current.getNext();
temp.setText(current.toString());
if (checkWin(current)) {
gui.banner.setText("You won!");
} else {
if (!isClose(other, current) && !isClose(current, other)) {
rand(other);
}
if (checkWin(other))
gui.banner.setText("You Lost!");
}
}请注意,这还需要一个带有手动定义的Player enum方法的getNext方法。在这种情况下,getNext将返回与current相反的内容。因此,如果current是X,它将返回O,反之亦然。
你可能会问为什么你不能
String other = (turn%2 == 0) ? "O" : "X";简短的回答是,你可以这样做,但可能不想这样做。更长远的答案是,这是脆弱的。例如,如果您更改了O首先和X秒,则必须更改原始代码中的每一个事件。在新代码中,你必须改变两个位置。如果您将第二个结果建立在第一个结果的基础上,则两者一起移动。将其移动到enum使您更有可能立即进行任何所需的更改。例如,如果你决定要字母是G和T。
出于类似的原因,最好使用enum,如果您碰巧输入了Y,就会发出抱怨。在这种情况下,当前的代码将悄无声息地无法工作,您必须进行运行时测试来确定原因。修改后的代码将给出编译时错误。
编写!isClose(current, other)比将它与false相比较更有习性。两者都做同样的事情,但前者是更常见的写作方式。
我更喜欢使用带大括号的块窗体,即使单个语句窗体可以工作。我发现它更一致,更容易阅读。此外,单个语句窗体容易受到块窗体不存在的某种类型的编辑错误的影响。
for(int i=0;i<9;i++){ gui.buttons[i].addActionListener(this); gui.buttons[i].setText(""); }
您多次使用此模式。最明显的修正是常量,您可以使用如下
for (int i = 0; i < BUTTONS_COUNT; i++){
gui.buttons[i].addActionListener(this);
gui.buttons[i].setText("");
}然后所有的人都会一起行动。但是实际上我们这里有一个更好的解决方案,它更简单,并且节省了定义一个额外的常量:
for (JButton button : gui.buttons) {
button.addActionListener(this);
button.setText("");
}现在,我们不声明只用于取消数组引用的迭代变量。我们直接处理数组的内容。我们只和那些在那里的人一起工作。如果我们改变棋盘中的方格数,它会自动调整。我们永远不能增加或减少按钮的数量,但忘记了一个地方,我们手动交互。
Random对象Random random=new Random();
如果将它变成类上的static final变量,则只需创建一次并将其种子化。
public static final Random random = new Random();我们实际上可以简化整个方法。
int x; Random random=new Random(); do { x=random.nextInt(9)-0; } while(gui.buttons[x].getText()!="" && isFull()==false); if(isFull()==false) { gui.buttons[x].setText(al); gui.buttons[x].setEnabled(false); }
isFull方法每次都会返回相同的结果。所以我们可以先这么做。
if (isFull())
{
return;
}
int x;
do
{
x = random.nextInt(9)-0;
}
while (gui.buttons[x].getText() != "");
gui.buttons[x].setText(al);
gui.buttons[x].setEnabled(false);这至少节省了对isFull的一个调用,可能还保存了更多。
但是如果我们做不同的检查,我们实际上可以做得更好。
List<Integer> openSquares = new ArrayList<>();
for (int i = 0; i < gui.buttons.length; i++) {
if (gui.buttons[i].getText() == "") {
openSquares.add(i);
}
}
if (openSquares.isEmpty()) {
return;
}
JButton button = gui.buttons[openSquares.get(random.nextInt(openSquares.size())];
button.setText(al);
button.setEnabled(false);isEmpty检查的结果与isFull检查的结果相同。因此,这样做的效果是什么都不做,如果没有空方块,return,因为板是满的。否则,它会选择一个随机的开方形并对其进行标记。请注意,这只会生成一个随机值。原始代码会一直生成随机值,直到找到一个起作用的值为止。这段代码的平均速度可能较慢,但最坏的情况更好。
在这个模式中有八个代码块:
if(lineWin(chr,0,1,2)) { finish(0, 1, 2); return true; }
请注意,将相同的三个参数传递给两个单独的方法。考虑把这个重写成这样
int[] line = {0, 1, 2};
if (lineWin(chr, line)) {
finish(line);
return true;
}使用lineWin和finish重写如下
public boolean lineWin(String player, int[] line) {
for (int square : line)
{
if (!gui.buttons[square].getText().equals(player))
{
return false
}
}
return true;
}和
public void finish(int[] line)
{
for (int square : line)
{
gui.buttons[square].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
}
for (JButton button : gui.buttons)
{
button.setEnabled(false);
}
}这将确保将相同的值传递给这两个方法。
此外,这允许线的长度,而不是三个方格。
或者类似的东西
for (Integer[] line : lines) {
if (lineWin(player, line)) {
finish(line);
return true;
}
}
return false;其中可以定义lines,比如
private static final List<Integer[]> lines = new ArrayList<>();
static {
lines.add(new Integer[]{0, 1, 2});
lines.add(new Integer[]{3, 4, 5});
lines.add(new Integer[]{6, 7, 8});
lines.add(new Integer[]{0, 3, 6});
lines.add(new Integer[]{1, 4, 7});
lines.add(new Integer[]{2, 5, 8});
lines.add(new Integer[]{0, 4, 8});
lines.add(new Integer[]{2, 4, 6});
}这只在应用程序的生存期内完成一次。
或者类似的东西
public class Board {
private final String[] squares;
private final List<Integer[]> lines = new ArrayList<>();
Board(int width, int height) {
squares = new String[width * height];
for (int column = 0; column < width; column++) {
lines.add(makeColumn(column, height, width));
}
for (int row = 0; row < squares.length; row += width) {
lines.add(makeRow(row, width));
}
int rightEdge = width - 1;
if (width >= height) {
int difference = width - height + 1;
for (int diagonal = 0; diagonal < difference; diagonal++) {
lines.add(makeForwardDiagonal(0, diagonal, width, height));
lines.add(makeBackwardDiagonal(0, rightEdge - diagonal, width, height));
}
} else {
int difference = height - width + 1;
for (int diagonal = 0; diagonal < difference; diagonal++) {
lines.add(makeForwardDiagonal(diagonal, 0, width, width));
lines.add(makeBackwardDiagonal(diagonal, rightEdge, width, width));
}
}
}
private Integer[] makeBackwardDiagonal(int row, int column, int width, int length) {
Integer[] line = new Integer[length];
for (int i = 0; i < length; i++) {
line[i] = (row + i) * width + column - i;
}
return line;
}
private Integer[] makeForwardDiagonal(int row, int column, int width, int length) {
Integer[] line = new Integer[length];
for (int i = 0; i < length; i++) {
line[i] = (row + i) * width + column + i;
}
return line;
}
private Integer[] makeRow(int row, int width) {
Integer[] line = new Integer[width];
for (int i = 0; i < width; i++) {
line[i] = row + i;
}
return line;
}
private Integer[] makeColumn(int column, int height, int width) {
Integer[] line = new Integer[height];
for (int i = 0; i < height; i++) {
line[i] = i * width + column;
}
return line;
}
}您可以通过添加
public static void main(String[] args) {
Board board = new Board(5, 3);
for (Integer[] line : board.lines) {
System.out.println(Arrays.toString(line));
}
}如果需要,我将让您将其集成到您的应用程序中。请注意,一些相关的更改将发生在您发布的类之外。
https://codereview.stackexchange.com/questions/144892
复制相似问题