Origanally I wrote a program that let you play battleship against the computer.
Pretty easy:
- create a number of ships
- generate random cells for all the ships
- let the user try to guess
I implemented a way to place as many ships as possible:
If I have a 3x3 board and I want to place 4 ships that are 2 cells long, there are only few placements that allow the maximum number of ships in the board.
Example correct placement:
|1|1|O|
|2|2|4|
|3|3|4|
Example wrong placement:
|0|1|1|
|2|2|0|
|0|3|3|
Code(full code on github):
public void prepareGame(){
if (!(field_size*field_size/ship_length >= ship_numbers)){
System.out.println("Error: Game numbers are invalid");
System.exit(0);
}
for (int i = 0; i < ship_numbers; i++) {
Ships.add(new Ship();
}
ArrayList<String> toTest;
int leftToPlace = ship_numbers;
for (Ship ship : Ships){
System.out.println("generating cells for "+ship);
while(true){
toTest = generateCells();
if (!checkShips(toTest)){
if(backtrackShips(toTest, leftToPlace)){
ship.setShip(toTest);
System.out.println("success for "+ship+" "+toTest);
System.out.println();
leftToPlace--;
break;
}
}
}
}
}
private boolean backtrackShips(ArrayList<String> toBacktrack, int shipsToPlace){
boolean backtrack_result = false;
ArrayList<String> cells;
ArrayList<ArrayList<String>> givenCells = new ArrayList<>();
for (int i = 0; i < (ship_numbers - shipsToPlace); i++) {
givenCells.add(Ships.get(i).getCells());
}
//System.out.println("backtracking: "+toBacktrack);
//System.out.println("given cells before backtrack: "+ givenCells);
givenCells.add(toBacktrack);
shipsToPlace--;
for (int i = 0; i < shipsToPlace; i++) {
for (int j = 0; j < 1000; j++) {
cells = generateCells();
// check if cells lap over already chosen cells
for (ArrayList<String> list : givenCells) {
if (Collections.disjoint(list, cells)) {
backtrack_result = true;
} else if (!Collections.disjoint(list, cells)) {
backtrack_result = false;
break;
}
}
if(backtrack_result) {
givenCells.add(cells);
break;
}
}
}
if (shipsToPlace == 0) { //base-case
backtrack_result = true;
}
//System.out.println("given cells after backtrack: "+ givenCells);
return backtrack_result;
}
public boolean checkShips(ArrayList<String> cells){
boolean result = false;
for (Ship ship : Ships){
if (!Collections.disjoint(cells, ship.getCells())){
result = true;
}
}
return result;
}
If you want to know the Ship Class:
package src;
import java.util.ArrayList;
public class Ship {
ArrayList<String> cells = new ArrayList<>();
public void setShip(ArrayList<String> cells){
this.cells = cells;
}
public ArrayList<String> getCells(){
return this.cells;
}
public String checkYourself(String stringTip){
String result = "Miss";
if (this.cells.contains(stringTip)){
result = "Hit";
this.cells.remove(stringTip);
}
if (this.cells.isEmpty()) {
result = "submerged";
}
return result;
}
}
I have basically two questions.
Is this backtracking?
Where can I optimize the code?
Edit: changed naming of ships.
DotCom
?) to the question body, see How do I ask a Good Question? \$\endgroup\$dotcom
s? Why do the ships represent URLs? For the sake of readability and given the context of this question, it doesn't seem like replacing all thedotcom
s byship
s would hurt the integrity of your question. \$\endgroup\$checkDotcoms(toTest)
is currently missing. That will get the question closed by the community. \$\endgroup\$