Advertisement
Guest User

Battleship v1.0

a guest
May 5th, 2021
246
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.25 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <array>
  4. #include <string>
  5. #include <cctype>
  6. #include <chrono>
  7. #include <iomanip>
  8. #include <numeric>
  9. #include <windows.h>
  10.  
  11. using namespace std::chrono;
  12.  
  13. // ---------- SUPPORT FUNCTIONS ----------
  14. bool isDigitCheker(const std::vector<std::vector<char>>& hiddenMap,
  15.     const int& charPosition,
  16.     const int& numPosition) {
  17.     bool isDigit; // isdigit from cctype doesn't work with char(176)
  18.     char symbol = hiddenMap[charPosition][numPosition];
  19.     return (isDigit = (symbol > 48 && symbol < 57));
  20. }
  21.  
  22. int getRandomNumber(int lowRange, int highRange) {
  23.     return lowRange + (rand() % (highRange - lowRange));
  24. }
  25.  
  26. // ---------- MAP FUNCTIONS ----------
  27. std::vector<std::vector<char>> generateMap(const int& mapSize, char filler) {
  28.     // create char map with given size
  29.     std::vector<std::vector<char>> map;
  30.     for (int i = 0; i < mapSize; ++i) {
  31.         std::vector<char> row;
  32.         for (int j = 0; j < mapSize; ++j) {
  33.             row.push_back(filler);
  34.         }
  35.         map.push_back(row);
  36.     }
  37.     return map;
  38. }
  39.  
  40. std::string shipsLeft(int ships) {
  41.     std::string shipsStr;
  42.     for (int i = 0; i < ships * 2; ++i) {
  43.         if (i % 2 == 0) {
  44.             shipsStr.push_back(char(3));
  45.         }
  46.         else {
  47.             shipsStr.push_back(' ');
  48.         }
  49.     }
  50.     return shipsStr;
  51. }
  52.  
  53. void printMap(const std::vector<std::vector<char>>& playerOneMap,
  54.               const std::vector<std::vector<char>>& playerTwoMap,
  55.               const std::string& playerOneName,
  56.               const std::string& playerTwoName,
  57.               const int shipsOfPlayerOne,
  58.               const int shipsOfPlayerTwo) {
  59.     const size_t size = playerOneMap.size();
  60.     //FRAMES
  61.     const std::string topFrame(size * 2 + 1, '_');
  62.     const std::string nameFrame(size * 2 + 1 - playerOneName.length(), ' ');
  63.     std::string shipsLeftP1 = shipsLeft(shipsOfPlayerOne);
  64.     std::string shipsFrame(size * 2 + 1 - shipsLeftP1.length(), ' ');
  65.     std::string shipsLeftP2 = shipsLeft(shipsOfPlayerTwo);
  66.     std::string bottFrame = " ";
  67.     int n = 0;
  68.     for (size_t i = 0; i < size * 2; ++i) {
  69.         if (i % 2 == 0) {
  70.             n += 1;
  71.             bottFrame.push_back('0' + n);
  72.             continue;
  73.         }
  74.         bottFrame.push_back(' ');
  75.     }
  76.     //MAP
  77.     std::cout << "\n" << "  " << playerOneName << nameFrame << "  |   " << playerTwoName << std::endl;
  78.     std::cout << "  " << shipsLeftP1 << shipsFrame << "  |   " << shipsLeftP2 << std::endl;
  79.     std::cout << "  " << topFrame << "  |   " << topFrame << std::endl;
  80.     for (size_t i = 0; i < size; ++i) {
  81.         std::cout << ' ' << char('A' + i) << "|";
  82.         for (size_t j = 0; j < size; ++j) {
  83.             std::cout << playerOneMap[i][j] << "|";
  84.         }
  85.         std::cout << "  |  " << char('A' + i) << "|";
  86.         for (size_t j = 0; j < size; ++j) {
  87.             std::cout << playerTwoMap[i][j] << "|";
  88.         }
  89.         std::cout << std::endl;
  90.     }
  91.     std::cout << "  " << bottFrame << "  |   " << bottFrame << std::endl;
  92. }
  93.  
  94. void createNotAllowedField(const int& mapSize,
  95.     const int& numPosition,
  96.     const int& charPosition,
  97.     std::vector<std::vector<char>>& hiddenMap) {
  98.     int left = -1;
  99.     int right = 1;
  100.     int top = -1;
  101.     int bottom = 1;
  102.     if (charPosition == 0) {
  103.         top = 0;
  104.     }
  105.     else if (charPosition == mapSize - 1) {
  106.         bottom = 0;
  107.     }
  108.     if (numPosition == 0) {
  109.         left = 0;
  110.     }
  111.     else if (numPosition == mapSize - 1) {
  112.         right = 0;
  113.     }
  114.     for (int i = top; i <= bottom; ++i) {
  115.         for (int j = left; j <= right; ++j) {
  116.             if (isDigitCheker(hiddenMap, charPosition + i, numPosition + j)) {
  117.                 continue;
  118.             }
  119.             hiddenMap[charPosition + i][numPosition + j] = '.';
  120.         }
  121.     }
  122. }
  123.  
  124. void clearField(const int& mapSize, std::vector<std::vector<char>>& hiddenMap) {
  125.     for (int i = 0; i < mapSize; ++i) {
  126.         for (int j = 0; j < mapSize; ++j)
  127.             if (hiddenMap[i][j] == '.') {
  128.                 hiddenMap[i][j] = char(176);
  129.             }
  130.     }
  131. }
  132.  
  133. // ---------- SHIPS FUNCTIONS ----------
  134. std::vector<int> shipsGenerator(const int& mapSize) {
  135.     std::vector<int> shipArray;
  136.     if (mapSize < 7) { //small map
  137.         shipArray = { 3, 2, 2 }; //one 3x1, two 2x1
  138.     }
  139.     else if (mapSize == 7) { //medium map
  140.         shipArray = { 3, 3, 2, 2 }; //two 3x1, two 2x1
  141.     }
  142.     else { // big map
  143.         shipArray = { 4, 3, 3, 2, 2, 2 }; //one 4x1, two 3x1, three 2x1
  144.     }
  145.     return shipArray;
  146. }
  147.  
  148. void randomPoistionOfShip(std::vector<std::vector<char>>& hiddenMap, int& numPosition, int& charPosition) {
  149.     size_t mapSize = hiddenMap.size();
  150.     bool shipPlaced = false;
  151.     bool isDigit;
  152.     while (!shipPlaced) {
  153.         numPosition = getRandomNumber(0, mapSize);
  154.         charPosition = getRandomNumber(0, mapSize);
  155.         isDigit = isDigitCheker(hiddenMap, charPosition, numPosition);
  156.         if (!isDigit && hiddenMap[charPosition][numPosition] != '.') {
  157.             shipPlaced = true;
  158.         }
  159.     }
  160. }
  161.  
  162. bool getRandDirectionAndOffset(const int& freeRoomForShip,
  163.     const int& numPosition,
  164.     const int& charPosition,
  165.     int& offset) {
  166.     int directionToCreate = getRandomNumber(0, 4);
  167.     // 0 - go up, 1 - go right, 2 - go down, 3 - go left
  168.     bool goUp = false;
  169.     bool goRigth = false;
  170.     bool goDown = false;
  171.     bool goLeft = false;
  172.     switch (directionToCreate) {
  173.     case 0: goUp = true; break;
  174.     case 1: goRigth = true; break;
  175.     case 2: goDown = true; break;
  176.     case 3: goLeft = true; break;
  177.     }
  178.     if (goUp && charPosition >= freeRoomForShip) {
  179.         offset = -1; // up
  180.     }
  181.     else if (goUp) {
  182.         offset = 1; // down
  183.     }
  184.     if (goDown && charPosition <= freeRoomForShip) {
  185.         offset = 1; // down
  186.     }
  187.     else if (goDown) {
  188.         offset = -1; // up
  189.     }
  190.     if (goRigth && numPosition <= freeRoomForShip) {
  191.         offset = 1; // right
  192.     }
  193.     else if (goRigth) {
  194.         offset = -1; // left
  195.     }
  196.     if (goLeft && numPosition >= freeRoomForShip) {
  197.         offset = -1; // left
  198.     }
  199.     else if (goLeft) {
  200.         offset = 1; // right
  201.     }
  202.  
  203.     if (goUp || goDown) {
  204.         return true;
  205.     }
  206.     return false;
  207. }
  208.  
  209. void createShips(const std::vector<int>& playerShips, std::vector<std::vector<char>>& hiddenMap) {
  210.     const size_t mapSize = hiddenMap.size();
  211.     int numPosition = 0;
  212.     int charPosition = 0;
  213.     size_t shipsPlaced = playerShips.size();
  214.     while (shipsPlaced != 0) {
  215.         int offset = 0;
  216.         int freeRoomForShip = playerShips[shipsPlaced - 1] - 1;
  217.         char shipName = shipsPlaced + '0';
  218.         // start pos
  219.         randomPoistionOfShip(hiddenMap, numPosition, charPosition);
  220.         bool verticalDirection = getRandDirectionAndOffset(freeRoomForShip, numPosition, charPosition, offset);
  221.         // handle overlaps
  222.         bool isThereOtherShips;
  223.         if (verticalDirection) {
  224.             int tempChar = charPosition + freeRoomForShip * offset;
  225.             isThereOtherShips = hiddenMap[tempChar][numPosition] == '.';
  226.             isThereOtherShips = isDigitCheker(hiddenMap, tempChar, numPosition);
  227.         }
  228.         else {
  229.             int tempNum = numPosition + freeRoomForShip * offset;
  230.             isThereOtherShips = hiddenMap[charPosition][tempNum] == '.';
  231.             isThereOtherShips = isDigitCheker(hiddenMap, charPosition, tempNum);
  232.         }
  233.         if (isThereOtherShips) {
  234.             continue;
  235.         }
  236.         // create ship
  237.         for (int i = 0; i < playerShips[shipsPlaced - 1]; ++i) {
  238.             int tempCharPos = charPosition;
  239.             int tempNumPos = numPosition;
  240.             if (verticalDirection) {
  241.                 tempCharPos += (i * offset);
  242.             }
  243.             else { // go rigth or left
  244.                 tempNumPos += (i * offset);
  245.             }
  246.             hiddenMap[tempCharPos][tempNumPos] = shipName;
  247.             createNotAllowedField(mapSize, tempNumPos, tempCharPos, hiddenMap);
  248.         }
  249.         shipsPlaced--;
  250.     }
  251. }
  252.  
  253. // ---------- OTHER FUNCTIONS ----------
  254.  
  255. int inputSettings(std::string& playerOne, std::string& playerTwo) {
  256.     std::string mapSizeStr;
  257.     std::cout << " First player name: ";
  258.     std::cin >> playerOne;
  259.     std::cout << " Second player name: ";
  260.     std::cin >> playerTwo;
  261.     std::cout << " Map size (from 5 to 9): ";
  262.     std::cin >> mapSizeStr;
  263.     while (isdigit(mapSizeStr[0]) == 0 || stoi(mapSizeStr) < 5 || stoi(mapSizeStr) > 9) {
  264.         std::cout << " Please enter again: ";
  265.         std::cin >> mapSizeStr;
  266.     }
  267.     int mapSize = stoi(mapSizeStr);
  268.     std::cout << " Positions of ships: random" << std::endl;
  269.     return mapSize;
  270. }
  271.  
  272. void printGameRules (const int& mapSize) {
  273.     std::cout << "\n" << " Each player have: " << std::endl;
  274.     if (mapSize > 7) {
  275.         std::cout << " 1 x Battleship (4x1) " << std::endl;
  276.     }
  277.     std::cout << " " << ((mapSize < 7) ? "1" : "2") << " x Destroyer (3x1) " << std::endl;
  278.     std::cout << " " << ((mapSize > 7) ? "3" : "2") << " x Frigate (2x1) " << std::endl;
  279.     std::cout << " Symbols: " << std::endl;
  280.     std::cout << " X - Hit  " << char(176) << " - Miss  " << char(3) << " - Ships" << std::endl;
  281. }
  282.  
  283. int shoot(std::vector<std::vector<char>>& enemyMap,
  284.            const std::vector<std::vector<char>>& hiddenMap,
  285.            std::vector<int>& shipsOfEnemy,
  286.            int& currTurn,
  287.            int& shipIndx) {
  288.     int shipsDestroyed = 0;
  289.     std::cout << " Coordinates: "; // example: A1
  290.     std::string coordinates;
  291.     std::cin >> coordinates;
  292.     // input checker
  293.     while (coordinates[1] - '0' == 0 || !(coordinates[1] - '0' <= enemyMap.size()) || coordinates.length() > 2) {
  294.         std::cout << " Please enter again: ";
  295.         std::cin >> coordinates;
  296.     }
  297.     coordinates[0] = toupper(coordinates[0]);
  298.     int charAxis = coordinates[0] - 'A';
  299.     int numAxis = (coordinates[1] - '0') - 1;
  300.     bool isDigit = isDigitCheker(hiddenMap, charAxis, numAxis);
  301.     if (isDigit) {
  302.         shipIndx = hiddenMap[charAxis][numAxis] - '0';
  303.         shipsOfEnemy[shipIndx-1]--;
  304.         if (shipsOfEnemy[shipIndx - 1] == 0) {
  305.             shipsDestroyed--;
  306.         }
  307.         enemyMap[charAxis][numAxis] = 'X';
  308.         Beep(400, 300);
  309.     }
  310.     else {
  311.         enemyMap[charAxis][numAxis] = char(177);
  312.         Beep(200, 300);
  313.     }
  314.     currTurn++;
  315.     return shipsDestroyed;
  316. }
  317.  
  318. int main()
  319. {
  320.     srand(time(nullptr));
  321.     std::string playerOneName;
  322.     std::string playerTwoName;
  323.     std::vector<std::vector<char>> playerOneMap;
  324.     std::vector<std::vector<char>> playerTwoMap;
  325.     int currTurn = 2;
  326.  
  327.     // BATTLESHIP DRAWING
  328.     std::cout << "                                                         " << std::endl;
  329.     std::cout << "                 * B A T T L E S H I P *                 " << std::endl;
  330.     std::cout << "    _.._                           v 1.0    -==-   -=-   " << std::endl;
  331.     std::cout << "   (____)====       _.._                         -=-     " << std::endl;
  332.     std::cout << " ---''''-.__       (____)====                            " << std::endl;
  333.     std::cout << " _''_________`:___.-''''-.___._.___.--------/            " << std::endl;
  334.     std::cout << "  .  .  .  .    .          .  .  .    $    /             " << std::endl;
  335.     std::cout << " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'~~~~ ~~~ ~~ ~ " << std::endl;
  336.  
  337.     // *** GAME SETTINGS ***
  338.     std::cout << "\n" << " *** GAME SETTINGS *** " << std::endl;
  339.     int mapSize = inputSettings(playerOneName, playerTwoName);
  340.     playerOneMap = generateMap(mapSize, '_');
  341.     playerTwoMap = generateMap(mapSize, '_');
  342.     std::vector<std::vector<char>> playerOneHiddenMap = generateMap(mapSize, char(176));
  343.     std::vector<std::vector<char>> playerTwoHiddenMap = generateMap(mapSize, char(176));
  344.     std::vector<int> playerOneShips = shipsGenerator(mapSize);
  345.     std::vector<int> playerTwoShips = shipsGenerator(mapSize);
  346.     createShips(playerOneShips, playerOneHiddenMap);
  347.     createShips(playerTwoShips, playerTwoHiddenMap);
  348.     clearField(mapSize, playerOneHiddenMap);
  349.     clearField(mapSize, playerTwoHiddenMap);
  350.     size_t shipsOfPlayerOne = playerOneShips.size();
  351.     size_t shipsOfPlayerTwo = playerTwoShips.size();
  352.     int startShipsHealt = std::accumulate(playerOneShips.begin(), playerOneShips.end(), 0);
  353.  
  354.     // *** START ***
  355.     std::cout << "\n" << " *** START *** " << std::endl;
  356.     printGameRules(mapSize);
  357.     auto start = high_resolution_clock::now(); // start timer
  358.  
  359.     // *** TURNS ***
  360.     std::string winner;
  361.     while (shipsOfPlayerOne != 0 && shipsOfPlayerTwo != 0) {
  362.         std::cout << "\n" << " *** TURN " << currTurn / 2 << " ***" << std::endl;
  363.         printMap(playerOneMap, playerTwoMap, playerOneName, playerTwoName, shipsOfPlayerOne, shipsOfPlayerTwo);
  364.         int shipIndx = 0;
  365.         if (currTurn % 2 == 0) {
  366.             std::cout << " " << playerOneName << ", where to shoot? " << std::endl;
  367.             winner = playerOneName;
  368.             shipsOfPlayerTwo += shoot(playerTwoMap, playerTwoHiddenMap, playerTwoShips, currTurn, shipIndx);
  369.             continue;
  370.         }
  371.         std::cout << " " << playerTwoName << ", where to shoot? " << std::endl;
  372.         shipsOfPlayerOne += shoot(playerOneMap, playerOneHiddenMap, playerOneShips, currTurn, shipIndx);
  373.         winner = playerTwoName;
  374.        
  375.     }
  376.  
  377.     // *** GAME OVER ***
  378.     std::cout << "\n" << " *** GAME OVER ***" << std::endl;
  379.     auto stop = high_resolution_clock::now();
  380.     printMap(playerOneHiddenMap, playerTwoHiddenMap, playerOneName, playerTwoName, shipsOfPlayerOne, shipsOfPlayerTwo);
  381.     std::cout << '\7' << "\n" << ' ' << winner << " won the battle!" << "\n" << std::endl;
  382.  
  383.     // *** STATISTICS ***
  384.     std::cout << " *** STATISTICS ***" << std::endl;
  385.     std::cout << "\n" << " Total turns: " << currTurn / 2 << std::endl;
  386.     int shipsHealthP1 = std::accumulate(playerOneShips.begin(), playerOneShips.end(), 0);
  387.     int shipsHealthP2 = std::accumulate(playerTwoShips.begin(), playerTwoShips.end(), 0);
  388.     double accuracyP1 = ((startShipsHealt - shipsHealthP1 * 1.0) / (currTurn / 2)) * 100;
  389.     double accuracyP2 = ((startShipsHealt - shipsHealthP2 * 1.0) / (currTurn / 2)) * 100;
  390.     std::cout.precision(2);
  391.     std::cout << ' ' << playerOneName << " accuracy: " << std::fixed << accuracyP1 << '%' << std::endl;
  392.     std::cout << ' ' << playerTwoName << " accuracy: " << std::fixed << accuracyP2 << '%' << std::endl;
  393.     auto duration = duration_cast<seconds>(stop - start);
  394.     std::cout << " Game time: ";
  395.     if (duration.count() > 60) {
  396.         std::cout << duration.count() / 60 << "m " << duration.count() % 60 << "s" << std::endl;
  397.     } else {
  398.         std::cout << duration.count() << "s" << std::endl;
  399.     }
  400. }
  401.  
  402.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement