确定骑士守卫的方格数

时间:2017-04-23 23:20:11

标签: java arraylist user-input hashcode

我在为此作业生成正确的输出时遇到了一些麻烦,并且不确定我做错了什么。

N x N棋盘上有K个骑士,你要确定他们守卫的方格数。如果一个正方形被一个占用,则一个正方形被保护 骑士或骑士可以通过一次动作到达骑士。 编写一个程序,读取正整数N和K,然后写入骑士的K个位置,并打印出 由这些K骑士守卫的方格数量。

enter image description here

输入示例:8 2 c 1 e 2

对应输出:10

输入示例:8 6 c 1 e 2 d 4 c 7 f 7 h 6

对应输出:30

当我输入第一个例子时,它可以工作,但是当我输入第二个例子时它给了我34

package knightguard;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class KnightGuard {

    static class Position {

        int x;
        int y;

        public Position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public boolean equals(Position p) {
            if (p.x == x && p.y == y) {
                return true;
            }
            return false;
        }

        @Override
        public String toString() {
            return x + "," + y;
        }

    }

    ArrayList<Position> knightPositions;
    int size;
    int no_of_knights;

    public KnightGuard(int size, int k, ArrayList<Position> knightPositions) {
        this.knightPositions = knightPositions;
        no_of_knights = k;
        this.size = size;
    }

    public int getSafePositions() {
        Set<Position> safePos = new HashSet<>();
        for (Position p : knightPositions) {
            if (isValid(p.x - 2, p.y - 1)) {
                safePos.add(new Position(p.x - 2, p.y - 1));
            }
            if (isValid(p.x - 2, p.y + 1)) {
                safePos.add(new Position(p.x - 2, p.y + 1));
            }
            if (isValid(p.x + 2, p.y - 1)) {
                safePos.add(new Position(p.x + 2, p.y - 1));
            }
            if (isValid(p.x + 2, p.y + 1)) {
                safePos.add(new Position(p.x + 2, p.y + 1));
            }

            if (isValid(p.x - 1, p.y - 2)) {
                safePos.add(new Position(p.x - 1, p.y - 2));
            }
            if (isValid(p.x - 1, p.y + 2)) {
                safePos.add(new Position(p.x - 1, p.y + 2));
            }
            if (isValid(p.x + 1, p.y - 2)) {
                safePos.add(new Position(p.x + 1, p.y - 2));
            }
            if (isValid(p.x + 1, p.y + 2)) {
                safePos.add(new Position(p.x + 1, p.y + 2));
            }
        }

        return safePos.size();
    }

    private boolean isValid(int x, int y) {
        if (x < 0 || x >= size || y < 0 || y >= size) {
            return false;
        }

        if (knightPositions.contains(new Position(x, y))) {
            return false;
        }

        return true;
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int size = s.nextInt();
        int knights = s.nextInt();
        ArrayList<Position> knightPos = new ArrayList<>();
        for (int i = 0; i < knights; i++) {
            int x = s.next().charAt(0) - 'a';
            int y = s.nextInt() - 1;
            knightPos.add(new Position(x, y));
        }

        KnightGuard knightGuard = new KnightGuard(size, knights, knightPos);
        System.out.println(knightGuard.getSafePositions());

        s.close();

    }

}

1 个答案:

答案 0 :(得分:1)

使用这种方法的一个问题是可能为不同的骑士生成可能的重复位置。例;使用帖子中的图片,位置D4和H6的两个骑士可以在F5处移动到正方形。因此,发布的代码将计算此位置TWICE。理论上,在八个不同的位置可能有八(8)名骑士,所有骑士都可以移动到同一个方格。必须进行检查以消除这些可能的“重复”位置。

我对KnightGuard类和getSafePositions方法感到有些困惑。 KnightGuard类有一个位置列表,这是给定骑士的位置列表。然而,getSafePositions方法只返回所有骑士可以从各自位置移动的不同移动的数量。此方法没有考虑到前一个骑士也可以移动到第一段所述的相同位置。

为了简化事情......我觉得一个名为Knight的课程会更好。骑士会有一个Position变量来指示“这个”骑士在棋盘上的位置。另外,Knight类将包含ArrayListPosition个对象,以指示此骑士在其位置可以做出的所有可能移动。 Knight不应该知道任何其他Knights,并且它可以移动到的位置列表是它可以移动到的所有位置,无论该位置是否有另一块。该列表至少包含两(2)个位置,最多包含八(8)个不同的位置。

当创建一个新的Knight对象时,可能会在实例化时自动生成可能的移动列表以及它在板上的位置,我们将在稍后使用。

以下是此Knight课程的示例。应该注意的是,在这个类和main方法中,我改变了板的索引,从左边的1(a)不是零(0)开始向右移动,也在y底部y索引的y索引处开始是1并向上移动。此外,还创建了SetValidMoves方法,以允许此骑士可以移动的位置列表进行更改。如果另一位骑士占据这个骑士的守卫位置列表中的一个位置,则可能需要这样做。这段代码没有利用这个优势,因为我们只对守卫方格的数量感兴趣。

public class Knight {

  Position knightPosition;
  ArrayList<Position> validMoves;
  int boardSize;

  public Knight(Position position, int inBoardSize) {
    knightPosition = position;
    validMoves = new ArrayList<Position>();
    boardSize = inBoardSize;
    SetValidMoves();
  }

  public Position GetKnightPosition() {
    return knightPosition;
  }

  public ArrayList<Position> GetValidMoves() {
    return validMoves;
  }
  public void SetValidMoves(ArrayList<Position> newMoves) {
    validMoves = newMoves;
  }

  private void SetValidMoves() {
    int thisX = knightPosition.x;
    int thisY = knightPosition.y;
    // check for bottom moves 2 down 1 left - right
    if (thisY - 2 >= 1) { 
      if (thisX + 1 <= boardSize) { 
        validMoves.add(new Position(thisX + 1, thisY - 2));
      }
      if (thisX - 1 >= 1) { 
        validMoves.add(new Position(thisX - 1, thisY - 2));
      }
    }
    // check for bottom moves 1 down 2 left - right
    if (thisY - 1 >= 1) { 
      if (thisX + 2 <= boardSize) { 
        validMoves.add(new Position(thisX + 2, thisY - 1));
      }
      if (thisX - 2 >= 1) { 
        validMoves.add(new Position(thisX - 2, thisY - 1));
      }
    }
    // check for top moves 2 up 1 left - right
    if (thisY + 2 <= boardSize) { 
      if (thisX + 1 <= boardSize) { 
        validMoves.add(new Position(thisX + 1, thisY + 2));
      }
      if (thisX - 1 >= 1) { 
        validMoves.add(new Position(thisX - 1, thisY + 2));
      }
    }
    // check for top moves 1 up 2 left - right
    if (thisY + 1 <= boardSize) { 
      if (thisX + 2 <= boardSize) { 
        validMoves.add(new Position(thisX + 2, thisY + 1));
      }
      if (thisX - 2 >= 1) { 
        validMoves.add(new Position(thisX - 2, thisY + 1));
      }
    }
  }
}

使用ArrayListKnight个对象(knightsOnBoard),可以循环思考此列表并创建ArrayListPosition个对象({{ 1}})每个validMoves表示一个或多个骑士守卫的位置。由于不需要重复,我们只是忽略已经在Position列表中的位置。

validMovesknightsOnBoard个对象的全局列表

Knight

由于上述代码使用private static ArrayList<Position> GetAllDifferentPositions() { ArrayList<Position> validMoves = new ArrayList<Position>(); for (Knight curKnight : knightsOnBoard) { for (Position curPos : curKnight.validMoves) { if (!validMoves.contains(curPos)) { validMoves.add(curPos); } } } return validMoves; } 属性检查位置是否已在列表contains中,因此需要在validMoves类中进行更改以公开公开{{1}使用Object参数的方法。

Position

现在我们有equals@Override public boolean equals(Object obj) { if (obj instanceof Position) { Position other = (Position)obj; if (this.x == other.x && this.y == other.y) return true; } return false; } 个没有重复项的对象。不幸的是,还有最后一个障碍需要明确。需要检查ArrayList是否可以移动到正方形但是已经被另一个骑士占用了。因此,我们需要移除骑士可以移动到的位置列表中的所有“骑士”位置。

必须这样做的原因是我们需要将所有给定Position的位置添加到计数中,因为骑士坐在的方格也是一个“守卫”的方格。由于这个位置可能已经在列表中...我们需要删除它们。换句话说,我们知道Knight在其移动列表中不会有“其”自己的位置,但是在移动列表中可能有另一个Knight位置。

Knight

现在位置列表(下面的Knight)没有重复,此外,我们知道列表中没有任何骑士所在的位置。因此,守卫方格的数量将是位置列表中private static void RemoveAllKnightPositions(ArrayList<Position> allPositions) { for (Knight curKnight : knightsOnBoard) { if (allPositions.contains(curKnight.knightPosition)) { allPositions.remove(curKnight.knightPosition); } } } 加上骑士数量的位置数。

最后,将这些全部放在下面的主要方法中。请注意,代码会更改索引顺序,因此BOTH x和y从一(1)开始,到finalResults结束。我希望这是有道理和有帮助的。

finalResults