From 8e88e25d6c3fbc9fd783aa39d834fb10105fc0ec Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 19:46:37 +0000 Subject: [PATCH] Classes in own files --- 09_Battle/java/.gitignore | 1 + 09_Battle/java/Battle.java | 195 ------------------------------------- 09_Battle/java/Input.java | 58 +++++++++++ 09_Battle/java/Sea.java | 57 +++++++++++ 09_Battle/java/Ship.java | 142 +++++++++++++++++++++++++++ 5 files changed, 258 insertions(+), 195 deletions(-) create mode 100644 09_Battle/java/.gitignore create mode 100644 09_Battle/java/Input.java create mode 100644 09_Battle/java/Sea.java create mode 100644 09_Battle/java/Ship.java diff --git a/09_Battle/java/.gitignore b/09_Battle/java/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/09_Battle/java/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/09_Battle/java/Battle.java b/09_Battle/java/Battle.java index b548292c..627906d0 100644 --- a/09_Battle/java/Battle.java +++ b/09_Battle/java/Battle.java @@ -144,199 +144,4 @@ public class Battle { catch (IOException e) { } } - - private static class Ship { - public static final int ORIENT_E=0; - public static final int ORIENT_SE=1; - public static final int ORIENT_S=2; - public static final int ORIENT_SW=3; - - private int id; - private int size; - private String type; - private boolean placed; - private boolean sunk; - private ArrayList hits; - - private int startX; - private int startY; - private int orientX; - private int orientY; - - public Ship(int i, String name, int sz) { - id = i; type = name; size = sz; - sunk = false; placed = false; - hits = new ArrayList<>(Collections.nCopies(size, false)); - } - - public int id() { return id; } - public int size() { return size; } - - public void hit(int x, int y) { - int offset; - if (orientX != 0) { - offset = (x - startX) / orientX; - } else { - offset = (y - startY) / orientY; - } - hits.set(offset, true); - - sunk = hits.stream().allMatch(Predicate.isEqual(true)); - } - - public boolean isSunk() { return sunk; } - - public boolean wasHit(int x, int y) { - int offset; - if (orientX != 0) { - offset = (x - startX) / orientX; - } else { - offset = (y - startY) / orientY; - } - return hits.get(offset); - }; - - public void placeRandom(Sea s) { - Random random = new Random(); - for (int tries = 0 ; tries < 1000 ; ++tries) { - int x = random.nextInt(s.size()); - int y = random.nextInt(s.size()); - int orient = random.nextInt(4); - - if (place(s, x, y, orient)) return; - } - - throw new RuntimeException("Could not place any more ships"); - } - - private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { - if (!s.isEmpty(toX, toY)) return false; // no space - if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical - - // we can extend the ship without colliding, but we are going diagonally - // and it should not be possible for two ships to cross each other on - // opposite diagonals. - - // check the two tiles that would cross us here - if either is empty, we are OK - // if they both contain different ships, we are OK - // but if they both contain the same ship, we are crossing! - int corner1 = s.get(fromX, toY); - int corner2 = s.get(toX, fromY); - if ((corner1 == 0) || (corner1 != corner2)) return true; - return false; - } - - public boolean place(Sea s, int x, int y, int orient) { - if (placed) { - throw new RuntimeException("Program error - placed ship " + id + " twice"); - } - switch(orient) { - case ORIENT_E: - orientX = 1; orientY = 0; - break; - case ORIENT_SE: - orientX = 1; orientY = 1; - break; - case ORIENT_S: - orientX = 0; orientY = 1; - break; - case ORIENT_SW: - orientX = -1; orientY = 1; - break; - default: - throw new RuntimeException("Invalid orientation " + orient); - } - - if (!s.isEmpty(x, y)) return false; - startX = x; startY = y; - int tilesPlaced = 1; - int nextX = startX; - int nextY = startY; - while (tilesPlaced < size) { - if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { - tilesPlaced += 1; - nextX = nextX + orientX; - nextY = nextY + orientY; - } else { - int backX = startX - orientX; - int backY = startY - orientY; - - if (extendShip(s, startX, startY, backX, backY)) { - tilesPlaced +=1; - startX = backX; - startY = backY; - } else { - return false; - } - } - } - - for (int i = 0; i < size; ++i) { - int sx = startX + i * orientX; - int sy = startY + i * orientY; - s.set(sx, sy, id); - } - placed = true; - return true; - } - - } - - private static class Sea { - private int tiles[]; - private boolean hits[]; - - private int size; - public Sea(int make_size) { - size = make_size; - tiles = new int[size*size]; - } - - public int size() { return size; } - - public String encodedDump() { - StringBuilder out = new StringBuilder(); - for (int x = 0; x < size; ++x) { - for (int y = 0; y < size; ++y) - out.append(Integer.toString(get(x, y))); - out.append('\n'); - } - return out.toString(); - } - - /* return true if x,y is in the sea and empty - * return false if x,y is occupied or is out of range - */ - public boolean isEmpty(int x, int y) { - if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; - return (get(x,y) == 0); - } - - /* return the ship number, or zero if no ship */ - public int get(int x, int y) { - return tiles[index(x,y)]; - } - - public void set(int x, int y, int value) { - tiles[index(x, y)] = value; - } - - public int shipHit(int x, int y) { - if (hits[index(x,y)]) return get(x, y); - else return 0; - } - - public void recordHit(int x, int y) { - hits[index(x, y)] = true; - } - - private int index(int x, int y) { - if ((x < 0) || (x >= size)) - throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); - if ((y < 0) || (y >= size)) - throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y); - - return y*size + x; - } - } } diff --git a/09_Battle/java/Input.java b/09_Battle/java/Input.java new file mode 100644 index 00000000..8a782dba --- /dev/null +++ b/09_Battle/java/Input.java @@ -0,0 +1,58 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.text.NumberFormat; + +public class Input { + private BufferedReader reader; + private NumberFormat parser; + private int scale; + private boolean isQuit; + private int[] coords; + + public Input(int seaSize) { + scale = seaSize; + reader = new BufferedReader(new InputStreamReader(System.in)); + parser = NumberFormat.getIntegerInstance(); + } + + public boolean readCoordinates() throws IOException { + while (true) { + System.out.print("\nTarget x,y\n> "); + String inputLine = reader.readLine(); + if (inputLine == null) { + System.out.println("Game quit\n"); + isQuit = true; + return false; + } + + String[] fields = inputLine.split(","); + if (fields.length != 2) { + System.out.println("Need two coordinates separated by ','"); + continue; + } + + coords = new int[2]; + boolean error = false; + try { + for (int c = 0 ; c < 2; ++c ) { + int val = Integer.parseInt(fields[c].strip()); + if ((val < 1) || (val > scale)) { + System.out.println("Coordinates must be from 1 to " + scale); + error = true; + } else { + coords[c] = val; + } + } + } + catch (NumberFormatException ne) { + System.out.println("Coordinates must be numbers"); + error = true; + } + if (!error) return true; + } + } + + public int x() { return coords[0]; } + public int y() { return coords[1]; } +} diff --git a/09_Battle/java/Sea.java b/09_Battle/java/Sea.java new file mode 100644 index 00000000..d9987f34 --- /dev/null +++ b/09_Battle/java/Sea.java @@ -0,0 +1,57 @@ +class Sea { + private int tiles[]; + private boolean hits[]; + + private int size; + public Sea(int make_size) { + size = make_size; + tiles = new int[size*size]; + } + + public int size() { return size; } + + public String encodedDump() { + StringBuilder out = new StringBuilder(); + for (int x = 0; x < size; ++x) { + for (int y = 0; y < size; ++y) + out.append(Integer.toString(get(x, y))); + out.append('\n'); + } + return out.toString(); + } + + /* return true if x,y is in the sea and empty + * return false if x,y is occupied or is out of range + */ + public boolean isEmpty(int x, int y) { + if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; + return (get(x,y) == 0); + } + + /* return the ship number, or zero if no ship */ + public int get(int x, int y) { + return tiles[index(x,y)]; + } + + public void set(int x, int y, int value) { + tiles[index(x, y)] = value; + } + + public int shipHit(int x, int y) { + if (hits[index(x,y)]) return get(x, y); + else return 0; + } + + public void recordHit(int x, int y) { + hits[index(x, y)] = true; + } + + private int index(int x, int y) { + if ((x < 0) || (x >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); + if ((y < 0) || (y >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y); + + return y*size + x; + } +} diff --git a/09_Battle/java/Ship.java b/09_Battle/java/Ship.java new file mode 100644 index 00000000..e3fb4f44 --- /dev/null +++ b/09_Battle/java/Ship.java @@ -0,0 +1,142 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Random; +import java.util.function.Predicate; + +class Ship { + public static final int ORIENT_E=0; + public static final int ORIENT_SE=1; + public static final int ORIENT_S=2; + public static final int ORIENT_SW=3; + + private int id; + private int size; + private String type; + private boolean placed; + private boolean sunk; + private ArrayList hits; + + private int startX; + private int startY; + private int orientX; + private int orientY; + + public Ship(int i, String name, int sz) { + id = i; type = name; size = sz; + sunk = false; placed = false; + hits = new ArrayList<>(Collections.nCopies(size, false)); + } + + public int id() { return id; } + public int size() { return size; } + + public void hit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + hits.set(offset, true); + + sunk = hits.stream().allMatch(Predicate.isEqual(true)); + } + + public boolean isSunk() { return sunk; } + + public boolean wasHit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + return hits.get(offset); + }; + + public void placeRandom(Sea s) { + Random random = new Random(); + for (int tries = 0 ; tries < 1000 ; ++tries) { + int x = random.nextInt(s.size()); + int y = random.nextInt(s.size()); + int orient = random.nextInt(4); + + if (place(s, x, y, orient)) return; + } + + throw new RuntimeException("Could not place any more ships"); + } + + private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { + if (!s.isEmpty(toX, toY)) return false; // no space + if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical + + // we can extend the ship without colliding, but we are going diagonally + // and it should not be possible for two ships to cross each other on + // opposite diagonals. + + // check the two tiles that would cross us here - if either is empty, we are OK + // if they both contain different ships, we are OK + // but if they both contain the same ship, we are crossing! + int corner1 = s.get(fromX, toY); + int corner2 = s.get(toX, fromY); + if ((corner1 == 0) || (corner1 != corner2)) return true; + return false; + } + + public boolean place(Sea s, int x, int y, int orient) { + if (placed) { + throw new RuntimeException("Program error - placed ship " + id + " twice"); + } + switch(orient) { + case ORIENT_E: + orientX = 1; orientY = 0; + break; + case ORIENT_SE: + orientX = 1; orientY = 1; + break; + case ORIENT_S: + orientX = 0; orientY = 1; + break; + case ORIENT_SW: + orientX = -1; orientY = 1; + break; + default: + throw new RuntimeException("Invalid orientation " + orient); + } + + if (!s.isEmpty(x, y)) return false; + startX = x; startY = y; + int tilesPlaced = 1; + int nextX = startX; + int nextY = startY; + while (tilesPlaced < size) { + if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { + tilesPlaced += 1; + nextX = nextX + orientX; + nextY = nextY + orientY; + } else { + int backX = startX - orientX; + int backY = startY - orientY; + + if (extendShip(s, startX, startY, backX, backY)) { + tilesPlaced +=1; + startX = backX; + startY = backY; + } else { + return false; + } + } + } + + for (int i = 0; i < size; ++i) { + int sx = startX + i * orientX; + int sy = startY + i * orientY; + s.set(sx, sy, id); + } + placed = true; + return true; + } +} +