我已经完成了一个战舰游戏,用c++写的。我希望有人能检查我的代码,告诉我哪里可以改进。我已经发布了所有的代码下面,我希望这是好的。如果没有,而且我只能张贴片段,请让我知道,我会删除这个问题。游戏的选择是人对cpu和cpu对cpu。谢谢!
主要:
int main() {
Game();
return 0;
}battleship.hpp:
#ifndef battleship_hpp
#define battleship_hpp
#include <iostream>
#include <cstring>
#include <cmath>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include "Ship.h"
#include "Board.h"
#include "Player.h"
#include "Game.h"
const std::string border = "---------------------------------------------------------\n";
const std::string alphabet = "abcdefghijklmnopqrstuvwxyz";加梅赫:
#ifndef Game_h
#define Game_h
class Game {
public:
Game();
Player& getPlayer(int id);
void fire(Player&, int, int); //attacks enemy ship
private:
Player p1;
Player p2;
};
#endif /* Game_h */Game.cpp:
#include "battleship.hpp"
Player nullPlayer(-1);
const int speed1 = 0; //0 seconds
const int speed2 = 1; //1 second
Player& Game::getPlayer(int id) {
if(id == 1) { return p1; }
else if(id == 2) { return p2; }
else {
std::cout << "error getting player\n";
return nullPlayer;
}
}
void Game::fire(Player& playerBeingAttacked, int attackX, int attackY) {
//referenced multiple times
Ship* spaceBeingAttacked = &playerBeingAttacked(attackY, attackX);
Ship* shipStoredInArray = &playerBeingAttacked.getBoard().getShip(playerBeingAttacked(attackY, attackX).getShipNumber());
std::cout << border;
//ensure valid target
if(attackX >= 0 && attackX < BOARD_SIZE && attackY >= 0 && attackY < BOARD_SIZE) {
//if already attacked, return error
if(spaceBeingAttacked->getFiredUpon()) {
std::cout << "error, already attacked\n";
return;
}
//otherwise, attack
else {
spaceBeingAttacked->setFiredUpon(true);
//sink ship, decrease board ships[] by 1
if(spaceBeingAttacked->getStatus() == afloat) {
spaceBeingAttacked->setStatus(sunk);
//decrement ship in array
shipStoredInArray->setSize(shipStoredInArray->getSize() - 1);
std::cout << "HIT!\n";
//sink board ship[] if all ship objects are sunk
if(shipStoredInArray->getSize() == 0) {
shipStoredInArray->setStatus(sunk);
std::cout << "Player " << playerBeingAttacked.getID() << "'s " << shipStoredInArray->getName() << " SUNK!\n";
}
}
else {
std::cout << "MISS!\n";
}
}
}
else {
std::cout << "invalid attack coordinate\n";
}
}
//two gamemode's
//1 = human vs cpu
//2 = cpu vs cpu
Game::Game() {
int gamemode;
std::cout << border;
std::cout << "Gamemodes:\n1. Player vs. CPU\n2. CPU vs. CPU\n";
std::cout << border;
std::cout << "Please select a gamemode (1/2):\n: ";
std::cin >> gamemode;
p1.setID(1);
p2.setID(2);
p1.setTurn(true);
p2.getBoard().randomizeFleet();
p2.setPlayerType("cpu");
std::cout << "---------------------------------------------------------\nGAME STARTED\n";
std::string startLoc, endLoc;
int x1, y1, x2, y2, shipNumber;
char choice;
if(gamemode == 1) { p1.setPlayerType("human"); }
else if(gamemode == 2) { p1.setPlayerType("cpu"); }
else { std::cout << "invalid gamemode\n"; return; }
//place if human
if(p1.getPlayerType() == "human") {
//place ships
std::cout << "Player 1, please place your ships.\n";
std::cout << border;
//while all ships aren't placed
//give option to randomize
std::cout << "Would you like to place or randomize your fleet (p/r)?\n: ";
std::cin >> choice;
std::cout << border;
if(choice != 'r') {
while(!p1.getBoard().allShipsPlaced()) {
//print reamining ships
//print board
std::cout << "p1's current board:\n";
p1.getBoard().printBoard();
p1.getBoard().printRemainingShips();
std::cout << "Please enter ship number to place:\nShip Number: ";
std::cin >> shipNumber;
std::cout << "Please enter range to place ship:\nStart Location (ie: a3): ";
std::cin >> startLoc;
std::cout << "End Location (ie: a6): ";
std::cin >> endLoc;
x1 = std::stoi(startLoc.substr(0,1));
y1 = std::stoi(startLoc.substr(1,1));
x2 = std::stoi(endLoc.substr(0,1));
y2 = std::stoi(endLoc.substr(1,1));
//place ship
p1.getBoard().setShip(shipNumber, x1, y1, x2, y2);
}
}
else if(choice == 'r') { p1.getBoard().randomizeFleet(); }
else { std::cout << "invalid option\n"; return; }
}
//computer player
else {
srand(static_cast<unsigned int>(time(NULL)));
sleep(1);
p1.getBoard().randomizeFleet();
std::cout << "CPU Player: Ships Randomly Placed\n";
std::cout << border;
}
Player currPlayer = p1;
Player nextPlayer = p2;
Player tmpPlayer;
int option;
std::string attackCoord;
if(currPlayer.getPlayerType() == "human") {
while(!(currPlayer.getBoard().allShipsSunk() || nextPlayer.getBoard().allShipsSunk())) {
//take turns
std::cout << "Player " << currPlayer.getID() << "'s turn:\n";
std::cout << "Please select a command.......\n";
std::cout << border;
std::cout << "1. Print My Board\n2. Attack Enemy\n3. Print Enemy Board\n: ";
std::cin >> option;
if(option == 1) {
std::cout << "Player " << currPlayer.getID() << "'s board\n";
currPlayer.getBoard().printBoard();
}
else if(option == 2) {
std::cout << border;
std::cout << "Enter coordinate to attack (ie: a3)\n: ";
std::cin >> attackCoord;
x1 = (int)attackCoord[0] - 97;
y1 = (int)attackCoord[1] - 48;
if(x1 >= 0 && y1 >= 0 && x1 < BOARD_SIZE && y1 < BOARD_SIZE && !nextPlayer.getBoard()(x1, y1).getFiredUpon()) {
fire(nextPlayer, x1, y1);
std::cout << border;
//swap players if successful fire
tmpPlayer = currPlayer;
currPlayer = nextPlayer;
nextPlayer = tmpPlayer;
}
else {
std::cout << border;
std::cout << "invalid target, try again\n";
std::cout << border;
}
}
else if(option == 3) {
std::cout << border;
std::cout << "Player " << nextPlayer.getID() << "'s board\n";
nextPlayer.getBoard().printBoard();
}
else {
std::cout << border;
std::cout << "invalid option, try again.\n";
std::cout << border;
}
}
//the last player to guess will have won and they will have ben reassigned to nextPlayer
std::cout << "PLAYER " << nextPlayer.getID() << " WON!!!!\nCONGRATULATIONS!!!\n";
std::cout << "play again (y/n)?\n: ";
char again = 'q';
std::cin >> again;
do {
std::cout << border;
if(again == 'y') { Game(); }
else if(again == 'n') { return; }
else {
std::cout << "invalid selection, try again.\nplay again (y/n)?\n: ";
std::cin >> again;
}
}while(again != 'y' || again != 'n');
}
//if player 1 is a cpu
else {
//initialize array of random numbers 0-99 to attack ships randomly
int p1RandomCoords[BOARD_SIZE*BOARD_SIZE];
int p2RandomCoords[BOARD_SIZE*BOARD_SIZE];
int tmpRandNumber1, tmpRandNumber2, tmpNumber;
for(int i = 0; i < BOARD_SIZE*BOARD_SIZE; i++) {
p1RandomCoords[i] = i;
p2RandomCoords[i] = i;
}
srand(static_cast<unsigned int>(time(NULL)));
for(int k = 0; k < BOARD_SIZE*BOARD_SIZE*BOARD_SIZE; k++) {
tmpRandNumber1 = rand()%100;
tmpNumber = p1RandomCoords[tmpRandNumber1];
p1RandomCoords[tmpRandNumber1] = p1RandomCoords[BOARD_SIZE*BOARD_SIZE - 1];
p1RandomCoords[BOARD_SIZE*BOARD_SIZE - 1] = tmpNumber;
tmpRandNumber2 = rand()%100;
tmpNumber = p2RandomCoords[tmpRandNumber2];
p2RandomCoords[tmpRandNumber2] = p2RandomCoords[BOARD_SIZE*BOARD_SIZE - 1];
p2RandomCoords[BOARD_SIZE*BOARD_SIZE - 1] = tmpNumber;
}
int attackX, attackY;
attackX = rand() % BOARD_SIZE;
attackY = rand() % BOARD_SIZE;
std::cout << "Player " << currPlayer.getID() << "'s board\n";
std::cout << border;
currPlayer.getBoard().printBoard();
std::cout << "Player " << nextPlayer.getID() << "'s board\n";
std::cout << border;
nextPlayer.getBoard().printBoard();
int i = 0;
int k = 0;
//until one of player's has all ships sunk
while(!(currPlayer.getBoard().allShipsSunk() || nextPlayer.getBoard().allShipsSunk())) {
//generate random attack that hasn't already been guessed
//pick from random numbers p1
if(currPlayer.getID() == 1) {
attackX = p1RandomCoords[i] / 10;
attackY = p1RandomCoords[i] % 10;
i++;
}
else {
attackX = p2RandomCoords[i] / 10;
attackY = p2RandomCoords[i] % 10;
k++;
}
//take turns
std::cout << "Player " << currPlayer.getID() << "'s turn.....\n";
//quick pause (as if cpu is thinking)
sleep(speed1);
std::cout << border;
std::cout << "Attacking player " << nextPlayer.getID() << "\nCoordinate's being attacked: (" << attackX << ',' << attackY << ")\n";
sleep(speed1);
fire(nextPlayer, attackX, attackY);
std::cout << "Attack Successful\n";
std::cout << border;
//print boards
sleep(speed1);
std::cout << "Printing player 1's board:\n";
std::cout << border;
sleep(speed2);
//print player 1's board
std::cout << "Player 1's board\n";
std::cout << border;
if(currPlayer.getID() == 1) { currPlayer.getBoard().printBoard(); }
else { nextPlayer.getBoard().printBoard(); }
std::cout << "Printing player 2's board:\n";
std::cout << border;
sleep(speed2);
//print player 2's board
std::cout << "Player 2's board\n";
std::cout << border;
if(currPlayer.getID() == 2) { currPlayer.getBoard().printBoard(); }
else { nextPlayer.getBoard().printBoard(); }
sleep(speed1);
//swap players on successful fire
tmpPlayer = currPlayer;
currPlayer = nextPlayer;
nextPlayer = tmpPlayer;
}
//the last player to guess will have won and they will have ben reassigned to nextPlayer
std::cout << border;
std::cout << "PLAYER " << nextPlayer.getID() << " WON!!!!\nCONGRATULATIONS!!!\n";
std::cout << "play again (y/n)?\n: ";
char again = 'q';
std::cin >> again;
do {
std::cout << border;
if(again == 'y') { Game(); }
else if(again == 'n') { return; }
else {
std::cout << "invalid selection, try again.\nplay again (y/n)?\n: ";
std::cin >> again;
}
}while(again != 'y' || again != 'n');
}
}Player.h:
#ifndef Player_h
#define Player_h
class Player {
public:
Player() { }
Player(int nID) { id = nID; }
Player(std::string nType, int nID) { playerType = nType; id = nID; }
Player(const Player &rhs);
std::string getPlayerType() { return playerType; }
void setPlayerType(std::string nType) { playerType = nType; }
int getID() { return id; }
void setID(int nID) { id = nID; }
bool getTurn() { return turn; }
void setTurn(bool nTurn) { turn = nTurn; }
Board& getBoard() { return playerBoard; }
Ship& operator()(int, int);
Player& operator=(const Player &p);
bool operator==(const Player &rhs);
bool operator!=(const Player&);
private:
Board playerBoard;
std::string playerType = "";
int id = -1;
bool turn = false;
};
#endif /* Player_h */Player.cpp:
#include "battleship.hpp"
Ship& Player::operator()(int x, int y) {
return getBoard()(y, x);
}
Player& Player::operator=(const Player &rhs) {
if(this != &rhs) {
playerType = rhs.playerType;
id = rhs.id;
turn = rhs.turn;
playerBoard = rhs.playerBoard;
}
return *this;
}
Player::Player(const Player &rhs) {
playerType = rhs.playerType;
id = rhs.id;
turn = rhs.turn;
playerBoard = rhs.playerBoard;
}
bool Player::operator==(const Player&rhs) {
if((playerBoard != rhs.playerBoard) || (playerType != rhs.playerType) || (id != rhs.id) || (turn != rhs.turn)) {
return false;
}
return true;
}
bool Player::operator!=(const Player& rhs) {
return !(*this == rhs);
}理事会:
#ifndef Board_h
#define Board_h
#include "battleship.hpp"
const int BOARD_SIZE = 10;
const int numOfShips = 5;
class Board {
public:
Board();
Board(const Board &rhs);
~Board() {}
void printBoard();
void setShip(int shipNumber, int x1, int y1, int x2, int y2);
bool isValidDirection(int x1, int y1, int x2, int y2);
bool rangeIsOccupied(int x1, int y1, int x2, int y2);
bool fitsOnBoard(int x1, int y1, int x2, int y2);
bool isSunk(int shipNumber);
void randomizeFleet();
bool allShipsPlaced();
bool allShipsSunk();
void printRemainingShips();
Ship& operator()(int, int);
Ship& getShip(int n) { return Ships[n]; }
Board& operator=(const Board &rhs);
bool operator==(const Board&);
bool operator!=(const Board&);
private:
Ship gameBoard[BOARD_SIZE][BOARD_SIZE];
Ship Ships[numOfShips];
};
#endif /* Board_h */Board.cpp:
#include <stdio.h>
#include "battleship.hpp"
Board::Board(const Board &rhs) {
for(int i = 0; i < BOARD_SIZE; i++) {
for(int k = 0; k < BOARD_SIZE; k++) {
gameBoard[i][k] = rhs.gameBoard[i][k];
}
}
for(int i = 0; i < numOfShips; i++) {
Ships[i] = rhs.Ships[i];
}
}
//x = hit ship
//o = ship on board
//m = empty space
void Board::printBoard() {
std::cout << "x = hit ship\no = ship on board\nm = empty space\n";
std::cout << border;
std::cout << " ";
for(int i = 0; i < BOARD_SIZE; i++) {
std::cout << '|' << alphabet[i] << "|";
if(i != BOARD_SIZE - 1) { std::cout << ' '; }
}
std::cout << "\n";
for(int j = 0; j < BOARD_SIZE; j++) {
std::cout << j << " - ";
for(int k = 0; k < BOARD_SIZE; k++) {
if(gameBoard[j][k].getShipNumber() != -1 && gameBoard[j][k].getFiredUpon()) {
std::cout << 'x';
}
else if(!gameBoard[j][k].getStatus()) { std::cout << 'm'; } //empty spaces
else { std::cout << 'o'; } //ships that are afloat
if(k != BOARD_SIZE - 1) { std::cout << " "; }
}
std::cout << "\n";
}
std::cout << border;
}
Board::Board() {
Ships[0] = Ship("Carrier", 5, sunk, 0);
Ships[1] = Ship("Battleship", 4, sunk, 1);
Ships[2] = Ship("Cruiser", 3, sunk, 2);
Ships[3] = Ship("Submarine", 3, sunk, 3);
Ships[4] = Ship("Destroyer", 2, sunk, 4);
}
Ship& Board::operator()(int x, int y) {
return gameBoard[y][x];
}
//returns bool based on if coords are valid direction
bool Board::isValidDirection(int x1, int y1, int x2, int y2) {
if(x1 == x2 || y1 == y2) { return true; }
return false;
}
//returns bool based on if range is occupied or not
bool Board::rangeIsOccupied(int x1, int y1, int x2, int y2) {
//if horizontal
if(y1 == y2) {
while(x1 != x2) {
if(gameBoard[y1][x1].getStatus()) {
return true;
}
if(x1 > x2) {
x1--;
}
else {
x1++;
}
}
if(gameBoard[y1][x1].getStatus()) {
return true;
}
}
//if vertical
else {
while(y1 != y2) {
if(gameBoard[y1][x1].getStatus()) {
return true;
}
if(y1 > y2) {
y1--;
}
else {
y1++;
}
}
if(gameBoard[y1][x1].getStatus()) {
return true;
}
}
return false;
}
bool Board::fitsOnBoard(int x1, int y1, int x2, int y2) {
if((x1 >= 0 && x1 < BOARD_SIZE) && (x2 >= 0 && x2 < BOARD_SIZE) && (y1 >= 0 && y1 < BOARD_SIZE) && (y2 >= 0 && y2 < BOARD_SIZE)) { return true; }
return false;
}
bool Board::isSunk(int shipNumber) {
return !Ships[shipNumber].getStatus();
}
bool Board::allShipsPlaced() {
for(int i = 0; i < numOfShips; i++) {
if(!Ships[i].getStatus()) {
return false;
}
}
return true;
}
bool Board::allShipsSunk() {
for(int i = 0; i < BOARD_SIZE; i++) {
for(int k = 0; k < BOARD_SIZE; k++) {
if(gameBoard[i][k].getStatus()) {
return false;
}
}
}
return true;
}
bool Board::operator==(const Board& rhs) {
for(int i = 0; i < BOARD_SIZE; i++) {
for(int k = 0; k < BOARD_SIZE; k++) {
if(gameBoard[i][k] != rhs.gameBoard[i][k]) {
return false;
}
}
}
for(int r = 0; r < numOfShips; r++) {
if(Ships[r] != rhs.Ships[r]) {
return false;
}
}
return true;
}
bool Board::operator!=(const Board& rhs) {
return !(*this == rhs);
}
Board& Board::operator=(const Board &rhs) {
if(this != &rhs) {
for(int i = 0; i < BOARD_SIZE; i++) {
for(int k = 0; k < BOARD_SIZE; k++) {
gameBoard[i][k] = rhs.gameBoard[i][k];
}
}
for(int i = 0; i < numOfShips; i++) {
Ships[i] = rhs.Ships[i];
}
}
return *this;
}
void Board::setShip(int shipNumber, int x1, int y1, int x2, int y2) {
//checks if valid placement first
if(!rangeIsOccupied(x1, y1, x2, y2) && fitsOnBoard(x1, y1, x2, y2) && isValidDirection(x1, y1, x2, y2)) {
Ship shipToPlace = Ship(Ships[shipNumber].getName(), Ships[shipNumber].getSize(), afloat, shipNumber);
//place ship
while((x1 != x2 || y1 != y2)) {
gameBoard[y1][x1] = shipToPlace;
gameBoard[y1][x1].setShipNumber(shipNumber);
if(x1 > x2) {
x1--;
}
else if(x2 > x1) {
x1++;
}
else if(y1 > y2) {
y1--;
}
else if(y2 > y1) {
y1++;
}
}
gameBoard[y1][x1] = shipToPlace;
Ships[shipNumber].setStatus(afloat);
}
else {
return;
}
}
void Board::randomizeFleet() {
srand(static_cast<unsigned int>(time(NULL)));
for(int i = 0; i < numOfShips; i++) {
int startX = rand() % BOARD_SIZE;
int startY = rand() % BOARD_SIZE;
int endX = startX;
int endY = startY;
//go vert
if(rand() % 2 == 0) {
//go up
if(rand() % 2 == 0) {
endX -= (Ships[i].getSize() - 1);
}
//go down
else {
endX += (Ships[i].getSize() - 1);
}
}
//go horiz
else {
//go left
if(rand() % 2 == 0) {
endY -= (Ships[i].getSize() - 1);
}
//go right
else {
endY += (Ships[i].getSize() - 1);
}
}
setShip(i, startX, startY, endX, endY);
//don't incrment i unless ship is placed
if(!Ships[i].getStatus()) {
i--;
}
}
}
void Board::printRemainingShips() {
for(int i = 0; i < numOfShips; i++) {
if(!Ships[i].getStatus()) {
std::cout << Ships[i].getShipNumber() << ". " << Ships[i].getName() << " | Size = " << Ships[i].getSize() << "\n";
}
}
}船舶h:
#ifndef Ship_h
#define Ship_h
enum Afloat {afloat = true, sunk = false};
class Ship {
public:
Ship() { }
Ship(std::string nName, int nSize, Afloat nStatus, int nShipNumber) { name = nName; size = nSize; status = nStatus; shipNumber = nShipNumber;}
Ship(const Ship& rhs);
~Ship() { }
int getSize() { return size; }
void setSize(int nSize) { size = nSize; }
std::string getName() { return name; }
void setName(std::string nName) { name = nName; }
bool getStatus() { return status; }
void setStatus(Afloat nStatus) { status = nStatus; }
bool getFiredUpon() { return firedUpon; }
void setFiredUpon(bool f) { firedUpon = f; }
int getShipNumber() { return shipNumber; }
void setShipNumber(int n) { shipNumber = n; }
Ship& operator=(const Ship&);
bool operator==(const Ship&);
bool operator!=(const Ship&);
private:
int shipNumber = -1;
std::string name = "";
int size = 0;
//true = sunk, false = afloat
Afloat status = sunk;
bool firedUpon = false;
};
#endif /* Ship_h */Ship.cpp:
#include <stdio.h>
#include "battleship.hpp"
Ship::Ship(const Ship& rhs) {
shipNumber = rhs.shipNumber;
name = rhs.name;
size = rhs.size;
status = rhs.status;
firedUpon = rhs.firedUpon;
}
Ship& Ship::operator=(const Ship &rhs) {
if(this != &rhs) {
shipNumber = rhs.shipNumber;
name = rhs.name;
size = rhs.size;
status = rhs.status;
firedUpon = rhs.firedUpon;
}
return *this;
}
bool Ship::operator==(const Ship& rhs) {
if((name != rhs.name) || (size != rhs.size) || (status != rhs.status)) {
return false;
}
return true;
}
bool Ship::operator!=(const Ship& rhs) {
return !(*this == rhs);
}发布于 2017-04-19 16:47:12
int main() {
Game(); // If Game is a function then make it one.
// Don't hide a class behind a temporary variable
return 0;
}看起来会更像这样:
int main()
{
std::unique_ptr<Player> player1 = getPlayer(); // returns PlayerHuman or PlayerComputer object.
std::unique_ptr<Player> player2 = getPlayer();
Game game(*player1, *player2);
game.play();
}https://codereview.stackexchange.com/questions/161225
复制相似问题