Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <vector>
- #include <array>
- #include <string>
- #include <cctype>
- #include <chrono>
- #include <iomanip>
- #include <numeric>
- #include <windows.h>
- using namespace std::chrono;
- // ---------- SUPPORT FUNCTIONS ----------
- bool isDigitCheker(const std::vector<std::vector<char>>& hiddenMap,
- const int& charPosition,
- const int& numPosition) {
- bool isDigit; // isdigit from cctype doesn't work with char(176)
- char symbol = hiddenMap[charPosition][numPosition];
- return (isDigit = (symbol > 48 && symbol < 57));
- }
- int getRandomNumber(int lowRange, int highRange) {
- return lowRange + (rand() % (highRange - lowRange));
- }
- // ---------- MAP FUNCTIONS ----------
- std::vector<std::vector<char>> generateMap(const int& mapSize, char filler) {
- // create char map with given size
- std::vector<std::vector<char>> map;
- for (int i = 0; i < mapSize; ++i) {
- std::vector<char> row;
- for (int j = 0; j < mapSize; ++j) {
- row.push_back(filler);
- }
- map.push_back(row);
- }
- return map;
- }
- std::string shipsLeft(int ships) {
- std::string shipsStr;
- for (int i = 0; i < ships * 2; ++i) {
- if (i % 2 == 0) {
- shipsStr.push_back(char(3));
- }
- else {
- shipsStr.push_back(' ');
- }
- }
- return shipsStr;
- }
- void printMap(const std::vector<std::vector<char>>& playerOneMap,
- const std::vector<std::vector<char>>& playerTwoMap,
- const std::string& playerOneName,
- const std::string& playerTwoName,
- const int shipsOfPlayerOne,
- const int shipsOfPlayerTwo) {
- const size_t size = playerOneMap.size();
- //FRAMES
- const std::string topFrame(size * 2 + 1, '_');
- const std::string nameFrame(size * 2 + 1 - playerOneName.length(), ' ');
- std::string shipsLeftP1 = shipsLeft(shipsOfPlayerOne);
- std::string shipsFrame(size * 2 + 1 - shipsLeftP1.length(), ' ');
- std::string shipsLeftP2 = shipsLeft(shipsOfPlayerTwo);
- std::string bottFrame = " ";
- int n = 0;
- for (size_t i = 0; i < size * 2; ++i) {
- if (i % 2 == 0) {
- n += 1;
- bottFrame.push_back('0' + n);
- continue;
- }
- bottFrame.push_back(' ');
- }
- //MAP
- std::cout << "\n" << " " << playerOneName << nameFrame << " | " << playerTwoName << std::endl;
- std::cout << " " << shipsLeftP1 << shipsFrame << " | " << shipsLeftP2 << std::endl;
- std::cout << " " << topFrame << " | " << topFrame << std::endl;
- for (size_t i = 0; i < size; ++i) {
- std::cout << ' ' << char('A' + i) << "|";
- for (size_t j = 0; j < size; ++j) {
- std::cout << playerOneMap[i][j] << "|";
- }
- std::cout << " | " << char('A' + i) << "|";
- for (size_t j = 0; j < size; ++j) {
- std::cout << playerTwoMap[i][j] << "|";
- }
- std::cout << std::endl;
- }
- std::cout << " " << bottFrame << " | " << bottFrame << std::endl;
- }
- void createNotAllowedField(const int& mapSize,
- const int& numPosition,
- const int& charPosition,
- std::vector<std::vector<char>>& hiddenMap) {
- int left = -1;
- int right = 1;
- int top = -1;
- int bottom = 1;
- if (charPosition == 0) {
- top = 0;
- }
- else if (charPosition == mapSize - 1) {
- bottom = 0;
- }
- if (numPosition == 0) {
- left = 0;
- }
- else if (numPosition == mapSize - 1) {
- right = 0;
- }
- for (int i = top; i <= bottom; ++i) {
- for (int j = left; j <= right; ++j) {
- if (isDigitCheker(hiddenMap, charPosition + i, numPosition + j)) {
- continue;
- }
- hiddenMap[charPosition + i][numPosition + j] = '.';
- }
- }
- }
- void clearField(const int& mapSize, std::vector<std::vector<char>>& hiddenMap) {
- for (int i = 0; i < mapSize; ++i) {
- for (int j = 0; j < mapSize; ++j)
- if (hiddenMap[i][j] == '.') {
- hiddenMap[i][j] = char(176);
- }
- }
- }
- // ---------- SHIPS FUNCTIONS ----------
- std::vector<int> shipsGenerator(const int& mapSize) {
- std::vector<int> shipArray;
- if (mapSize < 7) { //small map
- shipArray = { 3, 2, 2 }; //one 3x1, two 2x1
- }
- else if (mapSize == 7) { //medium map
- shipArray = { 3, 3, 2, 2 }; //two 3x1, two 2x1
- }
- else { // big map
- shipArray = { 4, 3, 3, 2, 2, 2 }; //one 4x1, two 3x1, three 2x1
- }
- return shipArray;
- }
- void randomPoistionOfShip(std::vector<std::vector<char>>& hiddenMap, int& numPosition, int& charPosition) {
- size_t mapSize = hiddenMap.size();
- bool shipPlaced = false;
- bool isDigit;
- while (!shipPlaced) {
- numPosition = getRandomNumber(0, mapSize);
- charPosition = getRandomNumber(0, mapSize);
- isDigit = isDigitCheker(hiddenMap, charPosition, numPosition);
- if (!isDigit && hiddenMap[charPosition][numPosition] != '.') {
- shipPlaced = true;
- }
- }
- }
- bool getRandDirectionAndOffset(const int& freeRoomForShip,
- const int& numPosition,
- const int& charPosition,
- int& offset) {
- int directionToCreate = getRandomNumber(0, 4);
- // 0 - go up, 1 - go right, 2 - go down, 3 - go left
- bool goUp = false;
- bool goRigth = false;
- bool goDown = false;
- bool goLeft = false;
- switch (directionToCreate) {
- case 0: goUp = true; break;
- case 1: goRigth = true; break;
- case 2: goDown = true; break;
- case 3: goLeft = true; break;
- }
- if (goUp && charPosition >= freeRoomForShip) {
- offset = -1; // up
- }
- else if (goUp) {
- offset = 1; // down
- }
- if (goDown && charPosition <= freeRoomForShip) {
- offset = 1; // down
- }
- else if (goDown) {
- offset = -1; // up
- }
- if (goRigth && numPosition <= freeRoomForShip) {
- offset = 1; // right
- }
- else if (goRigth) {
- offset = -1; // left
- }
- if (goLeft && numPosition >= freeRoomForShip) {
- offset = -1; // left
- }
- else if (goLeft) {
- offset = 1; // right
- }
- if (goUp || goDown) {
- return true;
- }
- return false;
- }
- void createShips(const std::vector<int>& playerShips, std::vector<std::vector<char>>& hiddenMap) {
- const size_t mapSize = hiddenMap.size();
- int numPosition = 0;
- int charPosition = 0;
- size_t shipsPlaced = playerShips.size();
- while (shipsPlaced != 0) {
- int offset = 0;
- int freeRoomForShip = playerShips[shipsPlaced - 1] - 1;
- char shipName = shipsPlaced + '0';
- // start pos
- randomPoistionOfShip(hiddenMap, numPosition, charPosition);
- bool verticalDirection = getRandDirectionAndOffset(freeRoomForShip, numPosition, charPosition, offset);
- // handle overlaps
- bool isThereOtherShips;
- if (verticalDirection) {
- int tempChar = charPosition + freeRoomForShip * offset;
- isThereOtherShips = hiddenMap[tempChar][numPosition] == '.';
- isThereOtherShips = isDigitCheker(hiddenMap, tempChar, numPosition);
- }
- else {
- int tempNum = numPosition + freeRoomForShip * offset;
- isThereOtherShips = hiddenMap[charPosition][tempNum] == '.';
- isThereOtherShips = isDigitCheker(hiddenMap, charPosition, tempNum);
- }
- if (isThereOtherShips) {
- continue;
- }
- // create ship
- for (int i = 0; i < playerShips[shipsPlaced - 1]; ++i) {
- int tempCharPos = charPosition;
- int tempNumPos = numPosition;
- if (verticalDirection) {
- tempCharPos += (i * offset);
- }
- else { // go rigth or left
- tempNumPos += (i * offset);
- }
- hiddenMap[tempCharPos][tempNumPos] = shipName;
- createNotAllowedField(mapSize, tempNumPos, tempCharPos, hiddenMap);
- }
- shipsPlaced--;
- }
- }
- // ---------- OTHER FUNCTIONS ----------
- int inputSettings(std::string& playerOne, std::string& playerTwo) {
- std::string mapSizeStr;
- std::cout << " First player name: ";
- std::cin >> playerOne;
- std::cout << " Second player name: ";
- std::cin >> playerTwo;
- std::cout << " Map size (from 5 to 9): ";
- std::cin >> mapSizeStr;
- while (isdigit(mapSizeStr[0]) == 0 || stoi(mapSizeStr) < 5 || stoi(mapSizeStr) > 9) {
- std::cout << " Please enter again: ";
- std::cin >> mapSizeStr;
- }
- int mapSize = stoi(mapSizeStr);
- std::cout << " Positions of ships: random" << std::endl;
- return mapSize;
- }
- void printGameRules (const int& mapSize) {
- std::cout << "\n" << " Each player have: " << std::endl;
- if (mapSize > 7) {
- std::cout << " 1 x Battleship (4x1) " << std::endl;
- }
- std::cout << " " << ((mapSize < 7) ? "1" : "2") << " x Destroyer (3x1) " << std::endl;
- std::cout << " " << ((mapSize > 7) ? "3" : "2") << " x Frigate (2x1) " << std::endl;
- std::cout << " Symbols: " << std::endl;
- std::cout << " X - Hit " << char(176) << " - Miss " << char(3) << " - Ships" << std::endl;
- }
- int shoot(std::vector<std::vector<char>>& enemyMap,
- const std::vector<std::vector<char>>& hiddenMap,
- std::vector<int>& shipsOfEnemy,
- int& currTurn,
- int& shipIndx) {
- int shipsDestroyed = 0;
- std::cout << " Coordinates: "; // example: A1
- std::string coordinates;
- std::cin >> coordinates;
- // input checker
- while (coordinates[1] - '0' == 0 || !(coordinates[1] - '0' <= enemyMap.size()) || coordinates.length() > 2) {
- std::cout << " Please enter again: ";
- std::cin >> coordinates;
- }
- coordinates[0] = toupper(coordinates[0]);
- int charAxis = coordinates[0] - 'A';
- int numAxis = (coordinates[1] - '0') - 1;
- bool isDigit = isDigitCheker(hiddenMap, charAxis, numAxis);
- if (isDigit) {
- shipIndx = hiddenMap[charAxis][numAxis] - '0';
- shipsOfEnemy[shipIndx-1]--;
- if (shipsOfEnemy[shipIndx - 1] == 0) {
- shipsDestroyed--;
- }
- enemyMap[charAxis][numAxis] = 'X';
- Beep(400, 300);
- }
- else {
- enemyMap[charAxis][numAxis] = char(177);
- Beep(200, 300);
- }
- currTurn++;
- return shipsDestroyed;
- }
- int main()
- {
- srand(time(nullptr));
- std::string playerOneName;
- std::string playerTwoName;
- std::vector<std::vector<char>> playerOneMap;
- std::vector<std::vector<char>> playerTwoMap;
- int currTurn = 2;
- // BATTLESHIP DRAWING
- std::cout << " " << std::endl;
- std::cout << " * B A T T L E S H I P * " << std::endl;
- std::cout << " _.._ v 1.0 -==- -=- " << std::endl;
- std::cout << " (____)==== _.._ -=- " << std::endl;
- std::cout << " ---''''-.__ (____)==== " << std::endl;
- std::cout << " _''_________`:___.-''''-.___._.___.--------/ " << std::endl;
- std::cout << " . . . . . . . . $ / " << std::endl;
- std::cout << " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'~~~~ ~~~ ~~ ~ " << std::endl;
- // *** GAME SETTINGS ***
- std::cout << "\n" << " *** GAME SETTINGS *** " << std::endl;
- int mapSize = inputSettings(playerOneName, playerTwoName);
- playerOneMap = generateMap(mapSize, '_');
- playerTwoMap = generateMap(mapSize, '_');
- std::vector<std::vector<char>> playerOneHiddenMap = generateMap(mapSize, char(176));
- std::vector<std::vector<char>> playerTwoHiddenMap = generateMap(mapSize, char(176));
- std::vector<int> playerOneShips = shipsGenerator(mapSize);
- std::vector<int> playerTwoShips = shipsGenerator(mapSize);
- createShips(playerOneShips, playerOneHiddenMap);
- createShips(playerTwoShips, playerTwoHiddenMap);
- clearField(mapSize, playerOneHiddenMap);
- clearField(mapSize, playerTwoHiddenMap);
- size_t shipsOfPlayerOne = playerOneShips.size();
- size_t shipsOfPlayerTwo = playerTwoShips.size();
- int startShipsHealt = std::accumulate(playerOneShips.begin(), playerOneShips.end(), 0);
- // *** START ***
- std::cout << "\n" << " *** START *** " << std::endl;
- printGameRules(mapSize);
- auto start = high_resolution_clock::now(); // start timer
- // *** TURNS ***
- std::string winner;
- while (shipsOfPlayerOne != 0 && shipsOfPlayerTwo != 0) {
- std::cout << "\n" << " *** TURN " << currTurn / 2 << " ***" << std::endl;
- printMap(playerOneMap, playerTwoMap, playerOneName, playerTwoName, shipsOfPlayerOne, shipsOfPlayerTwo);
- int shipIndx = 0;
- if (currTurn % 2 == 0) {
- std::cout << " " << playerOneName << ", where to shoot? " << std::endl;
- winner = playerOneName;
- shipsOfPlayerTwo += shoot(playerTwoMap, playerTwoHiddenMap, playerTwoShips, currTurn, shipIndx);
- continue;
- }
- std::cout << " " << playerTwoName << ", where to shoot? " << std::endl;
- shipsOfPlayerOne += shoot(playerOneMap, playerOneHiddenMap, playerOneShips, currTurn, shipIndx);
- winner = playerTwoName;
- }
- // *** GAME OVER ***
- std::cout << "\n" << " *** GAME OVER ***" << std::endl;
- auto stop = high_resolution_clock::now();
- printMap(playerOneHiddenMap, playerTwoHiddenMap, playerOneName, playerTwoName, shipsOfPlayerOne, shipsOfPlayerTwo);
- std::cout << '\7' << "\n" << ' ' << winner << " won the battle!" << "\n" << std::endl;
- // *** STATISTICS ***
- std::cout << " *** STATISTICS ***" << std::endl;
- std::cout << "\n" << " Total turns: " << currTurn / 2 << std::endl;
- int shipsHealthP1 = std::accumulate(playerOneShips.begin(), playerOneShips.end(), 0);
- int shipsHealthP2 = std::accumulate(playerTwoShips.begin(), playerTwoShips.end(), 0);
- double accuracyP1 = ((startShipsHealt - shipsHealthP1 * 1.0) / (currTurn / 2)) * 100;
- double accuracyP2 = ((startShipsHealt - shipsHealthP2 * 1.0) / (currTurn / 2)) * 100;
- std::cout.precision(2);
- std::cout << ' ' << playerOneName << " accuracy: " << std::fixed << accuracyP1 << '%' << std::endl;
- std::cout << ' ' << playerTwoName << " accuracy: " << std::fixed << accuracyP2 << '%' << std::endl;
- auto duration = duration_cast<seconds>(stop - start);
- std::cout << " Game time: ";
- if (duration.count() > 60) {
- std::cout << duration.count() / 60 << "m " << duration.count() % 60 << "s" << std::endl;
- } else {
- std::cout << duration.count() << "s" << std::endl;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement