Witam :-)
W ostatnim czasie zaczęłam pisać w konsoli grę w statki. Jest to jak na razie jeden z moich większych projektów (uczę się programowania raczej od niedawna).
Pisząc grę miałam głównie przećwiczyć używanie wskaźników oraz posługiwanie się strukturami danych, w tym typem wyliczeniowym enum
.
Kiedy doszłam do momentu, gdzie zaczęło mieć sens odpalenie gry i obejrzenie efektów swojej pracy- kompilator pokazał mi pierdyliard błędów... :-(
No nic- mimo tego, że jest ich aż tak dużo, wciąż żywię nadzieję, że będę to w stanie jakoś naprawić.
Zanim napisałam ten wątek, spędziłam kilka godzin naprawiając te błędy, które póki co naprawić potrafiłam- i komunikatów jest znacząco mniej niż na początku (musicie mi uwierzyć na słowo :-b).
Ale niestety doszłam do wniosku, że z moim dotychczasowym poziomem umiejętności ze wszystkim sobie sama nie poradzę :-( - dlatego uprzejmie proszę o pomoc.
A więc, po pierwsze:
-nigdy wcześniej w większym projekcie nie posługiwałam się enum
, więc nie wiem, jak prawidłowo powinnam to rozdzielić na plik z nagłówkami (spis treści) i część zawierającą całe implementacje klas i funkcji.
-po drugie:
próbując załączyć pliki z nagłówkami pisałam na początku pliku z rozszerzeniem .h
:
#ifndef __ BATTLESHIP_H__ #define __BATTLESHIP_H__
kompilator pokazuje mi błąd: unterminated ifndef
- jest to dla mnie zupełnie coś nowego i nie wiem, co mam z tym zrobić :-(
- po trzecie: cała reszta- prawie wszystko to skutki błędów w kodzie, jakie popełniłam przy tworzeniu struktur (wcześniej nie miałam wielu okazji, żeby tego używać)
Zrobiłam zrzut ekranu i umieściłam w załączniku.
Projekt nieskończonej gry składa się z 6 plików: main.cpp, Battleship.cpp, Battleshipi.h, Instruction.cpp (ten plik to akurat jeden wielki komentarz z pseudokodem, planem tworzenia gry), Utils.cpp i Utils.h (dwa ostatnie zawierają funcje korygujące dane wprowadzane z klawiatury przez użytkownika- użyłam tego w nieco zmienionej formie przy tworzeniu gry w wisielca(poprzedni wpis)).
main.cpp:
include <iostream>
#include "Battleship.h"
using namespace std;
int main()
{
const char * INPUT_ERROR_STRING = "input error! Please, try again.";
Player player1;
Player player2;
InitializePlayer(player1, "Player1");
InitializePlayer(player2, "Player2");
do
{
PlayGame(player1, player2);
}while(WantToPlayAgain());
return 0;
}
Battleship.h:
enum SizeType
{
AIRCRAFT_CARRIER_SIZE = 5,
BATTLESHIP_SIZE = 4,
CRUISER_SIZE = 3,
DESTROYER_SIZE = 2,
SUBMARINE_SIZE = 1,
BOARD_SIZE = 10,
NUM_SHIPS = 5,
PLAYER_NAME_SIZE = 8, // Player1, Player2
MAX_SHIP_SIZE = AIRCRAFT_CARRIER_SIZE
};
enum ShipType
{
ST_NONE = 0,
ST_AIRCRAFT_CARRIER,
ST_BATTLESHIP,
ST_CRUISER,
ST_DESTROYER,
ST_SUBMARINE
};
enum ShipOrientationType
{
SO_HORIZONTAL = 0,
SO_VERTICAL
};
struct ShipPositionType
{
int row;
int col;
};
struct Ship
{
ShipType shipType;
int shipSize;
ShipOrientationType orientation; //stworzylam tutaj typ, ale on sam nie definiuje zadnej kokrenej zmiennej =>
ShipPositionType position; // miszê ustawiæ wszystkie statki dla kazdego gracza
};
enum GuessType
{
GT_NONE = 0,
GT_MISSED,
GT_HIT
};
struct ShipPartType
{
ShipType shipType;
bool isHit;
};
struct Player
{
char playerName[PLAYER_NAME_SIZE];
Ship ships[NUM_SHIPS]; // musze ustawic wszystkie statki poprawnie i przekazac graczowi jeden typ statku do
GuessType guessBoard[BOARD_SIZE][BOARD_SIZE]; // kazdego z poszczegolnych elementow tablicy
ShipPartType shipBoard[BOARD_SIZE][BOARD_SIZE];
};
Battleship.cpp
#include <iostream>
#include <cstring>
#include <cctype>
#include "Battleship.h"
#include "Utils.h"
using namespace std;
const char * INPUT_ERROR_STRING = "input error! Please, try again.";
void InitializePlayer(Player & player, const char * playerName)
{
if(playerName != nullptr && strlen(playerName)>0)
{
{
strcpy(player, playerName);
}
InitializeShip(player.ships[0], AIRCRAFT_CARRIER_SIZE, ST_AIRCRAFT_CARRIER);
InitializeShip(player.ships[1], BATTLESHIP_SIZE, ST_BATTLESHIP);
InitializeShip(player.ships[2], CRUISER_SIZE, ST_CRUISER);
InitializeShip(player.ships[3], DESTROYER_SIZE, ST_DESTROYER);
InitializeShip(player.ships[4], SUBMARINE_SIZE, ST_SUBMARINE);
}
}
void InitializeShip(Ship & ship, int shipSize, ShipType shipType)
{
ship.shipType = ST_AIRCRAFT_CARRIER;
ship.shipSize = AIRCRAFT_CARRIER_SIZE;
ship.position.row = 0;
ship.position.col = 0;
ship.orientation = SO_HORIZONTAL;
}
void PlayGame(Player& player1, Player&player2)
{
SetUpBoards(player1);
SetUpBoards(player2);
}
bool WantToPlayAgain()
{
char input;
const char validInput[2] = {'y','n'};
input = GetCharacter("Would you like to play again? (y/n)", INPUT_ERROR_STRING, validInput, 2, CC_LOWER_CASE);
return input == 'y';
}
void SetUpBoards(Player& player)
{
ClearBoards(player);
DrawBoards(player);
}
void ClearBoards(Player&player)
{
for(int r=0; r<BOARD_SIZE; r++)
{
for(int c=0; c<BOARD_SIZE; c++)
{
player.guessBoard[r][c] = GT_NONE;
player.shipBoard[r][c].shipType = ST_NONE;// no ship here
player.shipBoard[r][c].isHit = false;
}
}
}
void DrawBoards(const Player&player)
{
DrawColumnsRow();
DrawColumnsRow();
cout<<endl;
for(int r=0; r<BOARD_SIZE; r++)
{
DrawSeparatorLine();
cout<<" ";
DrawSeparatorLine();
cout<<endl;
DrawShipBoardRow(player, r);
cout<<" ";
DrawGuessBoardRow(player, r);
cout<<endl;
}
DrawSeparatorLine();
cout<<" ";
DrawSeparatorLine();
cout<<endl;
}
void DrawSeparatorLine()
{
cout<<" ";
for(int c=0; c<BOARD_SIZE; c++)
{
cout<<"+---";
}
cout<<"+";
}
void DrawColumnsRow()
{
cout<<" ";
for(int c=0; c<BOARD_SIZE; c++)
{
int columnName = c+1;
cout<<" "<<columnName<<" ";
}
cout<<"+";
}
char GetShipReprezentation(const Player& player, int row, int col)
{
if(player.guessBoard[row][col].isHit)
{
return '*';// represents hit
}
if(player.shipBoard[row][col].shipType == ST_AIRCRAFT_CARRIER)
{
return 'A';
}
else if(player.shipBoard[row][col].shipType == ST_BATTLESHIP)
{
return 'B';
}
else if(player.shipBoard[row][col].shipType == ST_CRUISER)
{
return 'C';
}
else if(player.shipBoard[row][col].shipType == ST_DESTROYER)
{
return 'D';
}
else if(player.shipBoard[row][col].shipType == ST_SUBMARINE)
{
return 'S';
}
else return ' ';
}
char GetGuessRepresentationAt(const Player& player, int row, int col)
{
if(player.guessBoard[row][col] == GT_HIT)
{
return '*';
}
else if(player.guessBoard[row][col == GT_MISSED])
{
return 'o';
}
else return ' ';
}
void DrawShipBoardRow(const Player& player, int row)
{
char rowName = row + 'A';
cout<<rowName<<"|";
for(int c=0; c<BOARD_SIZE; c++)
{
cout<<" "<<GetShipReprezentation(player, row, c)<<" ";
}
}
void DrawGuessBoardRow(const Player& player, int row)
{
char rowName = row + 'A';
cout<<rowName<<"|";
for(int c=0; c<BOARD_SIZE; c++)
{
cout<<" "<<GetGuessRepresentationAt(player, row, c)<<" "; // tu trzeba uzupelnic reprezentacja kazdego statku
}
}
Instruction.cpp:
/*
InitPlayer(player1, "Player1");
InitPlayer(player2, "Player2");
do
{
PlayGame(player1, player2);
} while(WantToPlayAgain());
PlayGame()
{
SetupBoard(Player1);
SetupBoard(Player2);
do
{
DrawBoards(currentPlayer)
do
{
Prompt the current player for a guess
guess = GetGuess()
} while(!IsGuessIsValid(guess, currentPlayer));
UpdateBoards(guess, currentPlayer, otherPlayer);
DrawBoard(currentPlayer) // to see the result of the guess
if(a ship was sunk on currentPlayer's turn)
{
output that the current player sunk that ship
}
WatForKeyPress
SwitchPlayers()
} while(!GameIsOver());
DisplayWinner();
}
SetUpBoards(player)
{
ClearBoards(player)
for(all the ships)
{
DrawBoards(player)
currentShip = Get the current ship
// sprawdzam, czy statek zostal umieszczony poprawnie
do
{
Get Board Position for the head of the ship
Get the ship orientation
isValidPlacement = IsValidPlacement(currenShip, position, orientation, player)
if (!isValidPlacement)
{
output to the player that it was not a valid placement
}
} while(!isValidPlacement)
PlaceShipOnBoard(currenShip, position, orientation, player)
}
}
IsValidPlacement(currentShip, position, orientation, player)
{
if(orientatin == HO0RIZONTAL)
{
for(all the columns the currentShip would take up)
{
if(ship will overlap another ship or the ship will be off the board horizontally)
{
return false
}
}
}
else
{
for(all the rows the currentShip would take up)
{
if(ship will overlap another ship or the ship will be off the board vertically)
{
return false
}
}
} return true
}
PlaceShipOnBoard(currentShip, position, orientation, player)
{
ship.position = position
ship.orientation = orientation
if(orientation == HORIZONTAL)
{
for(all the columns the ship would take up)
{
set the ship part on the board at position.row and current column
}
}
else
{
for(all the rows that the ship would take up)
{
set the ship part on the board at current row and position.col
}
}
}
UpdateBoards(guess, currentPlayer, otherPlayer)
{
if(otherPlayer's ship board at guess is a ship)
{
// hit
set hit on the currentPlayer's guess board
apply damage to the otherPlayer's shipBoard
return shipType
}
else
{
set miss on the currentPlayer's guess board
return ST_NONE
}
}
IsGameOver(player1, player2)
{
return AreAllShipsSunk(player1) || AreAllShipsSunk(player2)
}
AreAllShipsSunk(player)
{
for(all the player's ships)
{
if(!IsSunk(player, currentShip))
{
return false
}
} return true
}
IsSunk(player, ship)
{
if(ship.orientation == HORIZONTAL)
{
for(columns that ship takes up)
{
if(currentPosition on the shipBoard is not hit)
{
return false
}
}
}
else
{
for(rows that the ship takes up)
{
if(currentPosition on the shipBoard is not hit)
{
return false
}
}
}
}
*/
Utils.h:
#ifndef __ UTILS_H__
#define __UTILS_H__
enum CharacterCaseType
{
CC_UPPER_CASE=0,
CC_LOWER_CASE,
CC_EITHER
};
char GetCharacter(const char* prompt, const char*error);
char GetCharacter(const char* prompt, const char* error, const char validInput[], int validInputLength, CharacterCaseType charCase);
#endif
Utils.cpp
#include <iostream>
#include <cctype>
#include "Utils.h"
using namespace std;
const int IGNORE_CHARS = 256; //to do main
const char * INPUT_ERROR_STRING = "input error! Please, try again.";
char GetCharacter(const char* prompt, const char*error)
{
char input;
bool failure;
do
{
failure=false;
cout<<prompt;
cin>>input;
if(cin.fail())
{
cin.clear();
cin.ignore(IGNORE_CHARS, '\n');
cout << error << endl;
failure=true;
}
else
{
cin.ignore(IGNORE_CHARS, '\n');
if(isalpha(input))
{
input = tolower(input);
}
else
{
cout<<error<<endl;
failure = true;
}
}
}while(failure); return input;
}
char GetCharacter(const char* prompt, const char* error, const char validInput[], int validInputLength, CharacterCaseType charCase)
{
char input;
bool failure;
do
{
failure=false;
cout<<prompt;
cin>>input;
if(cin.fail())
{
cin.clear();
cin.ignore(IGNORE_CHARS, '\n');
cout << error << endl;
failure=true;
}
else
{
cin.ignore(IGNORE_CHARS, '\n');
if(isalpha(input))
{
if(charCase == CC_UPPER_CASE)
{
input = toupper(input);
}
else if(charCase == CC_LOWER_CASE)
{
input = tolower(input);
}
for (int i=0;i<validInputLength;i++)
{
if(input==validInput[i])
{
return input;
}
}
}
cout<<error<<endl;
failure=true;
}
}while(failure); return input;
}
Proszę o wyrozumiałość w związku z tym, że tu jest aż tak dużo błędów.
Wiem, że tego dużo, ale może jednak komuś będzie się chciało to chociaż pobieżnie przejrzeć i podpowiedzieć mi co i jak poprawić ;-)
Z góry dziękuję za odpowiedź :-)