JavaでのOOP戦艦コンソールゲーム

これに関する私の2番目の見解は ここ

OOPを練習するために、簡単なコンソールゲームを作りたかったのです。読みやすさ、メンテナンス、ベストプラクティスを検討したレビューをいただければ幸いです。

このコードで少しイライラするのは、インターフェイス、抽象クラス、継承を使用していないことですが、できませんでした。 「ここでそれらの適切な使用例を見つけることができません。

Board.java

package com.tn.board; import com.tn.constants.Constants; import com.tn.ship.Ship; import com.tn.utils.Position; import com.tn.utils.Utils; import java.awt.Point; import java.util.Scanner; public class Board { private static final Ship[] ships; private char[][] board; /** * Initialize ships (once). * */ static { ships = new Ship[]{ new Ship("Carrier", Constants.CARRIER_SIZE), new Ship("Battleship", Constants.BATTLESHIP_SIZE), new Ship("Cruiser", Constants.CRUISER_SIZE), new Ship("Submarine", Constants.SUBMARINE_SIZE), new Ship("Destroyer", Constants.DESTROYER_SIZE) }; } /** * Constructor */ public Board() { board = new char[Constants.BOARD_SIZE][Constants.BOARD_SIZE]; for(int i = 0; i < Constants.BOARD_SIZE; i++) { for(int j = 0; j < Constants.BOARD_SIZE; j++) { board[i][j] = Constants.BOARD_ICON; } } placeShipsOnBoard(); } /** * Target ship ship. * * @param point the point * @return ship */ public Ship targetShip(Point point) { boolean isHit = false; Ship hitShip = null; for(int i = 0; i < ships.length; i++) { Ship ship = ships[i]; if(ship.getPosition() != null) { if(Utils.isPointBetween(point, ship.getPosition())) { isHit = true; hitShip = ship; break; } } } final char result = isHit ? Constants.SHIP_IS_HIT_ICON : Constants.SHOT_MISSED_ICON; updateShipOnBoard(point, result); printBoard(); return (isHit) ? hitShip : null; } /** * Place ships on board. */ private void placeShipsOnBoard() { System.out.printf("%nAlright - Time to place out your ships%n%n"); Scanner s = new Scanner(System.in); for(int i = 0; i < ships.length; i++) { Ship ship = ships[i]; boolean isShipPlacementLegal = false; System.out.printf("%nEnter position of %s (length %d): ", ship.getName(), ship.getSize()); while(!isShipPlacementLegal) { try { Point from = new Point(s.nextInt(), s.nextInt()); Point to = new Point(s.nextInt(), s.nextInt()); while(ship.getSize() != Utils.distanceBetweenPoints(from, to)) { System.out.printf("The ship currently being placed on the board is of length: %d. Change your coordinates and try again", ship.getSize()); from = new Point(s.nextInt(), s.nextInt()); to = new Point(s.nextInt(), s.nextInt()); } Position position = new Position(from, to); if(!isPositionOccupied(position)) { drawShipOnBoard(position); ship.setPosition(position); isShipPlacementLegal = true; } else { System.out.println("A ship in that position already exists - try again"); } } catch(IndexOutOfBoundsException e) { System.out.println("Invalid coordinates - Outside board"); } } } } private void updateShipOnBoard(Point point, final char result) { int x = (int) point.getX() - 1; int y = (int) point.getY() - 1; board[y][x] = result; } /** * * @param position * @return */ private boolean isPositionOccupied(Position position) { boolean isOccupied = false; Point from = position.getFrom(); Point to = position.getTo(); outer: for(int i = (int) from.getY() - 1; i < to.getY(); i++) { for(int j = (int) from.getX() - 1; j < to.getX(); j++) { if(board[i][j] == Constants.SHIP_ICON) { isOccupied = true; break outer; } } } return isOccupied; } /** * * @param position */ private void drawShipOnBoard(Position position) { Point from = position.getFrom(); Point to = position.getTo(); for(int i = (int) from.getY() - 1; i < to.getY(); i++) { for(int j = (int) from.getX() - 1; j < to.getX(); j++) { board[i][j] = Constants.SHIP_ICON; } } printBoard(); } /** * Print board. */ private void printBoard() { System.out.print("\t"); for(int i = 0; i < Constants.BOARD_SIZE; i++) { System.out.print(Constants.BOARD_LETTERS[i] + "\t"); } System.out.println(); for(int i = 0; i < Constants.BOARD_SIZE; i++) { System.out.print((i+1) + "\t"); for(int j = 0; j < Constants.BOARD_SIZE; j++) { System.out.print(board[i][j] + "\t"); } System.out.println(); } } } 

Constants.java

package com.tn.constants; public class Constants { private Constants() {} public static final int PLAYER_LIVES = 17; //sum of all the ships public static final int CARRIER_SIZE = 5; public static final int BATTLESHIP_SIZE = 4; public static final int CRUISER_SIZE = 3; public static final int SUBMARINE_SIZE = 3; public static final int DESTROYER_SIZE = 2; public static final char SHIP_ICON = "X"; public static final char BOARD_ICON = "-"; public static final char SHIP_IS_HIT_ICON = "O"; public static final char SHOT_MISSED_ICON = "M"; public static final char[] BOARD_LETTERS = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"}; public static final int BOARD_SIZE = 10; } 

Player.java

package com.tn.player; import com.tn.board.Board; import com.tn.constants.Constants; import com.tn.ship.Ship; import java.awt.Point; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Player { private int id; private int lives; private Board board; private Map<Point, Boolean> targetHistory; private Scanner scanner; /** * Instantiates a new Player. * * @param id the id */ public Player(int id) { System.out.printf("%n=== Setting up everything for Player %s ====", id); this.id = id; this.lives = Constants.PLAYER_LIVES; this.board = new Board(); this.targetHistory = new HashMap<>(); this.scanner = new Scanner(System.in); } /** * Gets id. * * @return the id */ public int getId() { return id; } /** * Gets lives. * * @return the lives */ public int getLives() { return lives; } /** * Decrement live by one. */ public void decrementLiveByOne() { lives--; } /** * Turn to play. * * @param opponent the opponent */ public void turnToPlay(Player opponent) { System.out.printf("%n%nPlayer %d, Choose coordinates you want to hit (x y) ", id); Point point = new Point(scanner.nextInt(), scanner.nextInt()); while(targetHistory.get(point) != null) { System.out.print("This position has already been tried"); point = new Point(scanner.nextInt(), scanner.nextInt()); } attack(point, opponent); } /** * Attack * * @param point * @param opponent */ private void attack(Point point, Player opponent) { Ship ship = opponent.board.targetShip(point); boolean isShipHit = (ship != null) ? true : false; if(isShipHit) { ship.shipWasHit(); opponent.decrementLiveByOne(); } targetHistory.put(point, isShipHit); System.out.printf("Player %d, targets (%d, %d)", id, (int)point.getX(), (int)point.getY()); System.out.println("...and " + ((isShipHit) ? "HITS!" : "misses...")); } } 

Ship.java

package com.tn.ship; import com.tn.utils.Position; public class Ship { private String name; private int size; private int livesLeft; private boolean isSunk; private Position position; public Ship(String name, int size) { this.name = name; this.size = size; this.livesLeft = size; this.isSunk = false; } public String getName() { return name; } public int getSize() { return size; } public int getLivesLeft() { return livesLeft; } public boolean isSunk() { return isSunk; } public void setSunk(boolean sunk) { isSunk = sunk; } public Position getPosition() { return position; } public void setPosition(Position position) { this.position = position; } public void shipWasHit() { if(livesLeft == 0) { isSunk = true; System.out.println("You sunk the " + name); return; } livesLeft--; } } 

Position.java

package com.tn.utils; import com.tn.constants.Constants; import java.awt.Point; public class Position { private Point from; private Point to; /** * Instantiates a new Position. * * @param from the from * @param to the to */ public Position(Point from, Point to) { if(from.getX() > Constants.BOARD_SIZE || from.getX() < 0 || from.getY() > Constants.BOARD_SIZE || from.getY() < 0 || to.getX() > Constants.BOARD_SIZE || to.getX() < 0 || to.getY() > Constants.BOARD_SIZE || to.getY() < 0) { throw new ArrayIndexOutOfBoundsException(); } this.from = from; this.to = to; } /** * Gets from. * * @return the from */ public Point getFrom() { return from; } /** * Gets to. * * @return the to */ public Point getTo() { return to; } } 

Utils.java

package com.tn.utils; import java.awt.Point; public class Utils { private Utils() { } /** * Distance between points double. * * @param from the from * @param to the to * @return the double */ public static double distanceBetweenPoints(Point from, Point to) { double x1 = from.getX(); double y1 = from.getY(); double x2 = to.getX(); double y2 = to.getY(); return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2)) + 1; } /** * Is point between boolean. * * @param point the point * @param position the position * @return the boolean */ public static boolean isPointBetween(Point point, Position position) { Point from = position.getFrom(); Point to = position.getTo(); return from.getY() <= point.getY() && to.getY() >= point.getY() && from.getX() <= point.getX() && to.getX() >= point.getX(); } } 

Game.java

package com.tn.game; import com.tn.player.Player; public class Game { private Player[] players; /** * Instantiates a new Game. */ public Game() { players = new Player[]{ new Player(1), new Player(2) }; } /** * Start. */ public void start() { int i = 0; int j = 1; int size = players.length; Player player = null; while(players[0].getLives() > 0 && players[1].getLives() > 0) { players[i++ % size].turnToPlay(players[j++ % size]); player = (players[0].getLives() < players[1].getLives()) ? players[1] : players[0]; } System.out.printf("Congrats Player %d, you won!",player.getId()); } } 

Mai n.java

package com.tn; import com.tn.game.Game; public class Main { public static void main(String[] args) { Game game = new Game(); game.start(); } } 

コメント

  • 私は’ここに完全なレビューを書くつもりはありません(私は’ Javaの専門家ではありません)。しかし、この質問に答える最後のポイントに興味があるかもしれません。
  • @πάνταῥεῖその’いくつかの素晴らしい点、ありがとうございます。 ‘あなたの提案に関して私はそれほど遠く離れていたとは思いません。
  • どちらもそうは思いません、’私がそこで指摘した理由。
  • あなたのコードは非常に優れています。答えは、私が指摘したことも示しています。’ 1つだけ例外があります: ‘テストケースはありません。

回答

ありがとうございますコードを共有してください。

このコードで少しイライラするのは、インターフェイス、抽象クラス、継承を使用しないことです。

OOPを実行するということは、(とりわけ)次の特定の原則に従うことを意味します。

  • 情報の非表示/カプセル化
  • 単一責任
  • 関心の分離
  • KISS(シンプルに(そして)愚かにしてください。)
  • DRY(繰り返してはいけません。)
  • 「教えてください!尋ねないでください。」
  • 関心の分離の法則(「見知らぬ人と話さないでください!」)

インターフェース、absトラクトクラス、または継承は帽子の原則をサポートし、必要に応じて使用する必要があります。これらはOOPを「定義」しません。

私見では、アプローチがOOPに失敗する主な理由は、「モデル」がプリミティブ型charの配列であるためです。これは最終的にゲームロジックの手続き型アプローチにつながります。

次のようなインターフェースを考えます:

interface GameField{ char getIcon(); Result shootAt(); } 

where Resultは列挙型になります:

 enum Result{ NO_HIT, PARTIAL_HIT, DESTROYED } 

そして、インターフェイスのさまざまな実装があります:

public class BorderField implements GameField{ private final char borderName; public BorderField(char borderName){ this.borderName = borderName; } @Override public char getIcon(){ return borderName; } @Override public Result shootAt(){ return Result.NO_HIT; } } 

public class WaterField implements GameField{ private boolean isThisFieldHit = false; @Override public char getIcon(){ return isThisFieldHit?"M": " "; } @Override public Result shootAt(){ return Result.NO_HIT; } } 

public class ShipField implements GameField{ private final Ship ship; private boolean isThisFieldHit = false; public ShipField(Ship ship){ this.ship = ship; } @Override public char getIcon(){ Result shipState = ship.getState(); switch(shipState){ case NO_HIT: return " "; case PARTIAL_HIT: return isThisFieldHit?"O":" "; case DESTROYED: return "#"; } @Override public Result shootAt(){ ship.hit(); return ship.getState(); } } 

これで十分です。アイデアを得る…


正式な問題

命名

適切な名前を見つけることは、プログラミングで最も難しい部分です。したがって、常に時間をかけて識別子名について考えてください。

明るい面では、Javaの命名規則に従います。

ただし、メソッド名は動詞で始める必要があります。現在形。例:shipWasHit()にはhit()という名前を付ける必要があります。
またはdistanceBetweenPoints()に名前を付ける必要があります。 calculateDistanceBetween()になります。ここで、パラメーターは距離がポイント間の距離であることを示しているため、メソッド名にそれを含める必要はありません。

変数名は冗長にしてください。代わりに

 double x1 = from.getX(); double y1 = from.getY(); double x2 = to.getX(); double y2 = to.getY(); 

この変数はむしろ次のような名前が付けられています:

 double startPointX = from.getX(); double startPointY = from.getY(); double endPointX = to.getX(); double endPointY = to.getY(); 

技術的な解決策ではなく、問題のあるドメインから名前を取得します。例:SHIP_ICONは、Shipクラス内に別の定数がない限り、SHIPにする必要があります。 。

コメント

コメントでコードがの理由を説明する必要があります。他のすべてのコメントを削除します。

コメントは、実装者が満たさなければならない契約が含まれているインターフェースまたは抽象メソッドでのみ使用する必要があります。

定数クラス

一緒に属するものをまとめます。それらを使用するクラスで定数を定義します。

コメント

  • すべての有効なポイントであり、非常に役立ちます。ありがとうございました!

回答

すでにいくつかの良い回答がありますが、私は立っていたもののいくつかを追加したいと思いましたコードを調べたときに私にわかりました。

現時点では、入力のソースはスキャナーからのユーザー入力のみです。これにより、ある種のコンピューターの対戦相手を追加する場合は非常に困難になります。対戦します。

Boardクラスには、Playerクラスに適したコードがあるようです。

具体的には、placeShipsOnBoard()メソッドの内容です。

p>

このメソッドは、ユーザーからの入力を受け取り、位置を作成します。プレーヤー(人間またはコンピューター)が位置を作成できるように、これを再構築してみましょう。

インターフェイス

public interface Player { Position placeNextShip(); void fireAt(Position target); } 

すでに人間からの実装があります

public class HumanPlayer implements Player { // variables @Override public Position placeNextShip(){ // uses Scanner instance to create a Position } @Override public void fireAt(Position target){ // code from your attack method } } 

そしてどうですか基本的なコンピュータープレーヤー

public class DumbComputer implements Player { @Override public Position placeNextShip(){ // keep choosing random locations } @Override public void fireAt(Position target){ // keep firing at random positions } } 

次に、メインボードクラスで、プレーヤーインターフェイスにプログラムします

while(!isShipPlacementLegal){ for(Player player : players){ // some list of players in the game // either scanner input or randomly generated Position Position shipPlacement = player.placeNextShip(); boolean validPosition = validatePos(shipPlacement); if(validPostion){ // good to go! Place ship and continue to next player } else { // prompt again, whatever else you need to do here. } } } 

すべてのコードが具体的な実装ではなくプレーヤー(現在はインターフェイス)を参照している場合、新しいタイプのコンピュータープレーヤーを簡単に追加できます。例えば新しいCheatingComputer()、新しいHardComputer()、新しいMediumComputer()。それぞれが次に発砲する場所と次の船を配置する場所を異なる方法で決定するだけです。

そして、これがあれば、2人のコンピュータープレーヤーでゲームを作成し、それ自体をプレイさせることができます。エキサイティングな権利:D

変更できるもう1つの関連事項は、Gameのコンストラクターでは、常に2人の人間のプレイヤーがいることです。これにプレーヤーのリストを取得させることができるので、ゲームに任意の数のプレーヤーを含めることができます。実際のゲームの戦艦が2人のプレイヤーに制限されているからといって、あなたがそうしなければならないという意味ではありません。

グリッドサイズと任意のプレイヤー数を調整できるようにすることができます。突然、100x100グリッドと8のグリッドができました。プレイヤーはすべて無料です!

(コンピューターで制御できます)

船もボードクラスの静的ブロックで初期化されます。実際の船はすべて揃っています。戦艦からです。しかし、ここでも柔軟性を高めてみませんか。船がポイントのリストで構成されている場合はどうでしょうか。S字型の船を使用できれば、水平方向の垂直方向の配置に限定する必要はありません。 (これはやり過ぎかもしれませんが、「考えるのはクールなことだと思います!)

私にとって面白そうないくつかの小さなことで終わります

throw new ArrayIndexOutOfBoundsException(); 

Positionクラスから。これは、ここでスローするには不適切な例外のようです。 Positionクラスには配列がないため、これはBoardクラスの配列を参照している必要があります。より適切な例外タイプはIllegalArgumentExceptionであると思います。ArrayIndexOutofBoundsExceptionは(別のクラスの)実装の詳細です。また、例外をスローするとともに、適切なエラーメッセージを必ず提供してください。たとえば、「値はxとyの範囲内にある必要があります」

boolean isShipHit = (ship != null) ? true : false; 

簡単に置き換えることができます

boolean isShipHit = ship != null; 

ここでは三項演算子は必要ありません。

targetHistoryの使用Playerクラスでwhile(targetHistory.get(point)!= null)

ここでは、要素が含まれているかどうかを確認することのみを目的としてマップを使用しています。これがまさにセットです。 for!

targetHistory = new HashSet<>(); while(targetHistory.contains(point)){ // re-prompt } 

コメント

  • 洞察に感謝します!これらの回答はすべてそれぞれを補完しますその他は本当にうまくいっています!’バージョン2.0で作業を開始しますこのすべてを念頭に置いてください。
  • 問題ありません’お役に立ててうれしいです。 2.0で頑張ってください!

回答

迷惑なことこのコードで少し私は、インターフェイス、抽象クラス、または継承を使用していませんが、ここでそれらの適切な使用例を見つけることができませんでした。

ゲームではこれに問題はありません。ゲームのコンセプトはとてもシンプルなので、それらのどれも必要ありません。小さなおもちゃのプログラムの問題は、通常、大きなデザインソリューションを適用する必要がないことです。通常の SOLID設計原則に準拠していることを確認する必要があります。


これで、問題が解決されました。改善すべきコードの詳細をいくつか見てください。

最初の詳細は非常に明白です。コメントを書くためにコメントを書かないでください。一部の教師は、すべてについてjavadocコメントを書くように強制することを好みます。私は実際にはこれに完全に反対しています。ただし、他の人が使用しなければならないある種のユーティリティパッケージを作成する場合を除きます。通常、コードは自己文書化する必要があります。コードはそれで非常にうまく機能します。コメントを削除してください。基本的に、適切に選択された変数/関数の名前を繰り返します…

例:

/** * Is point between boolean. * * @param point the point * @param position the position * @return the boolean */ public static boolean isPointBetween(Point point, Position position) { 

そのコメントはどのような値を追加しますか関数に?これは、読みやすくするために変更する唯一の方法でもあると思います。位置がfromtoポイントで構成されていることは明らかではないためです。これらのポイントでpointはそれらの間にあります。

メソッドにこのシグネチャがある場合:

public static boolean containsPoint(Position position, Point point) { 

そうではありませんもう少し意味がありますか?

コメントは一般的に反対ではないことをここに追加する必要があります。ただし、コメントは、なぜそのように行われるのかを説明する必要があります。実装方法ではありません。それがどのように実装されているかを知っている私はコードを見ただけだろう。


次のポイントはそのUtilクラスを持つことです…一部の純粋主義者とは異なり、私はUtilクラスの概念に反対するものは何もありません。 。Utilクラスは、同様の関数をまとめるのに役立ちます。たとえば、java.lang.Mathはすべての通常の算術演算を1つのクラスにグループ化します。

私を悩ませているのはUtilクラスでは、それが存在する正当な理由が実際にはないということです。そこにある2つの関数は、Boardクラス内でのみ使用されます。したがって、「そのクラス内のprivate staticヘルパー関数である可能性もあります。

実際、署名を何に変更した後でも、もう少し改善することができます。以前に提案しました。Position divではなくPositionクラス内にcontainsPoint(Position position, Point point) {を配置するとどうなりますか。 >メソッドのパラメータとして?それなら次のように使用できます:

Position shipPosition = //some ship"s position if(shipPosition.contains(targetPoint)) { //handle ship hit } 

そこに非常によく合いますね?


Positionsクラスと言えば。あなたのコードを見ている間、私はこれについて奇妙な感覚を持っていました。最初は、ボードを表すsomething[][]がないと思いました。コードベース全体ですべてをポイントとして表したと思いました。これは機能しますが、ボードの印刷が面倒になります。そして、Boardクラス内にchar[][]があることに気づきました。しかし、船を即座に中に入れる方が理にかなっているのではないでしょうか。中間のPositionクラスがないグリッドですか?

placeShipsOnBoard()について別の危険なことにも気づきました。ユーザーが2つの有効な座標を入力することを本当に信頼する必要がありますか?ユーザーが面白くしようとして、from =(1,1)to =(2,2)と入力した場合はどうなりますか?これを許可する必要がありますか?または、長さ5の船を入力して、from =(1,1)から=(1,1)を入力すると、基本的に船が1つの正方形に縮小されます(船から5回ヒットする必要があります)。 5人の命があります)。 「彼がこのように不正行為をするのを防ぐべきではありませんか?

船の配置を処理する別の方法を見てみましょう。まず、船を水平に配置するか垂直に配置するかをユーザーに選択させます。次に、船の左上の座標を入力してもらいます。残りのポイントは自分で計算します。

実際のメソッドの実装は次のようになります。

private Scanner scanner = new Scanner(System.in); private void placeShipsOnBoard() { System.out.printf("%nAlright - Time to place out your ships%n%n"); for(Ship ship : ships) { //awesome for-each loop is better here boolean horizontal = askValidShipDirection(); Point startingPoint = askValidStartingPoint(ship, horizontal); placeValidShip(ship, startingPoint, boolean horizontal); } } private boolean askValidShipDirection() { do { System.out.println("Do you want to place the ship horizontally (H) or vertically (V)?"); String direction = Scanner.nextLine().trim(); while ( !"H".equals(direction) && !"V".equals(direction); return "H".equals(direction); //note here: use "constant".equals(variable) so nullpointer is impossible. //probably not needed, but it"s best practice in general. } private Point askValidStartingPoint(Ship ship, boolean horizontal) { do { //note: do-while more useful here System.out.printf("%nEnter position of %s (length %d): ", ship.getName(), ship.getSize()); Point from = new Point(scanner.nextInt(), scanner.nextInt()); while(!isValidStartingPoint(from, ship.getLength(), horizontal)); return from; } private boolean isValidStartingPoint(Point from, int length, boolean horizontal) { int xDiff = 0; int yDiff = 0; if(horizontal) { xDiff = 1; } else { yDiff = 1; } for(int i = 0; i < lenth; i++) { if(!isInsideBoard(i,from.getY()) { return false; } if(!Constants.BOARD_ICON.equals(board[from.getY()+i*yDiff][from.getX()+i*xDiff])){ return false; } } return true; } private boolean isInsideBoard(int x, int y){ return x <= Constants.BOARD_SIZE && x >= 0 && y <= Constants.BOARD_SIZE && y >= 0 && x <= Constants.BOARD_SIZE && x >= 0 && y <= Constants.BOARD_SIZE && y >= 0; } private void placeValidShip(Ship ship, Point startingPoint, boolean horizontal) { int xDiff = 0; int yDiff = 0; if(horizontal) { xDiff = 1; } else { yDiff = 1; } for(int i = 0; i < ship.getLenth() ; i++) { board[ship.getY() + i*yDiff][ship.getX()+i*xDiff] = Constants.SHIP_ICON; } } 

これで、船をボードに直接配置すると、Positionクラスとそのすべての参照を削除できます。これは、船が沈んだかどうかがわからなくなったことを意味します。

これを入力しているときに、@ TimothyTruckleがすでに回答を投稿していることに気付きました。ボードを表すためにcharの代わりに専用のFieldを使用するという彼のソリューションが本当に気に入っています。

so配置船の方法が次のように変更されます:

private void placeValidShip(Ship ship, Point startingPoint, boolean horizontal) { int xDiff = 0; int yDiff = 0; if(horizontal) { xDiff = 1; } else { yDiff = 1; } for(int i = 0; i < ship.getLenth() ; i++) { board[ship.getY() + i*yDiff][ship.getX()+i*xDiff] = new ShipField(ship); } } 

これにより、。

この回答を続ける代わりに、@ Timothyも読んで、両方の回答の良い点を確認することをお勧めします。一見、私たちはお互いの答えに同意するか、単に補完し合うかのどちらかです。したがって、コードを改善する方法について、適切な指針が必要です:)

コメント

  • 詳細なレビューをありがとうございました!皆さんは確かな意見を述べています。すべての回答がとても良かったので、’回答した人にチェックマークを付けます最初に。
  • ahem “これはゲームに問題はありません。ゲームのコンセプトは非常にシンプルなので’これらのいずれも必要ありません。”-同意しない必要があります:’練習する方が良い最初にイージーモードで何でも。’シンプルなものに概念やパターンを適用できない場合は、’より複雑なものにそれらを適用しないでください。
  • コメントに関する部分は特に重要です。冗長なコメントは、wrに時間とエネルギーを完全に浪費します。 ite、maintain、verify。自分自身を説明するコードと関数を取得できない場合にのみコメントしてください。

回答

他の回答ではほとんどすべてが指摘されているので、1つだけ追加します。 どういうわけかフロー制御を実行するために例外を使用していると私には思います。 例外は制御フローメカニズムではありません

public Position(Point from, Point to) { if (from.getX() > Constants.BOARD_SIZE || from.getX() < 0 || from.getY() > Constants.BOARD_SIZE || from.getY() < 0 || to.getX() > Constants.BOARD_SIZE || to.getX() < 0 || to.getY() > Constants.BOARD_SIZE || to.getY() < 0) { throw new ArrayIndexOutOfBoundsException(); } this.from = from; this.to = to; } 

そして

} catch (IndexOutOfBoundsException e) { System.out.println("Invalid coordinates - Outside board"); } 

Positionを作成する前に、指定された座標がボード内にあることを確認する必要があると思います。 これはユーザー入力であり、それを行うのに完全に合理的です。 あなたはすでにそのship.getSize() != Utils.distanceBetweenPoints(from, to)を検証しています。Boardオブジェクト自体でそれを行うこともできます。その後、Boardの位置をチェックします。 div id = “7108ca8522”>

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です