After playing hours of Vietnamese Cards in our dorm, we decided to try and translate the card game we loved so much, into the code that we also loved so much, for a project in an intro to C programming class.
For this project we had to implement many functions therefore it was important to keep the code organized in the case there was something wrong it would be easy to locate the bug and deal with it. To stay organized we followed the format of the matrix library we created in lab by creating an API with the prototypes of all the functions we created and what variables need to be passed into those functions, we then have a main where the functions are all called.
After main we have our implementation section of the code. Each function is broken up by a commented spacer telling us what the function is and what it does just to stay organized. In order to stay as organized as possible, main is almost all function calls so if something goes wrong with the code we can comment out certain functions to make sure the bulk of the code is working and it was only the function we were currently working on that had the bugs.
In main we included command line arguments that the user can type in when running the program one of these command line arguments is “-r” which displays the rules of the game in case the user is unfamiliar, at first we were just going to type the rules into a printf then realized that there were too many rules and would mess up our formatting and organization so we went online and learned how to open a text file, read the text file, print it to the terminal, and close the text file making it much easier to format the rules and making our code look cleaner.
In the card game that we are creating it is extremely helpful to sort cards from lowest to highest in your hand in order to see what cards can be played easier than if they were just random, to deal with this we had to create a function called sortcards. In this function we ran into many issues because of the way we created the cards in a player's hand the code actually stores two arrays one with the number of the suits and one with the number of the card so we had to figure out how to keep the two arrays together when we were sorting them it first looks through the hand that it was given and first sets the minimum card to be the very first card in the hand and then goes through the hand and and looks for cards lower than the first card in the hand and then sets that card as the first element in a new hand array.
Our plans for the final version of the project will include several more functions where we read the string of cards that the user types in and makes sure that the user has those cards and if those cards played can beat the cards that were played in the previous turn. After all of the functions are all working we will then worry about the formatting of the actual gameplay. In the gameplay there will need to be several things displayed such as the current players hand, the previous play, and how many cards all the rest of the players have but the current player should not be able to see the hands of the other players. We also plan on taking many of our card handling functions and creating a card library so that not all of our code is in one file.
For the final submission of this project we made the code into a library creating a header file called, cardgame.h, and an implementation file called, cardgame.c along with a makefile. After the checkpoint we fixed many bugs that we had seen come up for example, there was a bug that the user could type in any string of numbers and letters and the code would accept it as a play and place it in the previous play array, we fixed this bug by making it so that the specific places in the character array that is read through standard input has to be one of the values we defined a card to be otherwise it would make the player take their turn again.
To run this program all that needs to be done is type in ./tienlen or possibly ./tienlen -r if the user wants to read the rules first. Once ./tienlen is entered the program creates a deck, shuffles the deck, and deals the deck out to four players, then sorts the deck from their lowest card to their highest card, then the game begins with the player who has the 3 of spades in their hand getting printed to the terminal below an empty previous play array, this player is always the player who gets the first turn because in the rules of the game the 3 of spades, which is the lowest card in the game, must play first. In order to implement this we had to write in gameplay a check where we look at the first card of every players hand and the player who has the 3 of spades gets the first turn of the game meaning their hand will be printed first, then this player must play the 3 of spades which we ensured by writing a case in the function playcompare where there is a counter counting the number of plays that have been made so when the counter is equal to one signifying the first play of the game there is a statement saying that one of the cards played has to be 3S or the 3 of spades. From there the gameplay continues printing the current players hand with blanks where the cards he has already played were and a previous play array with the cards the previous player played until one of the players can no longer beat the previous play when they must enter “pass” which sets a boolean variable to 1 which in turn makes it so that the player cannot play again until another player gets a reset. Resets occurs if all other players but one have their hasPassed boolean variable set to 1 then the player who has their boolean variable at 0 then can play whatever card or cards they wish and then all boolean variables are set to 0 until “pass” is typed by a player. The game is over when one of the four player runs out of cards in which case the program prints “PLAYER ‘players number’ WINS!!!” and the game is over.
In this game a player can play one of a kind, two of a kind, three of a kind, a run of any number of cards greater than three, four of a kind, or a run of pairs greater than three however whatever the player plays must be in the same format as the play before them of higher cards or suits. For example, if a player plays 3S 3H (3 of spades and the 3 of hearts) as a pair the next player can only play a higher pair. This created an extra challenge of making sure that the next player plays only a higher pair from their hand. We implemented this by creating several functions, playcompare, gameplay, inHand, typeofplay. inHand checks to make sure that the cards played were in the current players deck, typeofplay returns the type of play that was played previously such as returning 2 for a pair then typeofplay is passed again with the current play and returns what type of play it was then if both returns are the same it is a valid play if they aren’t the current player is told to play again with the same type of play, playcompare checks to make sure the current play is higher than the previous play. All of these functions are called in the function gameplay.
Another difficulty we ran into was creating the makefile to compile our program after we had separated main, implementation, and the API. We ended up having to google a lot of different ways to write a makefile and looking at previous makefiles that we had downloaded with homeworks. After a couple of hours of getting error after error with trying to compile our program and having to make some adjustments of what is in main and what is in the gameplay function we finally got it to compile only to realize that in the process of getting the makefile to compile without errors the gameplay function started to not run the game right. In order to fix this we had to dive back into the gameplay function to make the game run correctly again we had to almost go back to the drawing board on how the game ran. The gameplay function broke because we had to move something that was in our main into the gameplay function changing the formatting and the calls of main and of gameplay, if we didn’t do this compiling with make -k resulted in a multitude of errors for reasons we can’t explain.
The main lessons we learned when writing this code was having to think of every possible scenario that a user might input. At one point we thought we had finished the program because everything was in working order, the standard input and play compare was working just as we expected it would but then we bumped the keyboard and accidently typed in a random string of numbers, curious to see what would happen we pressed enter which resulted in a long string of random numbers and letters being printed into the previous play and the next player being printed in the terminal meaning that the program saw this as a valid play and moved to the next turn. We realized that we had not thought about cases where the player playing the game didn't know what to put in, after this accident we tried putting in cards that weren’t in our hand, cards that didn't beat the previous play, and other random strings. After this we had to take the mindset of programing as if we didn't know how to play the game and making check cases for every little senario. We also learned that we should have been thinking several steps ahead, as described above we had real trouble with our makefile and moving our code into different files that most likely could have been avoided if we had started by making our program into different files in the first place instead of making it all in one file and then moving it.
We tested this program through play testing among our friends and using their input to find bugs in our program.
Comments