1+ /*
2+ * Board.java - blueprint class for objects that represent a board
3+ * in the game of Battleship.
4+ *
5+ * Computer Science 111, Boston University
6+ *
7+ * ********* YOU SHOULD NOT EDIT THIS FILE. *********
8+ */
9+
10+ import java .util .*;
11+
12+ public class Board {
13+ // The three possible states for a cell on the board.
14+ public static final int EMPTY = 0 ;
15+ public static final int UNHIT = 1 ;
16+ public static final int HIT = 2 ;
17+ public static final int MISS = 3 ;
18+
19+ public static final int VERTICAL = 0 ;
20+ public static final int HORIZONTAL = 1 ;
21+
22+ public static final Random RAND = new Random ();
23+
24+ private int dimension ;
25+ private int [][] status ; // status of each position on the board
26+ private Ship [][] shipAt ; // the ship (if any) located at each position
27+ private int shipsRemaining ; // number of unsunk ships
28+
29+ /*
30+ * constructor for a Board with the specified dimension
31+ */
32+ public Board (int dimension ) {
33+ this .dimension = dimension ;
34+
35+ // Initially, the array will be filled with 0s,
36+ // which corresponds to all of the positions being empty.
37+ this .status = new int [dimension ][dimension ];
38+
39+ // Initially, the array will be filled with nulls,
40+ // which corresponds to all of the positions having no ships.
41+ this .shipAt = new Ship [dimension ][dimension ];
42+
43+ // This will increase as ships are added by the addShip method.
44+ this .shipsRemaining = 0 ;
45+ }
46+
47+ /*
48+ * getDimension - returns the dimension of the board
49+ */
50+ public int getDimension () {
51+ return this .dimension ;
52+ }
53+
54+ /*
55+ * getShipsRemaining - returns the number of unsunk ships on the board
56+ */
57+ public int getShipsRemaining () {
58+ return this .shipsRemaining ;
59+ }
60+
61+ /*
62+ * addShip - add the specified ship to the board
63+ * at a randomly selected location.
64+ */
65+ public void addShip (Ship ship ) {
66+ int startRow , startCol , direction ;
67+ int dRow , dCol ;
68+
69+ // Find a position and direction that works.
70+ do {
71+ startRow = RAND .nextInt (dimension );
72+ startCol = RAND .nextInt (dimension );
73+ direction = RAND .nextInt (2 );
74+ if (direction == VERTICAL ) {
75+ dRow = 1 ;
76+ dCol = 0 ;
77+ } else { // HORIZONTAL
78+ dRow = 0 ;
79+ dCol = 1 ;
80+ }
81+ } while (!this .canPlaceShip (ship .getLength (), startRow , startCol , dRow , dCol ));
82+
83+ // Update the status and shipAt arrays.
84+ int row = startRow ;
85+ int col = startCol ;
86+ for (int i = 0 ; i < ship .getLength (); i ++) {
87+ this .status [row ][col ] = UNHIT ;
88+ this .shipAt [row ][col ] = ship ;
89+ row += dRow ;
90+ col += dCol ;
91+ }
92+
93+ this .shipsRemaining ++;
94+ }
95+
96+ /*
97+ * canPlaceShip - determines if a ship with the specified length
98+ * can be placed on the board at the starting position
99+ * (startRow, startCol) and with the specified change in row (dRow)
100+ * and change in column (dColumn).
101+ *
102+ * Returns true if a ship can be placed there, and false if it cannot.
103+ *
104+ * This method is private, because we only want it to be accessible
105+ * by other Board methods.
106+ */
107+ private boolean canPlaceShip (int length , int startRow , int startCol , int dRow , int dCol ) {
108+ // Check all of the positions that would be occupied by the ship.
109+ int row = startRow ;
110+ int col = startCol ;
111+ for (int i = 0 ; i < length ; i ++) {
112+ if (row < 0 || row >= this .dimension ||
113+ col < 0 || col >= this .dimension ||
114+ this .status [row ][col ] != EMPTY ) {
115+ return false ;
116+ }
117+ row += dRow ;
118+ col += dCol ;
119+ }
120+
121+ // If we get here, all of the positions must have been valid
122+ // and unoccupied.
123+ return true ;
124+ }
125+
126+ /*
127+ * applyGuess - applies the specified guess to the board,
128+ * updating the state accordingly.
129+ *
130+ * If the guess is a hit, the method returns the hit ship.
131+ * Otherwise, it returns null.
132+ */
133+ public Ship applyGuess (Guess guess ) {
134+ if (guess == null ) {
135+ throw new IllegalArgumentException ("guess cannot be null" );
136+ }
137+
138+ int row = guess .getRow ();
139+ int col = guess .getColumn ();
140+
141+ // Previously tried cell.
142+ if (this .previousHit (row , col ) || this .previousMiss (row , col )) {
143+ return null ;
144+ }
145+
146+ // Process a miss.
147+ if (this .status [row ][col ] == EMPTY ) {
148+ this .status [row ][col ] = MISS ;
149+ return null ;
150+ }
151+
152+ // Process a hit.
153+ this .status [row ][col ] = HIT ;
154+ Ship hitShip = this .shipAt [row ][col ];
155+ hitShip .applyHit ();
156+ if (hitShip .isSunk ()) {
157+ this .shipsRemaining --;
158+ }
159+ return hitShip ;
160+ }
161+
162+ /*
163+ * previousHit - has the position at (row, col) already been
164+ * the location of a hit?
165+ * Returns true if it has, and false otherwise.
166+ */
167+ public boolean previousHit (int row , int col ) {
168+ return (this .status [row ][col ] == HIT || this .sunkShipAt (row , col ));
169+ }
170+
171+ /*
172+ * previousMiss - has the position at (row, col) already been the
173+ * location of a miss?
174+ * Returns true if it has, and false otherwise.
175+ */
176+ public boolean previousMiss (int row , int col ) {
177+ return (this .status [row ][col ] == MISS );
178+ }
179+
180+ /*
181+ * hasBeenTried - has the position at (row, col) already been
182+ * tried by a previous guess (either a hit or a miss)?
183+ * Returns true if it has, and false otherwise.
184+ */
185+ public boolean hasBeenTried (int row , int col ) {
186+ return (this .previousHit (row , col ) || this .previousMiss (row , col ));
187+ }
188+
189+ /*
190+ * sunkShipAt - is their a sunk ship at the position (row, col)?
191+ * Returns true if there is, and false otherwise.
192+ */
193+ public boolean sunkShipAt (int row , int col ) {
194+ return (this .shipAt [row ][col ] != null && this .shipAt [row ][col ].isSunk ());
195+ }
196+
197+ /*
198+ * getSymbol - returns the single-character symbol that should be
199+ * used for printing the position (row, col) when the board
200+ * is displayed
201+ */
202+ public char getSymbol (int row , int col ) {
203+ if (this .status [row ][col ] == EMPTY ) {
204+ return ' ' ;
205+ } else if (this .previousHit (row , col )) {
206+ return 'X' ;
207+ } else if (this .previousMiss (row , col )) {
208+ return '-' ;
209+ } else {
210+ return this .shipAt [row ][col ].getSymbol ();
211+ }
212+ }
213+
214+ /*
215+ * display - displays the current state of the board,
216+ * calling getSymbol to determine what character to print
217+ * for each position.
218+ */
219+ public void display () {
220+ // Print the column numbers.
221+ System .out .print (" " );
222+ for (int col = 0 ; col < this .dimension ; col ++) {
223+ System .out .printf ("%3d" , col );
224+ }
225+ System .out .println ();
226+
227+ // Print the rows, one at a time.
228+ for (int row = 0 ; row < this .dimension ; row ++) {
229+ System .out .printf ("%3d:" , row );
230+ for (int col = 0 ; col < this .dimension ; col ++) {
231+ System .out .print (" " + this .getSymbol (row , col ) + " " );
232+ }
233+ System .out .println ();
234+ }
235+
236+ System .out .println ();
237+ }
238+ }
0 commit comments