CS 5007: Assignment 4 (Part 1 and 2)

Summer 2019

Part 1 DUE Jun 5, 2019, 6pm.

Part 2 DUE Jun 12, 2019, 6pm.

Objectives

Summary/Overview

In this assignment, you are going to implement some key components to a card game. The card game is NEUchre (pronounced "N-E-U-ker"), which is a 2-player version of a game called Euchre (pronounced "U-ker"). To get a sense of the game, you can play the traditional version at https://cardgames.io/euchre/.

There are two parts to this project, and many options for a challenge. Part 1 requires you to implement some data structures for the game. Part 2 requires you to implement some logic to support the game play.

Once you've implemented these two parts, you can play a simple version of the game. Solving some of the Challenges at the end of this assignment will build on the game and make it more fun!

Relevant Reading

Background

Basic rules of NEUchre

NEUchre is a 2-player game. The player with the most points after 5 rounds wins. A player wins a round by "collecting the most tricks". A round consists of each player being dealt 5 cards, choosing a trump (a suit designated as the highest/most powerful for this round), and then each player takes turns playing cards for a "trick". A player wins a trick by playing the highest value card. There are a couple of rules that must be followed for playing a card: the first player can play any card, but the second player must "follow suit": if they have a card of the same suit, they must play it (but they can choose which card they want to play). Further, a card of the trump suit is higher than all other cards in the deck. For example, if Spades is trump, a 9 of Spades is higher than an Ace of Diamonds. Within a suit, including trump, the face value of the card is highest, with Aces being the highest value card.

In this version of the game, Player 1 (the computer) ALWAYS goes first and leads the first card.

The deck used for NEUchre is a subset of the traditional 52-card deck. It includes the Ace, King, Queen, Jack, 10 & 9 of all four suits (Spades, Diamonds, Hearts, and Clubs).

We've provided support code to play the game; you need to fill in some very specific pieces of code.

Details

You'll see that in a4.h, we've begun to define some data structures for you. Cards have Suits and Names. A Deck is a Stack of Cards, and a Hand is a doubly-linked-list of list nodes called CardNodes.

Suits have both a Name and a Color. Cards have a Name, Suit and Value.

Part 0: Check out starter code and copy into your repo

The CS 5007 resources repo has some starter code for this assignment. Check it out (clone into it's own folder/local repo), and copy the a4 folder over to your own personal repo.

Part 1: Implementing the Game Data Structures

Implementing the Deck

The basic struct for Deck is already there, but you need to implement the Deck functions yourself.

Add your code to deck.c.

Implement the Deck as a Stack based on an array. For this implementation, aDeck->topCard is always pointing to the card at the top of the stack; when it's initialized (there are no cards in the stack), aDeck->topCard should equal -1.

You are asked to implement the following stack functions that will form the stack:

Part 2: Implementing the Hand

Implement the hand in a4.c.

The Hand has the following characteristics:

  1. It can be ordered in various ways
  2. We can easily add new cards and remove cards from the hand

For this assignment, implement the Hand as a doubly-linked list.

Part 3: Implementing Game Functions

Now that you have some of the data structures, write the code that uses them to make the game run.

The following functions should be implemented in a4.c:

  1. int isLegalMove(Hand *hand, Card *leadCard, Card *playedCard);
    Given a card that is lead, a player's hand, and the card the player wants to play, is it legal? If the player has a card of the same suit as the \texttt{leadCard}, they must play a card of the same suit. If the player does not have a card of the same suit, they can play any card. For this, it might be helpful to define a helper function that determines if a hand has any cards of a given suit.
  2. int whoWon(Card *leadCard, Card *followedCard, Suit trump);
    Given two cards that are played in a hand, which one wins? If the suits are the same, the higher card value wins. If the suits are not the same, player 1 wins, unless player 2 played trump. Return 1 if the person who led won, 0 if the person who followed won.

These functions should be implemented in deck.c:

  1. populateDeck();
    Create all the cards and pushes them into the Deck.
  2. shuffleDeck(Deck*);
    Takes all the cards in the deck, rearrange the order, and push the cards back into the Deck.
  3. deal(Deck*, Hand*, Hand*);
    Takes a shuffled deck and deals the cards one by one to the each hand.

Part 4: Using Valgrind to verify you have no leaks

Since we're starting to use the heap, it's time to learn how to use Valgrind.

For the rest of the semester, we'll be testing whether your code has any memory leaks. We use Valgrind for this.

First, install Valgrind:

  bash% sudo apt-get install valgrind

Try out Valgrind for yourself, to make sure you can run it:

  bash% valgrind --leak-check=full ./hello_world

You want to see that there are no memory leaks. Your output should be something like this. Note that the HEAP SUMMARY notes that there is no heap in use at exit.

==8114== Memcheck, a memory error detector
==8114== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8114== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8114== Command: ./example2
==8114==
aThing is at 0xfff0003e0 with value 6 and age 42
==8114==
==8114== HEAP SUMMARY:
==8114==     in use at exit: 0 bytes in 0 blocks
==8114==   total heap usage: 2 allocs, 2 frees, 1,032 bytes allocated
==8114==
==8114== All heap blocks were freed -- no leaks are possible
==8114==
==8114== For counts of detected and suppressed errors, rerun with: -v
==8114== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Part 5: Check style issues

Please be sure to follow the Course Style Guide for your C code.

Since you used clint for the last assignment, it is still available for you to use this assignment. If you followed the directions last time, you DO NOT need to copy clint.py to your a4 directory this time.

Run clint as such:

  bash% clint.py a4.c
  

No style-checking tool is perfect, but you should try to clean up any problems that clint detects unless clint flags something that is definitely not a problem in this particular context (but be sure you have very good reasons to ignore any warnings).

Be sure to check all the files you write.

Part 6: Challenges

If you've implemented the above, consider the following improvements to the game. Note: currently, tests haven't been written to test the challenge functions. These will be added later, or you can write your own.

Submit these changes with your final assignment submission. Partial implementation of any of these will be reviewed. Progress will be considered for your final grade. Not attempting any of these will have no impact on your assignment grade or final grade.

Challenge 1: Shuffle the computer's hand so it is unpredictable

Difficulty: Medium

Implement void shuffleHand(Hand*) in a4.c:
Right now, the computer (Player 1) is only playing the first card in the hand. Implement shuffleHand(), which will random a hand of cards. The computer will then play a random card.

Reflection question: You implementedshuffle() on the Deck, which is a Stack. How is this similar or different from how you can shuffle a Hand, which is a LinkedList?

Challenge 2: Sort a hand in terms of value
Difficulty: Medium

Implement void sortHand(Hand*, Suit) in a4.c:
A nice feature would be to print out the hand for the user (Player 2) in descending order of value. Given a Hand and a suit for trump, sort the hand so that it is in decreasing value, with cards of the trump suit first, then all other suits.

Challenge 3: Replace Deck using a LinkedList
Difficulty: Medium

In this quiz, you implemented both a linked list (Hand) and a stack (Deck). Create a new deck.c file (call it deck_2.c), and re-implement Deck. This time, instead of using an array to back the Deck, use a linked list. You can re-use the CardNode used in the Hand implementation. To test and use your implementation of deck_2.c, modify the Makefile by replacing deck.c with deck_2.c. Note, some of the tests for Deck will fail because they are checking your array implementation.

Challenge 4: Be smarter about calling trump
Difficulty: Hard

Right now, trump is decided randomly. In original Euchre, the process for calling trump requires the dealer and the other player to take turns having the opportunity to call trump in a structured way.

The process is like this:

  1. After the deal, show the top card in the deck.
  2. The player that is not the dealer looks at that card and decides if they want that suit for trump.
    1. If the player wants the trump, they "order it up".
    2. The dealer adds that top card to their hand.
    3. The dealer discards one card.
    4. Play begins.
  3. If the player does not want the top card for trump, the dealer gets to decide. If the deal wants that card, the process is the same as above (dealer picks up the card, and discards another card).
  4. If the deal does not want the top card suit for trump, the top card is turned over.
  5. The player gets to "call trump" or choose a suit.
  6. If the player declines to call trump, the dealer must call trump.
For this challenge, modify the getTrump(Card*) function in a4_run.c to use this process. Look at the other functions for examples of how to get input from the user.

Challenge 5: Give the computer player strategy
Difficulty: Hard

getBestMove():
Given a hand of cards, the card that was just led, and the current trump, pick the best card in the hand to play. Note: there might be some strategy in this one!

Submit your code to git by pushing

  • When you're all done and ready to submit your code, tag your repo: git tag 'a4-final', then git push origin a4-final to push the final tag to the repo so we can see it.
  • Milestone 1 deliverables: Due 5 June 2019, 6pm

    Milestone 2 deliverables: Due 12 Jun 2019, 6pm

    Hopefully Helpful Tips

    This time we're giving you a more substantial test file.

    Submission Details

    In general, you should only need to modify a4.c and deck.c. You may modify a4_test.c to write your own tests, but be aware that we will not necessarily use your test file to test your code. If you do some of the challenges, you may be changing a4_helper.c or a4.run

    You may also modify your Makefile for your dev process; once again, don't assume we will use your Makefile to test or run your code.

    Notes on submitting Part 1 versus Part 2:

    Helpful Hints