/
card_deck.c
239 lines (188 loc) · 5.74 KB
/
card_deck.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
* Author: Akhil Bagaria
* Email: abagaria@hmc.edu
* Date: Nov 18th, 2015
* Description: C file implementing a data structure for card decks
* answering the question of how long it takes to restore a deck to its
* original configuration.
*/
#include "card_deck.h"
#include <stdlib.h>
/*
* This function takes in the number of cards and returns a pointer
* to the head and tail of the stack of cards.
*/
deck_t *make_deck(int num_cards) {
// hand deck of n cards
deck_t *deck = (deck_t *)malloc(sizeof(deck_t));
deck->num_cards = num_cards;
deck->top = NULL;
deck->bottom = NULL;
// make deck in hand
int i;
for (i = 0; i < num_cards; ++i) {
card_t *card = (card_t *)malloc(sizeof(card_t));
// assign unique identity to the card
card->identity = i;
// make the new card the top of the stack
card->next = deck->top;
// update the top of the deck
deck->top = card;
// make the bottom card the bottom of the stack
if (i == 0) {
deck->bottom = card;
card->next = NULL;
}
}
return deck;
}
/*
* Given a hand deck and a table deck, move the top of the hand deck
* to the top of the table deck
*/
void move_to_top(deck_t *handdeck, deck_t *tabledeck) {
// if hand deck is empty, there is nothing to move
if (handdeck->top == NULL) {
printf("move_to_top called on an empty deck\n");
return;
}
// If hand deck only has one card remaning, then we need to make its
// bottom to nullptr. We thus need a flag to track if thats true
int bottom_flag = 0;
if (handdeck->top->identity == handdeck->bottom->identity) {
bottom_flag = 1;
}
// store the 2nd card in a tmp var
card_t *new_head = handdeck->top->next;
// make the top of the hand deck point at the current top of the
// table deck as the its next card
handdeck->top->next = tabledeck->top;
// update the table deck's head
tabledeck->top = handdeck->top;
// update the hand deck's top
handdeck->top = new_head;
// if table deck only has one card, then set its bottom
if (tabledeck->bottom == NULL) {
tabledeck->bottom = tabledeck->top;
}
if (bottom_flag) {
handdeck->bottom = NULL;
}
return;
}
/*
* Given a pointer to the deck, move the top card to the bottom.
* In the process, update the top and bottom of the deck.
*/
void move_to_bottom(deck_t *handdeck) {
// if no card, then return
if (handdeck->top == NULL) {
return;
}
// if only one card in the deck, move_to_bottom is already done
if (handdeck->top->next == NULL) {
return;
}
// update bottom card's next from nullptr to top (the new bottom)
handdeck->bottom->next = handdeck->top;
// update the top and the bottom of the deck
handdeck->bottom = handdeck->top;
handdeck->top = handdeck->top->next;
// update the new bottom card's next to be a nullptr instead of pointing to
// the 2nd card in the deck
handdeck->bottom->next = NULL;
}
/*
* Given two decks, return if they are the equal by looking at their
* respective card identities.
*/
int is_equal(deck_t *tabledeck) {
if (tabledeck->top == NULL) {
return -1;
}
card_t *current = tabledeck->top;
int card_number = tabledeck->num_cards - 1;
while (current->next != NULL) {
if (current->identity != card_number) {
return 0;
}
--card_number;
current = current->next;
}
return 1;
}
/*
* A round is defined as playing to top and then to bottom until there are no
* more cards in the hand deck.
*/
void play_round(deck_t *handdeck, deck_t *tabledeck) {
while (handdeck->top != NULL) {
move_to_top(handdeck, tabledeck);
move_to_bottom(handdeck);
}
}
/*
* Print function for a deck. Iterate through the cards
* in the deck, and print the identity of the cards to stdout
*/
void print(deck_t *deck) {
card_t *current = deck->top;
if (current == NULL)
return;
printf("%d ->", current->identity);
while (current->next != NULL) {
current = current->next;
printf(" %d ->", current->identity);
}
printf("\n");
return;
}
/*
* Print function for a card so that top and bottom can easily be printed.
*/
void print_card(card_t *card) {
if (card == NULL) {
return;
}
printf("%d\n", card->identity);
return;
}
int main(int argc, char *argv[]) {
// exit the program if the user didn't give an input arg for num cards
if (argc != 2) {
printf("Enter 1 argument to initialize the number of cards in deck\n");
exit(1);
}
char *num = argv[1];
int num_cards = atoi(num);
// make new deck and print it
deck_t* handdeck = make_deck(num_cards);
// initialize empty table deck
deck_t *tabledeck = (deck_t *)malloc(sizeof(deck_t));
tabledeck->num_cards = num_cards;
tabledeck->top = NULL;
tabledeck->bottom = NULL;
// play the game
int num_rounds = 0;
while (1) {
play_round(handdeck, tabledeck);
// hand deck will get table deck as hand deck should be null after
// a round has been played
handdeck->top = tabledeck->top;
handdeck->bottom = tabledeck->bottom;
// table deck is an empty deck again
tabledeck->top = NULL;
tabledeck->bottom = NULL;
++num_rounds;
if (is_equal(handdeck)) {
break;
}
}
printf("Final card stack = ");
print(handdeck);
printf("Number of rounds played = %d\n", num_rounds);
// free all the space in the heap used by the program
free(handdeck);
free(tabledeck);
return 1;
}