jeudi 28 mars 2019

new to c++ doubly link list advice/corrections please

I'm currently working on making a Racko card game using doubly link list, but I am still new to c++ and doubly link list are going over my head a bit, at least how I am required to write it.

The Card Class

This class is responsible for storing information on a card for the game. A Card is a doubly-linked node with both a previous and next pointer to other Cards. Note that in the test, the constructor is called with different numbers of arguments. This is because both prev and next have default parameter values of nullptr (read 5.9 in the book). In addition to the parameterized constructors, this class should have methods for accessing and setting its fields.

The Deck Class

This class is responsible for holding decks of cards in the Racko game. We will have separate decks for the discard pile and the draw pile. For most purposes, a Deck is a stack linked together by Cards with the one caveat that you can also insert into any position. This class should have the following additional methods:

MakeFullDeck () Creates a starting Racko deck of all 60 cards. Push () Creates a new Card from the passed in value and puts it on top of the Deck. Discard () Similar to Push but takes in a Card* instead of making a new Card. Draw () Removes the Card from the top of the Deck and returns it. Peek () Returns the value of the Card on top of the Deck without removing the Card. Shuffle () Rearranges the Cards in the Deck. You can choose how the Deck gets rearranged. InsertAt () Inserts a Card at the given position, starting from 0.

I am working of a test.cpp test case file that I need to pass with my code by doing "make clean test". I marked out the classes I am not working on and I have already gotten my card.cpp class to pass its test, but I'm stuck on the deck.cpp test case. the test case file is below. I'm actually stuck on the deck.cpp and I haven't been able to figure out the proper way to write the code as a doubly linked list and really need some help. The card class is supposed to be the equivalent to a node class that you would back when traditionally doing linked list, but my instructions where very specific.

#define CATCH_CONFIG_MAIN

#include <set>

#include "catch/catch.hpp"
#include "../card.hpp"
#include "../deck.hpp"
/*#include "../hand.hpp"
#include "../player.hpp"
#include "../game.hpp"
*/
TEST_CASE("Test card class")
{
    Card* twelve = new Card(12);
    REQUIRE(twelve->GetValue() == 12);
    Card* one = new Card(1, twelve);
    Card* two = new Card(2, twelve, one);
    one->SetPrev(two);
    twelve->SetNext(two);
    REQUIRE(twelve->GetNext()->GetValue() == 2);
    REQUIRE(one->GetPrev()->GetValue() == 2);
    REQUIRE(twelve->GetNext()->GetPrev()->GetValue() == 12);
    REQUIRE(one->GetPrev()->GetNext()->GetValue() == 1);
}


TEST_CASE("Test deck basics")
{
    // create deck
    Deck deck;
    REQUIRE(deck.Peek() == -1);
    deck.Push(1);
    deck.Push(2);
    deck.Push(3);
    deck.Push(4);
    deck.Push(5);
    deck.Push(6);
    Card* six = deck.Draw();
    REQUIRE(six->GetValue() == 6);
    REQUIRE(six->GetNext() == nullptr);
    REQUIRE(six->GetPrev() == nullptr);

    REQUIRE(deck.Peek() == 5);

    deck.Discard(six);
    REQUIRE(deck.Peek() == 6);
}

/*
TEST_CASE("Test full deck")
{
    Deck deck;
    deck.MakeFullDeck();

    //check for fullDeck    
    std::set<int> seen;
    bool correctCards = true;
    int numberOfCards = 0;
    Card* nextCard = deck.Draw();
    while(nextCard != nullptr)
    {
        numberOfCards++;
        int cardValue = nextCard->GetValue();
        if((cardValue < 1) || (cardValue > 60) || !seen.insert(cardValue).second)
        {
            correctCards = false;
            break;
        }
        nextCard = deck.Draw();
    }
    REQUIRE((correctCards && (numberOfCards == 60)));
}
*/

/*
TEST_CASE("Test shuffling")
{
    Deck unshuffledDeck;
    Deck shuffledDeck;
    unshuffledDeck.MakeFullDeck();
    shuffledDeck.MakeFullDeck();
    shuffledDeck.Shuffle();

    bool deckShuffled = false;

    Card* fromUnshuffled;
    Card* fromShuffled;
    for(int comparisonIndex = 0; comparisonIndex < 60; comparisonIndex++)
    {
        fromUnshuffled = unshuffledDeck.Draw();
        fromShuffled = shuffledDeck.Draw();
        if(fromUnshuffled->GetValue() != fromShuffled->GetValue())
        {
            deckShuffled = true;
            break;
        }   
    }
    REQUIRE(deckShuffled);
}
*/

/*
TEST_CASE("Testing user hand functions")
{
    Hand myHand;

    for (int i = 10; i > 0; --i)
    {
        myHand.AddToHand(new Card(i));
    }

    REQUIRE(myHand.HasRacko());

    Card* twenty = new Card(20);
    Card* two = myHand.SwapOutCard(twenty, 2);
    REQUIRE(!myHand.HasRacko());
    REQUIRE(two->GetValue() == 2);

    Card* foo = myHand.SwapOutCard(two, 1);
    REQUIRE(foo->GetValue() == 1);
    Card* bar = myHand.SwapOutCard(twenty, 10);
    REQUIRE(bar->GetValue() == 10);
}
*/

/*
TEST_CASE("Player")
{
    Hand paw;
    for (int i = 10; i > 0; --i)
    {
         paw.AddToHand(new Card(i));
    }

    Player player1("Snuka", paw);
    REQUIRE(player1.GetName() == "Snuka");
    REQUIRE(player1.IsComputer() == false);

    REQUIRE(player1.ShowHand() == "1: 1\n2:  2\n3:   3\n4:    4\n5:     5\n6:      6\n7:       7\n8:        8\n9:         9\n10:          10\n");

    std::string turnPrompt = player1.TurnPrompt();
    REQUIRE("Snuka's turn" == turnPrompt);

    Card* discard = new Card(20);
    player1.SwapOutCard(discard, 3);
    REQUIRE(player1.ShowHand() == "1: 1\n2:  2\n3:                    20\n4:    4\n5:     5\n6:      6\n7:       7\n8:        8\n9:         9\n10:          10\n");

    // Create empty player and add details
    Player player2;
    player2.SetName("Sophie");
    player2.SetHand(paw);
}
*/

/*
TEST_CASE("Game basics")
{
    // create game with 2 players
    std::vector<Player> players;
    Player player1;
    player1.SetName("Snuka");
    player1.SetIsComputer(true);
    players.push_back(player1);
    Player player2;
    player2.SetName("Sophie");
    player2.SetIsComputer(true);
    players.push_back(player2);

    Game game(players);

    // test show hand
    REQUIRE(game.GetPlayer(1)->ShowHand() != "");
    REQUIRE(game.GetPlayer(2)->ShowHand() != "");

    // test show discard value
    REQUIRE(game.ShowTopOfDiscardPile() > 0);

    // make sure that an empty deck refills by shuffling the discard pile
    for (int i = 0; i < 60; ++i)
    {
        Card* card = game.DrawFromDeck();
        game.Discard(card);
    }

    game.DoNextTurn(); // Quick check to ensure that simple runtime errors don't exist
    REQUIRE(!game.IsGameOver());

    Hand winningHand;

    for (int i = 10; i > 0; --i)
    {
        winningHand.AddToHand(new Card(i));
    }

    game.GetPlayer(2)->SetHand(winningHand);

    game.DoNextTurn();
    REQUIRE(game.IsGameOver());
}
*/

/*
TEST_CASE("Test computer decision")
{
    Hand hand;

    for (int i = 10; i > 0; --i)
    {
        if (i == 5)
        {
            hand.AddToHand(new Card(3));
        }
        else
        {
            hand.AddToHand(new Card((i) * 6));
        }
    }

    bool isComputer = true;
    Player player1("Snuka", hand, isComputer);
    REQUIRE(player1.IsComputer() == true);

    REQUIRE(player1.MakeChoice(31) == "p"); // discard pile is good card
    REQUIRE(player1.MakeChoice(10) == "d"); // pile was bad, draw from the deck
    REQUIRE(player1.MakeChoice(1) == "p"); // discard pile is good card
    REQUIRE(player1.MakeChoice(60) == "p"); // discard pile is good card
    REQUIRE(player1.HasRacko() == false); // discard pile is good card

}
*/

// Compile & run:
// make clean test

card.hpp:

#ifndef CARD_HPP
#define CARD_HPP
#include <iostream>
#include <string>

class Card
{
    private:
        int value;
        Card* prev;
        Card* next;
    public:
        Card(int value, Card* prev = nullptr, Card* next = nullptr);
        void SetNext(Card* next);
        void SetPrev(Card* prev);
        int GetValue();
        Card* GetNext();
        Card* GetPrev();
};
#endif

card.cpp:

#include "card.hpp"

Card::Card(int value, Card* prev, Card* next)
{
    this->value = value;
    this->prev = prev;
    this->next = next;
}

void Card::SetNext(Card* next)
{   
    this->next = next;
}

void Card::SetPrev(Card* prev)
{
    this->prev = prev;
}

int Card::GetValue()
{
    return value;
}

Card* Card::GetNext()
{
    return next;
}

Card* Card::GetPrev()
{
    return prev;
}

deck.hpp:

#ifndef DECK_HPP
#define DECK_HPP
#include "card.cpp"
#include <iostream>
#include <string>

class Deck
{
    private:
        Card* top;
        const int NUMBER_OF_CARDS_IN_RACKO_DECK = 60;
        int numberOfCardsInDeck;
    public:
        Deck();
        void MakeFullDeck();
        void Push(int value);
        void Discard(Card* card);
        Card* Draw();
        int Peek();
        void Shuffle();
        void InsertAt(Card* card, int index);
};
#endif

deck.cpp:

#include "deck.hpp"

Deck::Deck()
{
    Card* top =  nullptr;
    int numberOfCardsInDeck = 0;

}

void Deck::MakeFullDeck()
{
    //Creates a starting Racko deck of all 60 cards.
    for(int i = 1; i < NUMBER_OF_CARDS_IN_RACKO_DECK; ++i)
    {
        Card* card = new Card(i, nullptr, nullptr);
        numberOfCardsInDeck++;
        card->SetPrev(nullptr);
        card->SetNext(this->top);
        if(this->top != nullptr)
        {
            card = this->top->GetPrev();
        }else
        {
            this->top = card;
        }
    }
}

void Deck::Push(int value)
{
    //Creates a new Card from the passed in value and puts it on top of the Deck.
    Card* newCard = new Card(value, nullptr, nullptr);
    newCard->SetPrev(nullptr);
    newCard->SetNext(this->top);
    if(this->top != nullptr)
    {
        newCard = this->top->GetPrev();
    }else
    {
        this->top = newCard;
    }
}

void Deck::Discard(Card* card)
{
    //Similar to Push but takes in a Card* instead of making a new Card.
    card->SetPrev(nullptr);
    card->SetNext(this->top);
    if(card == nullptr)
    {
        return;
    }

    if(card != nullptr)
    {
        card = this->top->GetPrev();
    }else
    {
        this->top = card;
    }

}

Card* Deck::Draw()
{
    //Removes the Card from the top of the Deck and returns it.

}

int Deck::Peek()
{
    //Returns the value of the Card on top of the Deck without removing the Card.
}

void Deck::Shuffle()
{
    //Rearranges the Cards in the Deck. You can choose how the Deck gets rearranged.
}

void Deck::InsertAt(Card* card, int index)
{
    //Inserts a Card at the given position, starting from 0.
}

Any assistance would be appropriated as I am at a loss on how to write the code correctly at this point for the deck.cpp. Any corrections and advise is much appreciated.

Aucun commentaire:

Enregistrer un commentaire