// checks if two ships overlap public bool intersectsWith(Ship s) { bool boundsOK = false; bool parallel = false; if (!(this.orient || s.isVert)) // (easy case) both are horizontally placed { parallel = this.stPos.X != s.stPosit.X; boundsOK = checkBounds(this.stPos.Y, s.stPosit.Y, this.length, s.Length); return (!(parallel || boundsOK)); } else { if (this.orient && s.isVert) // (easy case) both are vertically placed { parallel = this.stPos.Y != s.stPosit.Y; boundsOK = checkBounds(this.stPos.X, s.stPosit.X, this.length, s.Length); return (!(parallel || boundsOK)); } else // (more complicated case) one is vertical, another is horizontal { // Example: // 1) e.g. this' start pos. is (1;1), its length is 4 and it's horizontally placed // then its s1 = 1, end point = (1;5), // 2) e.g. s's start pos. is (3;4), its length is 3 and it's vertically placed // then its s2 = 4, end point = (5;4) // 3) check if s1 belongs to set {3,..,5} AND s2 belongs to set {1,..,5} (true means overlap) // get value of axis which does not change // e.g. for vertical, Y does not change - (1;2),(2;2),(3;2),... -> 2 // e.g. for horizontal, X does not change - (1;1),(1;2),(1;3),... -> 1 int s1 = (this.orient) ? this.stPos.Y : this.stPos.X; int s2 = (s.isVert) ? s.stPosit.Y : s.stPosit.X; // calculate respective end points of ships // e.g. horizontally placed (at (1;1), length = 4) ship's end point is (1;5) Point ps1 = (this.orient) ? new Point(this.stPos.X + (this.length - OFFSET), s1) : new Point(s1, this.stPos.Y + (this.length - OFFSET)); Point ps2 = (s.isVert) ? new Point(s.stPosit.X + (s.Length - OFFSET), s2) : new Point(s2, s.stPosit.Y + (s.Length - OFFSET)); if (this.orient && !s.isVert) // one vertically, other horizontally placed { // check if s1/s2 is between(inclusive) the start and end point on Y/X axis return (s1 >= s.stPosit.Y && s1 <= ps2.Y) && (s2 >= this.stPos.X && s2 <= ps1.X); } else // one horizontally, other vertically placed { // check if s1/s2 is between(inclusive) the start and end point on X/Y axis return (s1 >= s.stPosit.X && s1 <= ps2.X) && (s2 >= this.stPos.Y && s2 <= ps1.Y); } } } }
// checks if ship placed at point P would be within the board (grid) private bool isWithinBoard(Ship s, Point p) { return (s.isVert) ? (p.X + s.Length <= GRIDSIZE) : (p.Y + s.Length <= GRIDSIZE); }
// checks if the ship does not overlap with other ships in the list // n.b. - does not compare with itself (index used for that) private bool noOverlap(Ship s, int index) { for (int i = 0; i < ships.Count; i++) { if (i != index) { if(s.intersectsWith(ships[i])) { return false; } } } return true; }
// puts a ship to a valid position, sets up its hitboxes, // and adds it to the list of all placed ships private void addShip(Ship s) { Point pos = new Point(); bool valid = false; // place first ship if (ships.Count == 0) { do { pos = new Point(); s.stPosit = pos; valid = isWithinBoard(s, pos); } while (!valid); } else // place 2nd, 3rd ship... { valid = false; do { pos = new Point(); s.stPosit = pos; valid = isWithinBoard(s, pos) && noOverlap(s, shipsAdded); } while (!valid); } s.calcHitboxes(); ships.Add(s); Console.WriteLine("== Added a " + s.ToString() + " =="); // for easy debugging }
// instantiates and adds ships to the list of ships // would've looked slightly cleaner with factory pattern private void createShips() { Random random = new Random(System.DateTime.Now.Millisecond); int v = random.Next(ROLL_VALUE); Ship bShip = new Ship(Ship.BSHIP_LENGTH, rollPosition(v)); addShip(bShip); shipsAdded++; for (int i = 0; i < DESTROYERS; i++) { v = random.Next(ROLL_VALUE); Ship destr = new Ship(Ship.DESTR_LENGTH, rollPosition(v)); addShip(destr); shipsAdded++; } }