diff --git a/src/App.php b/src/App.php index 6c668e2..4713009 100644 --- a/src/App.php +++ b/src/App.php @@ -9,6 +9,9 @@ class App { private static $myFleet = array(); private static $enemyFleet = array(); + + private static $fleetNumber; + private static $console; static function run() @@ -35,31 +38,29 @@ static function run() self::StartGame(); } - public static function InitializeEnemyFleet() + public static function InitializeEnemyFleet(int $fleetNumber) { self::$enemyFleet = GameController::initializeShips(); - array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 4)); - array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 5)); - array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 6)); - array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 7)); - array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 8)); - - array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 6)); - array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 7)); - array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 8)); - array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 9)); - - array_push(self::$enemyFleet[2]->getPositions(), new Position('A', 3)); - array_push(self::$enemyFleet[2]->getPositions(), new Position('B', 3)); - array_push(self::$enemyFleet[2]->getPositions(), new Position('C', 3)); - - array_push(self::$enemyFleet[3]->getPositions(), new Position('F', 8)); - array_push(self::$enemyFleet[3]->getPositions(), new Position('G', 8)); - array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 8)); - - array_push(self::$enemyFleet[4]->getPositions(), new Position('C', 5)); - array_push(self::$enemyFleet[4]->getPositions(), new Position('C', 6)); + switch ($fleetNumber) { + case 1: + self::initializeFleet1(); + break; + case 2: + self::initializeFleet2(); + break; + case 3: + self::initializeFleet3(); + break; + case 4: + self::initializeFleet4(); + break; + case 5: + self::initializeFleet5(); + break; + default: + throw new Exception("Invalid fleet number"); + } } public static function getRandomPosition() @@ -77,19 +78,109 @@ public static function InitializeMyFleet() { self::$myFleet = GameController::initializeShips(); - self::$console->println("Please position your fleet (Game board has size from A to H and 1 to 8) :"); + self::$console->printColoredLn("Set up your fleet (board size is from A to H and 1 to 8):", Color::YELLOW); + self::$console->printColoredLn("Directions: R - Right, D - Down", Color::YELLOW); foreach (self::$myFleet as $ship) { + while (true) { + try { + self::$console->println(); + self::$console->printColoredLn( + sprintf("Enter positions for %s (size: %s)", $ship->getName(), $ship->getSize()), + Color::YELLOW + ); + + self::$console->println("Enter starting position (e.g. A3):"); + $start = readline(""); + $startPos = self::parsePosition($start); + + self::$console->println("Enter direction (R/D):"); + $direction = strtoupper(readline("")); + + if (!in_array($direction, ['R', 'D'])) { + throw new Exception("Invalid direction! Use R (Right) or D (Down)."); + } + + // Early validation for ship bounds + if ($direction === 'R') { + $endColIndex = array_search($startPos->getColumn(), Letter::$letters) + ($ship->getSize() - 1); + if ($endColIndex >= count(Letter::$letters)) { + throw new Exception("Ship cannot be placed here - it would go off the board to the right!"); + } + } else { // direction is 'D' + $endRow = $startPos->getRow() + ($ship->getSize() - 1); + if ($endRow > 8) { + throw new Exception("Ship cannot be placed here - it would go off the board downwards!"); + } + } + + // Calculate all ship positions + $shipPositions = self::calculateShipPositions($startPos, $direction, $ship->getSize()); + + // Validate collisions with other ships + foreach ($shipPositions as $position) { + $pos = self::parsePosition($position); + if (self::isCollisionWithOtherShips($pos, self::$myFleet)) { + throw new Exception("Ships cannot be placed adjacent to each other!"); + } + } + + // Add positions to ship + foreach ($shipPositions as $position) { + $ship->addPosition(self::parsePosition($position)); + } + + break; // Exit loop if successful + + } catch (Exception $e) { + self::$console->printColoredLn("Error: " . $e->getMessage(), Color::RED); + self::$console->println("Please try again."); + } + } + } + } - self::$console->println(); - printf("Please enter the positions for the %s (size: %s)", $ship->getName(), $ship->getSize()); + private static function isCollisionWithOtherShips(Position $position, array $fleet): bool + { + foreach ($fleet as $ship) { + foreach ($ship->getPositions() as $shipPosition) { + // Sprawdź bezpośrednią kolizję + if ($position->getColumn() === $shipPosition->getColumn() && + $position->getRow() === $shipPosition->getRow()) { + return true; + } + + } + } + return false; + } - for ($i = 1; $i <= $ship->getSize(); $i++) { - printf("\nEnter position %s of %s (i.e A3):", $i, $ship->getSize()); - $input = readline(""); - $ship->addPosition($input); + private static function isPositionValid(Position $position): bool + { + $col = array_search($position->getColumn(), Letter::$letters); + $row = $position->getRow(); + + return $col >= 0 && $col < 8 && $row >= 1 && $row <= 8; + } + + private static function calculateShipPositions(Position $start, string $direction, int $size): array + { + $positions = []; + $startCol = array_search($start->getColumn(), Letter::$letters); + $startRow = $start->getRow(); + + for ($i = 0; $i < $size; $i++) { + switch ($direction) { + case 'D': + $positions[] = $start->getColumn() . ($startRow + $i); + break; + case 'R': + $positions[] = Letter::$letters[$startCol + $i] . $startRow; + break; } } + + return $positions; } public static function beep() @@ -99,12 +190,15 @@ public static function beep() public static function InitializeGame() { + self::$fleetNumber = random_int(1, 5); + self::InitializeMyFleet(); - self::InitializeEnemyFleet(); + self::InitializeEnemyFleet(self::$fleetNumber); } public static function StartGame() { + self::$console->setForegroundColor(Color::YELLOW); self::$console->println("\033[2J\033[;H"); self::$console->println(" __"); self::$console->println(" / \\"); @@ -116,15 +210,29 @@ public static function StartGame() self::$console->println(" | /_\'"); self::$console->println(" \\ \\_/"); self::$console->println(" \" \"\" \"\" \"\" \""); + self::$console->resetForegroundColor(); while (true) { - self::$console->println(""); - self::$console->println("Player, it's your turn"); + self::groupVisualy("Player turn"); + self::$console->printColoredLn("Player, it's your turn", Color::YELLOW); self::$console->println("Enter coordinates for your shot :"); $position = readline(""); + if (strtolower(trim($position)) === "map#") { + self::$console->printColoredln("MAP: " . self::$fleetNumber, Color::YELLOW); + continue; + } + $isHit = GameController::checkIsHit(self::$enemyFleet, self::parsePosition($position)); + if (GameController::checkIsGameOver(self::$enemyFleet)) { + self::$console->printColoredln("You are the winner!", Color::YELLOW); + self::$console->println("\nPress Enter to quit game..."); + readline(); + exit(); + } + if ($isHit) { + self::$console->setForegroundColor(Color::RED); self::beep(); self::$console->println(" \\ . ./"); self::$console->println(" \\ .:\" \";'.:..\" \" /"); @@ -134,16 +242,28 @@ public static function StartGame() self::$console->println(" - (\\- | \\ / | /) -"); self::$console->println(" -\\ \\ / /-"); self::$console->println(" \\ \\ / /"); + self::$console->println("Yeah ! Nice hit !"); + } else { + self::$console->setForegroundColor(Color::DARK_CYAN); } - - echo $isHit ? "Yeah ! Nice hit !" : "Miss"; - self::$console->println(); + self::$console->resetForegroundColor(); $position = self::getRandomPosition(); $isHit = GameController::checkIsHit(self::$myFleet, $position); - self::$console->println(); - printf("Computer shoot in %s%s and %s", $position->getColumn(), $position->getRow(), $isHit ? "hit your ship !\n" : "miss"); + + + + self::groupVisualy("Computer turn"); if ($isHit) { + if (GameController::checkIsGameOver(self::$enemyFleet)) { + self::$console->println("You lost"); + self::$console->println("\nPress Enter to quit game..."); + readline(); + exit(); + } + + self::$console->setForegroundColor(Color::RED); + self::$console->println(sprintf("Computer shoot in %s%s and hit your ship !", $position->getColumn(), $position->getRow())); self::beep(); self::$console->println(" \\ . ./"); @@ -155,12 +275,25 @@ public static function StartGame() self::$console->println(" -\\ \\ / /-"); self::$console->println(" \\ \\ / /"); + } else { + self::$console->setForegroundColor(Color::DARK_CYAN); + self::$console->println(sprintf("Computer shoot in %s%s and miss", $position->getColumn(), $position->getRow())); } -// exit(); + self::$console->resetForegroundColor(); } } + private static function groupVisualy($text = "") + { + $length = 70 - strlen($text) - 2; + + $length1 = ceil($length / 2); + $length2 = $length - $length1; + self::$console->println(); + self::$console->println(str_repeat('-', $length1) . ' ' . $text . ' ' . str_repeat('-', $length2)); + self::$console->println(); + } public static function parsePosition($input) { $letter = substr($input, 0, 1); @@ -172,4 +305,133 @@ public static function parsePosition($input) return new Position($letter, $number); } + + private static function initializeFleet1() + { + array_push(self::$enemyFleet[0]->getPositions(), new Position('A', 1)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('A', 2)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('A', 3)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('A', 4)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('A', 5)); + + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 3)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 4)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 5)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 6)); + + array_push(self::$enemyFleet[2]->getPositions(), new Position('E', 1)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('F', 1)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('G', 1)); + + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 4)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 5)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 6)); + + array_push(self::$enemyFleet[4]->getPositions(), new Position('F', 8)); + array_push(self::$enemyFleet[4]->getPositions(), new Position('G', 8)); + } + + private static function initializeFleet2() + { + array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 2)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 3)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 4)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 5)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('B', 6)); + + array_push(self::$enemyFleet[1]->getPositions(), new Position('D', 7)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 7)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('F', 7)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('G', 7)); + + array_push(self::$enemyFleet[2]->getPositions(), new Position('A', 8)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('B', 8)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('C', 8)); + + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 3)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 4)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 5)); + + array_push(self::$enemyFleet[4]->getPositions(), new Position('F', 2)); + array_push(self::$enemyFleet[4]->getPositions(), new Position('F', 3)); + + } + + private static function initializeFleet3() + { + array_push(self::$enemyFleet[0]->getPositions(), new Position('C', 1)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 1)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('E', 1)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('F', 1)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 1)); + + array_push(self::$enemyFleet[1]->getPositions(), new Position('A', 4)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('B', 4)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 4)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('D', 4)); + + array_push(self::$enemyFleet[2]->getPositions(), new Position('F', 5)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('F', 6)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('F', 7)); + + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 6)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 7)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('H', 8)); + + array_push(self::$enemyFleet[4]->getPositions(), new Position('B', 7)); + array_push(self::$enemyFleet[4]->getPositions(), new Position('C', 7)); + + + } + + private static function initializeFleet4() + { + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 3)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 4)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 5)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 6)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('D', 7)); + + array_push(self::$enemyFleet[1]->getPositions(), new Position('F', 2)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('F', 3)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('F', 4)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('F', 5)); + + array_push(self::$enemyFleet[2]->getPositions(), new Position('B', 8)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('C', 8)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('D', 8)); + + array_push(self::$enemyFleet[3]->getPositions(), new Position('A', 6)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('A', 7)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('A', 8)); + + array_push(self::$enemyFleet[4]->getPositions(), new Position('H', 1)); + array_push(self::$enemyFleet[4]->getPositions(), new Position('H', 2)); + + } + + private static function initializeFleet5() + { + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 4)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 5)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 6)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 7)); + array_push(self::$enemyFleet[0]->getPositions(), new Position('G', 8)); + + array_push(self::$enemyFleet[1]->getPositions(), new Position('B', 2)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('C', 2)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('D', 2)); + array_push(self::$enemyFleet[1]->getPositions(), new Position('E', 2)); + + array_push(self::$enemyFleet[2]->getPositions(), new Position('A', 1)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('A', 2)); + array_push(self::$enemyFleet[2]->getPositions(), new Position('A', 3)); + + array_push(self::$enemyFleet[3]->getPositions(), new Position('C', 7)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('C', 8)); + array_push(self::$enemyFleet[3]->getPositions(), new Position('D', 8)); + + array_push(self::$enemyFleet[4]->getPositions(), new Position('F', 5)); + array_push(self::$enemyFleet[4]->getPositions(), new Position('F', 6)); + } } \ No newline at end of file diff --git a/src/Batteship/Color.php b/src/Batteship/Color.php index e5e8502..42954d7 100644 --- a/src/Batteship/Color.php +++ b/src/Batteship/Color.php @@ -11,4 +11,5 @@ class Color const YELLOW = "\e[33m"; const ORANGE = "\e[33m"; const CHARTREUSE = "\e[32m"; + const DARK_CYAN = "\e[36m"; } \ No newline at end of file diff --git a/src/Batteship/GameController.php b/src/Batteship/GameController.php index b73455a..d03a9a2 100644 --- a/src/Batteship/GameController.php +++ b/src/Batteship/GameController.php @@ -7,7 +7,7 @@ class GameController { - public static function checkIsHit(array $fleet, $shot) + public static function checkIsHit(array &$fleet, $shot) { if ($fleet == null) { throw new InvalidArgumentException("ships is null"); @@ -20,6 +20,9 @@ public static function checkIsHit(array $fleet, $shot) foreach ($fleet as $ship) { foreach ($ship->getPositions() as $position) { if ($position == $shot) { + $index = array_search($position, $ship->getPositions()); + unset($ship->getPositions()[$index]); + return true; } } @@ -28,6 +31,17 @@ public static function checkIsHit(array $fleet, $shot) return false; } + public static function checkIsGameOver(array $fleet) + { + foreach ($fleet as $ship) { + if (count($ship->getPositions()) > 0) { + return false; + } + } + + return true; + } + public static function initializeShips() { return Array( diff --git a/src/Console.php b/src/Console.php index 928b984..7ea1f71 100644 --- a/src/Console.php +++ b/src/Console.php @@ -18,4 +18,12 @@ function println($line = "") { echo "$line\n"; } + + function printColoredLn($line = "", $color = Battleship\Color::DEFAULT_GREY) + { + self::setForegroundColor($color); + self::println($line); + self::resetForegroundColor(); + } + } \ No newline at end of file