diff --git a/shipsgame/src/main/scala/Board.scala b/shipsgame/src/main/scala/Board.scala index 042cd18..0636471 100644 --- a/shipsgame/src/main/scala/Board.scala +++ b/shipsgame/src/main/scala/Board.scala @@ -1,5 +1,6 @@ package main.battleship +import ConsoleColors._ import main.battleship.Constants.SIZE import scala.collection.mutable @@ -7,17 +8,15 @@ import scala.math.abs import main.battleship.ShipType.ShipType class Board{ - var occupied = new mutable.HashSet[(Int, Int)](); var ships = new mutable.HashSet[Ship](); - var checked = new mutable.HashSet[(Int, Int)](); - + var occupied = new mutable.HashSet[(Int, Int)](); //zawiera pola ktore sa zajete + var checked = new mutable.HashSet[(Int, Int)](); //zawiera pola ktore juz sprawdzilismy + var bombardedShipsFields = new mutable.HashSet[(Int, Int)]();//bedzie zawierac trafione POLA statkow def isEmpty(): Boolean = { occupied.isEmpty; } def addShip(xs: Int, ys: Int, xe: Int, ye: Int, ship: Option[Ship]): Boolean ={ -// var length = abs(ys - ye); to jest w shipFactory -// var width = abs(xs - xe); to jest w shipFactory //jesli ship jest none to nie dodajemy statku, tylko wypisujemy komunikat ze statek nie zostal dodany if (ship == None){ println("Statek nie zostal dodany") @@ -32,17 +31,53 @@ class Board{ true } - def printBoard(): Unit ={ - for (i <- 0 until SIZE){ - for (j <- 0 until SIZE){ + def placeShip(xs: Int, ys: Int, xe: Int, ye: Int, ship: Option[Ship],flag:Boolean=true): Boolean = { + if (ship == None) return false + //sprawdzenie czy wspolrzedne statku nie wychodza poza plansze + if (xs < 0 || xs >= SIZE || ys < 0 || ys >= SIZE || xe < 0 || xe >= SIZE || ye < 0 || ye >= SIZE) { + if(flag)println("Błędne współrzędne, statek wychodzi poza planszę.") + return false + } + // Walidacja rozmiaru statku + val shipLength = math.abs(xs - xe) + 1 + val shipWidth = math.abs(ys - ye) + 1 + if (!((shipLength == ship.get.length && shipWidth == ship.get.width) || + (shipLength == ship.get.width && shipWidth == ship.get.length))) { + if(flag)println("Rozmiar statku nie zgadza się z podanymi współrzędnymi.") + return false + } + //sprawdzenie czy statek nie pokrywa sie z innym na mapce + for (i <- math.min(xs, xe) to math.max(xs, xe)){ + for (j <- math.min(ys, ye) to math.max(ys, ye)){ if (occupied.contains((i, j))){ - print("x") + if(flag)println("Nie mozna dodac statku na to pole") + return false } - else{ - print(" ") + } + } + addShip(xs, ys, xe, ye, ship) + true + } + + + def printBoard(canShow: Boolean = true): Unit = { + println(" " + (0 until SIZE).mkString(" ")) // Wypisuje górny nagłówek + for (y <- 0 until SIZE) { + print(s"$y ") // Wypisuje indeksy z lewej strony + for (x <- 0 until SIZE) { + if (occupied.contains((x, y)) && canShow) {//canShow - flaga mowiaca, czy mozna pole pokazac + print(Green + "N " + Reset) + } else if (bombardedShipsFields.contains((x, y))) { + print(Red + "x " + Reset) + } else if (checked.contains((x, y))) { + print(Yellow + "- " + Reset) // nowy znak dla chybionych pól + } else { + print(Blue + "o " + Reset) } } + println() } + println(" " + (0 until SIZE).mkString(" ")) // Wypisuje dolny nagłówek } @@ -58,9 +93,14 @@ class Board{ } def tryAttack(x: Int, y: Int): Boolean = { + if(alreadyChecked(x,y)){ + println("To pole juz zostalo sprawdzone") + return false + } + checked.add((x, y)) //wykorzystane pole wiec dodajemy do checked if (occupied.contains((x, y))) { occupied.remove((x, y)) - checked.add((x, y)) //wykorzystane pole wiec dodajemy do checked + bombardedShipsFields.add((x, y)) //wykorzystane pole wiec dodajemy do checked true } else { false diff --git a/shipsgame/src/main/scala/ComputerUser.scala b/shipsgame/src/main/scala/ComputerUser.scala index 15154f2..bd6fb6e 100644 --- a/shipsgame/src/main/scala/ComputerUser.scala +++ b/shipsgame/src/main/scala/ComputerUser.scala @@ -1,5 +1,6 @@ package main.battleship import Constants._ +import main.battleship.SimpleUser.trials import scala.util.Random @@ -8,21 +9,46 @@ object ComputerUser extends User { var enemy_board: Board = new Board var points: Int = 0 var trials: Int = 0 - override def attack(x_x:Int=1,y_y:Int=1): Unit = {//pomysl: zrobic bardziej inteligentnego kompa, ktory bedzie wiedzial gdzie strzelac, - //np. jesli trafil to strzelaj wokol tego miejsca, jesli nie to strzelaj losowo + var state: String = "Hunt" + var lastHitX: Int = -1 + var lastHitY: Int = -1 - var x = Random.nextInt(10) - var y = Random.nextInt(10) + override def attack(x_x: Int = 1, y_y: Int = 1): Unit = { + trials+=1 + if (state == "Hunt") { + var x = Random.nextInt(SIZE) + var y = Random.nextInt(SIZE) - if (enemy_board.alreadyChecked(x, y)) println("Komputer trafil w pole wczesniej trafione!") - else if (enemy_board.tryAttack(x, y)) { //od razu usuwanie wektora z enemy_board jesli sie powiedzie atak - println(s"Komputer trafil na polu ($x, $y)!") - points += ACQUIRED_POINTS - } else { - println(s"Komputer chybil na polu ($x, $y).") - points -= LOST_POINTS + if (enemy_board.tryAttack(x, y)) { + println(s"Komputer trafił na polu ($x, $y)!") + points += ACQUIRED_POINTS + state = "Target" + lastHitX = x + lastHitY = y + } else { + println(s"Komputer chybił na polu ($x, $y).") + points = Math.max(points - LOST_POINTS,0) + } + } else if (state == "Target") { + val directions = Array((-1, 0), (1, 0), (0, -1), (0, 1)) // left, right, up, down + for ((dx, dy) <- directions) { + val x = lastHitX + dx + val y = lastHitY + dy + if (x >= 0 && x < SIZE && y >= 0 && y < SIZE && !enemy_board.alreadyChecked(x, y)) { + if (enemy_board.tryAttack(x, y)) { + println(s"Komputer trafił na polu ($x, $y)!") + points += 5 + lastHitX = x + lastHitY = y + } else { + println(s"Komputer chybił na polu ($x, $y).") + points -= 1 + } + return + } + } + state = "Hunt" } - trials+=1 } override def isDefeated(): Boolean = { diff --git a/shipsgame/src/main/scala/ConsoleColors.scala b/shipsgame/src/main/scala/ConsoleColors.scala new file mode 100644 index 0000000..af9afd7 --- /dev/null +++ b/shipsgame/src/main/scala/ConsoleColors.scala @@ -0,0 +1,13 @@ +package main.battleship +object ConsoleColors { + val Reset = "\u001b[0m" + val Black = "\u001b[30m" + val Red = "\u001b[31m" + val Green = "\u001b[32m" + val Yellow = "\u001b[33m" + val Blue = "\u001b[34m" + val Magenta = "\u001b[35m" + val Cyan = "\u001b[36m" + val White = "\u001b[37m" +} + diff --git a/shipsgame/src/main/scala/Engine.scala b/shipsgame/src/main/scala/Engine.scala index 30116aa..b0ab006 100644 --- a/shipsgame/src/main/scala/Engine.scala +++ b/shipsgame/src/main/scala/Engine.scala @@ -1,12 +1,129 @@ +package main.battleship + +import main.battleship.Constants.SIZE + +import scala.io.StdIn.readLine +import scala.util.Random + object Engine { //dodaj tworzymy statki na mape + val user: User = SimpleUser + val computer: User = ComputerUser + val shipFactUser: ShipFactory = new ShipFactory + val shipFactComp: ShipFactory = new ShipFactory + def connectUsers():Unit={ + user.enemy_board=computer.board + computer.enemy_board=user.board + } def makeShips() = { + var coordinates: Array[Int] = Array(0, 0, 0, 0) + while(!shipFactUser.everyTypeUsed()) { + var ship: Option[Ship] = None + user.board.printBoard() + shipFactUser.printShips() + var shipTypeInput: String = "" + do{ + println("Wybierz poprawny typ statku:") + shipTypeInput = readLine() + ship = shipFactUser.createShip(shipTypeInput) + }while(ship == None) + do{ + println("Podaj współrzędne (x0, y0, x1, y1):") + coordinates = getFourElementCoordinates() + }while(!user.board.placeShip(coordinates(0), coordinates(1), coordinates(2), coordinates(3), ship)) + } + user.board.printBoard() + } + + def makeShipsComp() = { + // Rozmieszczenie statków komputera + ShipType.values.foreach { shipType => + var ship: Option[Ship] = None + ship = shipFactComp.createShip(shipType.toString) + var coordinates = Array.fill(4)(Random.nextInt(SIZE)) + while (!computer.board.placeShip(coordinates(0), coordinates(1), coordinates(2), coordinates(3),ship,false)) { + coordinates = Array.fill(4)(Random.nextInt(SIZE)) + } + } } //ta wlasciwa gra - def properGame():Unit = { + def properGame(): Unit = { + while (true) { + stats() + println("\n\n--------Plansza usera---------\n\n") + user.board.printBoard() + println("\n\n--------Plansza wroga---------\n\n") + computer.board.printBoard(false) + println("Podaj koordynaty ataku (x, y):") + + val coordinates = getCoordinates() + + user.attack(coordinates(0), coordinates(1)) + if (computer.isDefeated()) { + println("Gratuluje wygrales!") + stats() + System.exit(1) + } + + computer.attack(-1, -1) + if (user.isDefeated()) { + println("Gratuluje przegrałeś!") + stats() + System.exit(1) + } + } + } + def stats():Unit = { + println(s"Statystyki usera: \nIlosc punktow: ${user.points}\nIlosc prob: ${user.trials}") + println(s"Statystyki wroga: \nIlosc punktow: ${computer.points}\nIlosc prob: ${computer.trials}") + } + + def getCoordinates(): Array[Int] = { + while (true) { + try { + val input = readLine() + val coordinates = input.split(",").map(_.trim.toInt) + if (coordinates.length != 2) { + throw new IllegalArgumentException("Wprowadzony ciąg znaków powinien zawierać dwie współrzędne oddzielone przecinkiem.") + } + return coordinates + } catch { + case _: NumberFormatException => + println("Wprowadzone współrzędne powinny być liczbami całkowitymi. Spróbuj ponownie.") + case e: IllegalArgumentException => + println(e.getMessage) + } + } + Array() + } + + def getFourElementCoordinates(): Array[Int] = { + while (true) { + try { + val input = readLine() + val coordinates = input.split(",").map(_.trim.toInt) + if (coordinates.length != 4) { + throw new IllegalArgumentException("Wprowadzony ciąg znaków powinien zawierać cztery współrzędne oddzielone przecinkami.") + } + return coordinates + } catch { + case _: NumberFormatException => + println("Wprowadzone współrzędne powinny być liczbami całkowitymi. Spróbuj ponownie.") + case e: IllegalArgumentException => + println(e.getMessage) + } + } + Array() + } + + def run():Unit = { + connectUsers() + makeShips() + makeShipsComp() + properGame() } } diff --git a/shipsgame/src/main/scala/Main.scala b/shipsgame/src/main/scala/Main.scala index 82fb372..f5685bf 100644 --- a/shipsgame/src/main/scala/Main.scala +++ b/shipsgame/src/main/scala/Main.scala @@ -1,30 +1,8 @@ -import main.battleship.ShipFactory +import main.battleship.Engine object Main { def main(args: Array[String]): Unit = { - println("Hello world!") - val factory = new ShipFactory() - - // Wyświetlanie dostępnych statków - factory.printShips() - - // Próba utworzenia statku nieistniejącego typu - println(factory.createShip("Type0")) - - // Utworzenie statku typu 1 - println(factory.createShip("Type1")) - - // Próba utworzenia statku typu 1 jeszcze raz - println(factory.createShip("Type1")) - - // Wyświetlanie dostępnych statków po utworzeniu statku typu 1 - factory.printShips() - - // Utworzenie statku typu 2 - println(factory.createShip("Type2")) - - // Wyświetlanie dostępnych statków po utworzeniu statku typu 2 - factory.printShips() + Engine.run() } } diff --git a/shipsgame/src/main/scala/Ship.scala b/shipsgame/src/main/scala/Ship.scala index 969ee3c..05885b3 100644 --- a/shipsgame/src/main/scala/Ship.scala +++ b/shipsgame/src/main/scala/Ship.scala @@ -1,7 +1,7 @@ package main.battleship -class Ship(val shipType: ShipType.Value, val length: Int, val width: Int) { +class Ship(val shipType: ShipType.Value,val length: Int, val width: Int) { val size: Int = length * width var occupied_fields: Int = size diff --git a/shipsgame/src/main/scala/ShipFactory.scala b/shipsgame/src/main/scala/ShipFactory.scala index 52a08d0..86fda26 100644 --- a/shipsgame/src/main/scala/ShipFactory.scala +++ b/shipsgame/src/main/scala/ShipFactory.scala @@ -7,7 +7,7 @@ class ShipFactory { def checkIfUsed(shipType: ShipType.ShipType): Boolean = usedShips.contains(shipType) def addToUsed(shipType: ShipType.ShipType): Unit = usedShips += shipType - + def everyTypeUsed(): Boolean = usedShips.size == ShipType.values.size def removeFromUsed(shipType: ShipType.ShipType): Unit = usedShips.remove(shipType) def createShip(shipType: String): Option[Ship] = { diff --git a/shipsgame/src/main/scala/SimpleUser.scala b/shipsgame/src/main/scala/SimpleUser.scala index 1f38057..f65d444 100644 --- a/shipsgame/src/main/scala/SimpleUser.scala +++ b/shipsgame/src/main/scala/SimpleUser.scala @@ -1,5 +1,6 @@ package main.battleship import Constants._ +import main.battleship.ComputerUser.points object SimpleUser extends User { var board: Board = new Board var enemy_board: Board = new Board @@ -13,7 +14,7 @@ object SimpleUser extends User { points += ACQUIRED_POINTS } else { println(s"Chybiłeś na polu ($x, $y).") - points -= LOST_POINTS + points = Math.max(points - LOST_POINTS,0) } trials+=1 } diff --git a/shipsgame/src/test/scala/Test.scala b/shipsgame/src/test/scala/Test.scala index ba573d4..3f7f85a 100644 --- a/shipsgame/src/test/scala/Test.scala +++ b/shipsgame/src/test/scala/Test.scala @@ -36,7 +36,7 @@ class Test extends AnyFunSuite{ assert(board.occupied.contains(3, 2)) assert(board.alreadyChecked(4, 2) === true) - assert(board.alreadyChecked(7, 8) === false) + assert(board.alreadyChecked(7, 8) === true) } }