Battleship

Dominika Łęczycka
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 5 lat
  • Postów:13
0

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:

Kopiuj
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:

Kopiuj
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

Kopiuj
#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:

Kopiuj
/*
    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:

Kopiuj
#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

Kopiuj
#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ź :-)

edytowany 2x, ostatnio: Dominika Łęczycka
twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
2

Każda dyrektywa preprocesora musi być w osobnej linii, czyli:

Kopiuj
#ifndef __ BATTLESHIP_H__ 
#define __BATTLESHIP_H__

```cpp strcpy(player, playerName); ``` `strcpy()` przyjmuje wskaźniki do ciągów znaków: https://en.cppreference.com/w/cpp/string/byte/strcpy, a Ty przekazujesz obiekt `Player`.
```cpp if(player.guessBoard[row][col].isHit) ``` `guessBoard` jest tablicą enumów `GuessType`, więc nie ma żadnego pola o nazwie `isHit`.
Błędy kopiuj i wklej jako tekst, a nie obrazek. Ten obrazek w dodatku obcina komunikat.
Dominika Łęczycka
A jak mogę poprawić to ostatnie? Bo pomyślałam, żeby może zmienić warunek na: if(player.guessBoard[row][col]==GT_HIT), ale wtedy kompilator zamiast poprzedniego błędu pokazuje mi: 1d returned 1 exit status (*wszystko inne już poprawiłam)
Silv
Tzn. ogólnie poczekajmy na odpowiedź @twonek, ale ten ostatni błąd może być niepowiązany z tym problemem z if-em.
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:4 minuty
  • Postów:4884
1

Jak się Uczysz, to Staraj się pisać porządnie, czyli modułowo, małe kawałki kodu, do każdego unit testy, jak moduły współpracują ze sobą to testy funkcjonalne. Będziesz eliminować dużo błędów na bieżąco.


MasterBLB
  • Rejestracja:około 19 lat
  • Ostatnio:5 dni
  • Lokalizacja:Warszawa
  • Postów:1454
0

Z uwag ogólnych Siostro @Dominika Łęczycka

  • dla nazw zmiennych/funkcji stosuj camelCase
  • w programie masz elementy takie jak Player, Ship, Board i Game. Warto stworzyć osobne pliki .h i .cpp dla każdego.
  • rzeczy wspólne, wykorzystywane przez różne elementy, na przykład enumy, wskazane jest dodać do wspólnego pliku definitions.h
  • zastanów się i zdefiniuj odpowiedzialności poszczególnych elementów. Za co ma być odpowiedzialny Ship, za co Board itd.

"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
Dominika Łęczycka
Tyle, że ja mam problem z podłączeniem poszczególnych plików do projektu 🙁 Bo czasem- tak jak teraz wyskakują mi dość dziwne błędy (Te dyrektywy w kodzie były w osobnych liniach, tak mi się jakoś skopiowało do wpisu)
MasterBLB
W każdym IDE w jakim pisałem programy była opcja "Add header/source file to existing project" która działała bez zarzutu. Czego ty używasz?
TomaszLiMoon
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 12 godzin
  • Postów:530
0

Kilka moich uwag odnośnie kodu.

  1. Generalnie każda klasa/struktura powinna być umieszczona w osobnych plikach ( definicja w nagłówku *.h i implementacja w *.cpp ) .
    To poprawi czytelność projektu i rozdzieli kod na podstawowe jednostki/moduły.
  2. Zamień wszystkie definicje wyliczeń enum na enum class, gdyż zmniejszają ryzyko wystąpienia błędów związanych z niejawną konwersją typów.
  3. Spróbuj pomyśleć o prawdziwie obiektowym kodzie ( wiem że to jest trudne dla początkujących ) w którym każda funkcja jest składową jakieś klasy.
  4. Używaj komponentów STL (np. vector,string) tam gdzie to jest możliwe.
    Na przykład strukturę Player można zaimplementować w następujący sposób:
Kopiuj
struct Player
{
    Player( const string& _playerName, int numShips, int boardSize )
    : playerName{_playerName}
    {
       ships.resize(numShips);
       guessBoard.resize(boardSize);
       for( auto& row : guessBoard ) row.resize(boardSize);
       shipBoard.resize(boardSize);
       for( auto& row : shipBoard ) row.resize(boardSize);
    }

    string playerName;
    vector<Ship> ships;
    vector<vector<GuessType>> guessBoard;
    vector<vector<ShipPartType>> shipBoard;
};
............
Player player("Pirate",5,20);
Dominika Łęczycka
Tyle, że ja mam problem z podłączeniem poszczególnych plików do projektu 🙁 Bo czasem- tak jak teraz wyskakują mi dość dziwne błędy (Te dyrektywy na początku w kodzie były w osobnych liniach, tak mi się jakoś skopiowało do wpisu) -
Dominika Łęczycka
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 5 lat
  • Postów:13
0
MasterBLB napisał(a):

Z uwag ogólnych Siostro @Dominika Łęczycka

  • dla nazw zmiennych/funkcji stosuj camelCase
  • w programie masz elementy takie jak Player, Ship, Board i Game. Warto stworzyć osobne pliki .h i .cpp dla każdego.
  • rzeczy wspólne, wykorzystywane przez różne elementy, na przykład enumy, wskazane jest dodać do wspólnego pliku definitions.h
  • zastanów się i zdefiniuj odpowiedzialności poszczególnych elementów. Za co ma być odpowiedzialny Ship, za co Board itd.

Code::Blockds 17.12

Oczywiście dodaję zawsze w ten sposób, w który napisałeś. Jak nie działa od razu, to próbuję dopisać dyrektywy, ale tym razem pojawia mi się błąd:
unterminated ifndef

Silv
Moderator Wiki
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa
0
Dominika Łęczycka napisał(a):

Oczywiście dodaję zawsze w ten sposób, w który napisałeś. Jak nie działa od razu, to próbuję dopisać dyrektywy, ale tym razem pojawia mi się błąd:
unterminated ifndef

Jak obecnie wyglądają u Ciebie wszystkie dyrektywy (ze wszystkich plików)? (#include, #define itd.)


edytowany 1x, ostatnio: Silv
Dominika Łęczycka
właśnie zauważyłam, że nie dodałam #endif na końcu pliku Battleship.h -na razie pozbyłam się tego błędu ;-) PS. Jesteś pewny, że powinnam tworzyć oddzielny plik dla każdej klasy? Bo to gra na konsolę i jest w gruncie rzeczy dość prosta (możnaby nawet powiedzieć prymitywna). Jak się uprzeć, to można by wszystko napisać w jednym pliku. Naprawdę byłoby lepiej, gdyby to wszystko porozdzielać? Wtedy do takiej mini-gry ów plików zrobi się naprawdę dużo...
Silv
Nie jestem pewien. To zależy. Nie znam się na C/C++, ale ogólnie rzecz biorąc: jeśli myślisz, że nie wyjdziesz ponad np. 10 funkcji/3 klasy, to być może warto zostawić wszystko w jednym pliku. Jeśli jednak zakładasz lub zauważysz w pewnym momencie, że tych funkcji i klas będzie/powinno być znacznie więcej, by to miało sens, to myślę, że lepiej należy rozdzielić. Ogólnie podział programu na pliki jest jednym z fundamentów architektury programów. Tak czy siak kiedyś będziesz musiała zacząć to dzielić, jeśli planujesz programować więcej niż takie gry jak teraz. :)
Silv
PS. Nie mówię oczywiście, że ta gra jest nic niewarta. Chodzi mi o inne rozróżnienie: czasem nawet nic niewarte, ale złożone aplikacje potrafią posiadać bardzo dużo plików.
Dominika Łęczycka
Dziękuję za podpowiedź ;-) Myślę, że tutaj zostawię już liczbę plików tak, jak jest, Ale przy kolejnych odrobinę większych projektach na pewno wezmę to pod uwagę 🙂
Silv
Jeśli chodzi o jakieś źródło – nie mogę podać Ci jednego źródła, bo każde ma wady i zalety, ale wpisz sobie w Google: C++ reasons splitting code multiple files i przejrzyj wyniki. Zwróciłbym szczególną uwagę na wątki ze stron "*.stackexchange.com" oraz "stackoverflow.com". Ewentualnie możesz nawet wpisać tak w Google – site:stackoverflow.com C++ reasons splitting code multiple files. Znajdzie Ci wyłącznie strony w domenie "stackoverflow.com".
Dominika Łęczycka
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 5 lat
  • Postów:13
0
Dominika Łęczycka napisał(a):

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:

Kopiuj
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:

Kopiuj
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

Kopiuj
#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:

Kopiuj
/*
    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:

Kopiuj
#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

Kopiuj
#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ź :-)

Poprzednie błędy już udało mi się poprawić.
Kiedy zmieniłam warunek w funkcji GetShipReprezentation z if(player.guessBoard[row][col].isHit na if(player.guessBoard[row][col]==GT_HIT), kompilator zamiast poprzedniego błędu pokazał mi komunikat 1d returned exit status. Kiedyś miałam już taką sytuację i po prostu tamtego programu nie naprawiłam, bo nie wiedziałam, co z tym zrobić. Ale tej gry nie chciałabym tak po prostu porzucić nieskończonej, bo już dużo czasu nad tym spędziłam :-(

Czy ktoś może kiedyś rozwiązał już podobny problem?
Resetowałam już komputer.
spróbowałam też otworzyć wcześniej działający projekt, dodać odpowiednią ilość plików i po prostu przekleić treść, ale też nie działa :-(
Bardzo proszę o odpowiedź, co mogę jeszcze zrobić w tej sytuacji.

Silv
Moderator Wiki
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa
1
  1. Podaj wszystko, co Code::Blocks wypisuje na wyjściu (rozumiem, że budujesz projekt w Code::Blocks).
  2. Czy tam nie powinno być ld ("el-de") zamiast 1d?
  3. Czy w komunikacie nie ma przypadkiem nazwy collect2? (w internecie można spotkać ten błąd z taką nazwą)
  4. Zobacz to: http://users.csc.calpoly.edu/~jdalbey/101/Resources/errormessages.html Nie sądzę, by trzeba było załączyć wspomnianą na tej stronie bibliotekę math, ale być może zapomniałaś dołączyć, lub źle dołączasz, w jakimś pliku jakąś inną bibliotekę lub plik.
  5. Jak czytam w internecie, część ld być może oznacza, że to linker (a nie kompilator) wyrzuca błąd (zwrócenie statusu 1 oznacza w rozumieniu Linuksa błąd). Możesz zobaczyć dla ciekawości to: https://linux.die.net/man/1/ld

UPDATE: 6. Również na tej stronie wspominany jest podobny błąd: http://web.mst.edu/~cpp/common/common_errors.html


edytowany 8x, ostatnio: Silv
Zobacz pozostałe 5 komentarzy
Dominika Łęczycka
-W projekcie znajduje się jedna funkcja int main zwracająca 0, w ustawieniach mam zaznaczone Have g++ follow the C++11 ISO language standard [-std=c++11] -próbowałam też zaznaczyć Treat as errors the warnings demanded by strict IScO C and ISO C++ [-pedantic-errors], ale nie pomogło -Posiadałam wcześniej działający projekt o nazwie test (w który wklejałam sobie różne fragmenty kody, żeby testować)- dodałam do projektu odpowiednią ilość plików i przekleiłam kod z poprzedniego projektu- dalej ten sam błąd. -Spróbowała też stworzyć nowy projekt testowy, w którym
Dominika Łęczycka
w którym umieściłam wszystko w jednym pliku (bo pomyślałam, że może z łączeniem plików jest problem), ale dalej pokazuje mi się ten sam błąd -oryginalny projekt nazywa się Battleship, w nazwach poszczególnych plików nie ma żadnych 'dziwnych znaków', tylko duże i małe litery -projekt znajduje się w folderze na pulpicie o nazwie C++, ale z tym raczej nie powinno być problemu, bo inne projekty znajdujące się tam działają. Próbowałam też przenieść projekt na pulpit, ale nie pomogło.
Silv
@Dominika Łęczycka: jeśli odpowiadasz w temacie, pisz odpowiedzi, nie komentarze. Trudniej się dyskutuje, jeśli każda odpowiedź dotyczy czego innego, a tak byłby jeden ciąg odpowiedzi z siebie wynikających.
Dominika Łęczycka
a, jasne- postaram się na przyszłość. Przepraszam, jeśli zaciemniam przekaz
Silv
Jeśli chodzi o komentarze, to zaraz je przeczytam. Odpowiem w odpowiedzi, jeśli to coś w temacie.
au7h
  • Rejestracja:ponad 11 lat
  • Ostatnio:12 miesięcy
  • Postów:215
0

Jeżeli "statki w konsoli" nazywasz większym projektem, w dodatku tak napisanym to lepiej daj sobie z tym spokój. Piszesz niby w c++ a to wygląda jak c. Nie korzystasz z dobrodziejstw jakie daje biblioteka STL. Jedyny plus to chyba taki że korzystasz z cin cout zamiast z printf scanf tak jak większość :-D

edytowany 2x, ostatnio: au7h
Silv
Motywujące to raczej nie jest.
Dominika Łęczycka
A ja Ci zrobię na złość i sobie nie odpuszczę 😝😝😝
Dominika Łęczycka
A uczę się tego języka dopiero jakieś 2 miesiące i projekt jest większy w porównaniu do innych, które robiłam do tej pory. Nie w porównaniu do tego, co można stworzyć w c++
Dominika Łęczycka
Czego ty oczekujesz??? Że ucząc się wszystkiego sama(bo nauczycielka informatyki w liceum powiedziała mi, że wskaźniki są trudne i zaczniemy się ich uczyć dopiero za 2 lata) od razu napiszę prawdziwą dużą grę? Projekty nie na konsolę też pisałam, ale np. Z dodatkiem buildera -więc teraz czysto w c++ mi jest trudniej
Dominika Łęczycka
I naprawdę lubię to, co robię, a na pewno sobie nie odpuszczę, bo ty tak twierdzisz 🖕
Stefan_3N
  • Rejestracja:około 6 lat
  • Ostatnio:10 dni
  • Postów:145
1

Nie chce mi się wgryzać w logikę programu, ale isHit jest elementem struktury ShipPartType, więc jeśli zamienisz
if(player.guessBoard[row][col].isHit)
na
if(player.shipBoard[row][col].isHit)
to ten fragment się skompiluje (ale czy taki był zamiar i się pomyliłaś, to nie wiem).

Poza tym jest błąd w strcpy(player, playerName); ale może to już poprawiłaś.

Wygląda mi na to, że nie uruchamiasz kodu fragmentami i go nie rozbudowujesz, tylko piszesz w całości i potem próbujesz w całości to uruchomić.

Powodzenia, nie poddawaj się :-).


Zobacz pozostałe 15 komentarzy
Stefan_3N
Jak użyjesz extern, to nie możesz przypisywać już wartości.
Dominika Łęczycka
o, na razie (po usunięciu) udało się odpalić :-)
Stefan_3N
Proszę :-). Staraj się pisać kod małymi fragmentami i nie idź dalej, póki to co masz się nie kompiluje, bo potem trudno znaleźć przyczynę.
Silv
O, nawet nie zauważyłem, że taka dyskusja tu jest.
Silv
Moderator Wiki
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa
1

Szkoda trochę, że nie mam Windowsa, bo by było większe prawdopodobieństwo, że trafię na ten sam błąd. Spróbuję stworzyć nowy projekt z tymi samymi plikami i zawartością, co podałaś.


UPDATE: Spróbowałem. Nie uruchamiałem, ale udało mi się sprawić, że buduje się bez problemów. Nie wiem jak u Ciebie na Windowsie, ale u mnie na Linuksie wyskoczyło kilka błędów (zawsze były odpowiednie komunikaty w zakładce "Build log" "Build messages"). Przechodziłem po kolei w miejsca ich występowania i komentowałem całe linijki (skrót do zakomentowania linijki, na Linuksie przynajmniej: CTRL+SHIFT+C). Teraz spróbuję zrobić, żeby działało bez komentowania tych linijek.


UPDATE2:

Podam swoje poprawki (w kolejności raportowania błędów przez Code::Blocks):

Błąd nr 1: main.cpp|13|error: ‘InitializePlayer’ was not declared in this scope|
Poprawiłem, dodając w pliku Battleship.h linijkę: void InitializePlayer(Player & , const char * );

Błąd nr 2: main.cpp|18|error: ‘PlayGame’ was not declared in this scope|
Poprawiłem, dodając w pliku Battleship.h linijkę: void PlayGame(Player& , Player&);

Błąd nr 3: Battleship.cpp|16|error: cannot convert ‘Player’ to ‘char*’|
Poprawiłem tymczasowo, komentując całą linijkę (nie wiem, co chciałaś osiągnąć, więc nie mogę poprawić inaczej).

Błąd nr 4: Battleship.cpp|19|error: ‘InitializeShip’ was not declared in this scope; did you mean ‘InitializePlayer’?|
Poprawiłem, przenosząc funkcję InitializeShip przed funkcję InitializePlayer.

Błąd nr 5: Battleship.cpp|38|error: ‘SetUpBoards’ was not declared in this scope|
Poprawiłem, przenosząc funkcję SetUpBoards przed funkcję PlayGame.

Błąd nr 6: Battleship.cpp|38|error: ‘ClearBoards’ was not declared in this scope|
Poprawiłem, przenosząc funkcję ClearBoards przed funkcję SetUpBoards.

Błąd nr 7: Battleship.cpp|53|error: ‘DrawBoards’ was not declared in this scope|
Poprawiłem, przenosząc funkcję DrawBoards przed funkcję SetUpBoards.

Błąd nr 8: Battleship.cpp|52|error: ‘DrawColumnsRow’ was not declared in this scope|
Poprawiłem, przenosząc funkcję DrawColumnsRow przed funkcję DrawBoards.

Reszta zaraz...


UPDATE3:

Błąd nr 9: main.cpp|19|error: ‘WantToPlayAgain’ was not declared in this scope|
Poprawiłem, dodając w pliku Battleship.h linijkę bool WantToPlayAgain();.

Błąd nr 10: Battleship.cpp|69|error: ‘DrawSeparatorLine’ was not declared in this scope|
Poprawiłem, przenosząc funkcję DrawSeparatorLine przed funkcję DrawBoards.

Błąd nr 11: Battleship.cpp|86|error: ‘DrawShipBoardRow’ was not declared in this scope|
Poprawiłem, przenosząc funkcję DrawShipBoardRow przed funkcję DrawBoards.

Błąd nr 12: Battleship.cpp|79|error: ‘GetShipReprezentation’ was not declared in this scope|
Poprawiłem, przenosząc funkcję GetShipReprezentation przed funkcję DrawShipBoardRow.

Błąd nr 13: Battleship.cpp|74|error: request for member ‘isHit’ in ‘player.Player::guessBoard[row][col]’, which is of non-class type ‘const GuessType’|
Poprawiłem tymczasowo, komentując całą instrukcję if, w której znajduje się to wywołanie funkcji isHit (nie wiem, co chciałaś osiągnąć, więc nie mogę poprawić inaczej).

Błąd nr 14: Battleship.cpp|130|error: ‘DrawGuessBoardRow’ was not declared in this scope; did you mean ‘DrawShipBoardRow’?|
Poprawiłem, przenosząc funkcję DrawGuessBoardRow przed funkcję DrawBoards.

Błąd nr 15: Battleship.cpp|120|error: ‘GetGuessRepresentationAt’ was not declared in this scope; did you mean ‘GetShipReprezentation’?|
Poprawiłem, przenosząc funkcję GetGuessRepresentationAt przed funkcję DrawGuessBoardRow.

Błąd nr 16:

Kopiuj
/usr/bin/ld: obj/Debug/Utils.o:[...]Utils.cpp|8|multiple definition of `INPUT_ERROR_STRING'; obj/Debug/Battleship.o:[...]Battleship.cpp:9: first defined here|

Nie jestem pewien, ale jak do tej pory to chyba jedyne miejsce, w którym występuje błąd związany z programem ld. Poprawiłem, usuwając definicję stałej INPUT_ERROR_STRING z plików: main.cpp oraz Utils.cpp.

Teraz, po zbudowaniu, otrzymuję komunikat:

Kopiuj
...
Process terminated with status 0 (0 minute(s), 1 second(s))
0 error(s), 0 warning(s) (0 minute(s), 1 second(s))

Zobaczmy, czy się uruchomi...


UPDATE4: Uruchomiło się (nie grałem, bo z uwagi na tymczasowe zakomentowanie dwóch linijek mogą być jakieś błędy).


PS. Plik Intruction.cpp mam cały zakomentowany, tak jak Ty podałaś na forum, więc nie wiem – może to dlatego mi działa?


edytowany 8x, ostatnio: Silv
Dominika Łęczycka
*Bląd 1: ale w pliku Battleship.h już istnieje ta linia kodu
Silv
Być może zmieniłaś coś w międzyczasie? U mnie jej nie było.
Silv
*Tzn. w tym kodzie, co podałaś na forum.
Dominika Łęczycka
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 5 lat
  • Postów:13
0

Właśnie- zadziałało mi na razie po prawnie- tylko po usunięciu deklaracji INPUT_ERROR_STRING z pliku Utils.cpp
(niestety rodzice zmusili mnie do odejścia od koputera, więc nie odpisałam wcześniej)

Myślisz, że powinnam pozmieniać też te wszystkie inne rzeczy?

edytowany 1x, ostatnio: Dominika Łęczycka
Silv
Aha, jak odpowiadasz, to dobrze by było, żebyś nie cytowała całej poprzedniej odpowiedzi, a jedynie potrzebne fragmenty. :)
Silv
O, dziękuję.
Silv
Moderator Wiki
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa
1

Czy powinnaś pozmieniać to nie wiem. Znam jedynie podstawy C++, ale ogólnie w programowaniu jest tak, że definicje i deklaracje funkcji powinny być przed ich wywołaniem. Znam jeden język, który umożliwia dowolne układanie definicji funkcji w stosunku do wywołań: JavaScript (i jest to raczej uważane za niedobrą cechę). Natomiast w pliku nagłówkowym (z rozszerzeniem h) powinny być deklaracje wszystkich funkcji, które są używane tam, gdzie ten plik jest dołączany (deklaracje, czyli nagłówki tych funkcji, stąd nazwa pliku).


PS: Technicznie rzecz biorąc, deklaracja funkcji oraz jej nagłówek to chyba co innego. Więc nie sugeruj się moją wiedzą. ;) Możesz przeczytać np. ten artykuł: http://www-h.eng.cam.ac.uk/help/languages/C++/c++_tutorial/functions.html


edytowany 2x, ostatnio: Silv
Zobacz pozostałe 21 komentarzy
stivens
To dopiero bez sensu
Silv
Jeśli nie znalazłoby się przeciwwskazanie do wywoływania metod publicznych, miałoby to rzeczywiście mniej sensu.
stivens
Ale to przeciwskazanie wydaje sie... fanatyczne
Silv
Nie wiem, o jakim piszesz? Nie podałem żadnego.
Silv
Ty podałeś alternatywę w przypadku, gdyby takie przeciwwskazanie było, ale właśnie nie jestem pewien, czy jest w ogóle sens rozważać alternatywę, skoro nie ma przeciwwskazań.
Dominika Łęczycka
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 5 lat
  • Postów:13
0

Dobrze, a więc- to, czego nie poprawiłam juz wcześniej, a było w Twoich wskazówkach- zrobiłam teraz. Na razie nadal działa. Dziękuję bardzo za pomoc :-)

Silv
W mojej ocenie bardzo dobre źródła dotyczące języka C++ to te strony: https://en.cppreference.com/w/ oraz http://www.cplusplus.com/ W obu jest np. dział Reference, czyli, hm, zwięzły opis (danego) języka.
Silv
Tzn. obie strony są po angielsku, być może to będzie dla Ciebie pewien problem. Ale nie znam polskich odpowiedników (pewnie jakieś są).
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)