ASSIGNMENT NO 01
DATA STRUCTURES
SUBMITTED BY: AYESHA NOOR
REG NO: SP24-BCS-027
SECTION: B
SUBMITTED TO: MAM HUMERA
NIAZ
Problem Statement:
Create a simple card game where players build a "tower" of cards using
stack data structures. The goal is to simulate placing and removing
cards based on specific rules, utilizing stack operations.
Solution:
#include <iostream>
#include <ctime>
#include <limits>
#define MAX_STACK_SIZE 5
#define MAX_ATTEMPTS 10
using namespace std;
class Stack {
private:
int cards[MAX_STACK_SIZE];
int top;
public:
Stack() { top = -1; }
bool isFull() { return top == MAX_STACK_SIZE - 1; }
bool isEmpty() { return top == -1; }
void push(int value) {
if (isFull()) {
cout << "Stack is full! Cannot push more
cards.\n";
return;
}
cards[++top] = value;
}
int pop() {
if (isEmpty()) {
cout << "Stack is empty! Cannot pop.\n";
return -1;
}
return cards[top--];
}
int peek() {
if (isEmpty()) return -1;
return cards[top];
}
void display() {
if (isEmpty()) {
cout << "[Empty Stack]\n";
return;
}
cout << "Current Stack: ";
for (int i = 0; i <= top; i++)
cout << cards[i] << " ";
cout << "\n";
}
int size() { return top + 1; }
};
int generateCard() {
return rand() % 13 + 1;
}
int main() {
srand(time(0));
Stack tower;
int attempts = 0, score = 0;
cout << " Welcome to the Card Tower Game! \n";
cout << "You must stack 5 cards in a maximum of 10
attempts.\n";
while (attempts < MAX_ATTEMPTS) {
int newCard = generateCard();
cout << "\nAttempt " << (attempts + 1) << ":
You got card [" << newCard << "]\n";
int topCard = [Link]();
if ([Link]() || newCard > topCard) {
cout << "You can push this card onto the
stack.\n";
cout << "\tPress 1 to Push\t2 to Discard:
";
int choice;
cin >> choice;
if (choice == 1) {
[Link](newCard);
score += 2;
cout << "Card [" << newCard << "] added
to the stack!\n";
} else if (choice == 2) {
cout << "Card [" << newCard << "]
discarded.\n";
} else {
cout << "Invalid input! Skipping this
attempt.\n";
}
} else {
cout << "This card is lower than the top
card [" << topCard << "].\n";
cout << "Press 1 to Pop top card(s) and
push new one,\n"
<< " 2 to Discard new card: ";
int choice;
cin >> choice;
if (choice == 1) {
while (![Link]() && [Link]()
> newCard) {
cout << "Popping top card [" <<
[Link]() << "] as it's greater than [" << newCard
<< "]\n";
[Link]();
score -= 1;
}
[Link](newCard);
score += 2;
cout << "Card [" << newCard << "] added
to the stack.\n";
} else if (choice == 2) {
cout << "Card [" << newCard << "]
discarded.\n";
} else {
cout << "Invalid input! Skipping this
attempt.\n";
}
}
[Link]();
attempts++;
if ([Link]() == MAX_STACK_SIZE) {
cout << "\nCongratulations! You have
successfully built the tower!\n";
break;
}
}
cout << " Game Over! \n";
cout << "Final Score: " << score << " points\n";
cout << "Final Stack: ";
[Link]();
if ([Link]() == MAX_STACK_SIZE) {
cout << "You Win!\n";
} else {
cout << "You Lose! Could not complete the tower
in 10 attempts.\n";
}
return 0;
}
Brief Report on Stack Operations Used in the Game
1. Stack Operations Used
The game is implemented using a stack, which follows the Last In, First Out
(LIFO) principle. The key stack operations used are:
1. Push (Inserting a Card)
o If the stack is not full and the new card is greater than or equal to
the top card, it is pushed onto the stack.
o Method Used: push(int value)
o Relation to Game: Ensures that cards are placed in increasing order,
forming a valid tower.
2. Pop (Removing the Top Card)
o If the new card is smaller than the top card, the player can choose to
pop the top card.
o Method Used: pop()
o Relation to Game: Allows the player to replace lower-value cards
with better ones but at the cost of losing 1 point.
3. Peek (Checking the Top Card)
o Used to check the current top card without modifying the stack.
o Method Used: peek()
o Relation to Game: Helps determine whether a new card can be added
or if the player needs to pop the top card first.
4. IsEmpty (Checking if Stack is Empty)
o Determines if the stack has no cards.
o Method Used: isEmpty()
o Relation to Game: Used before checking or popping to avoid errors
when the stack is empty.
5. IsFull (Checking if Stack is Full)
o Determines if the stack has reached its maximum capacity (5 cards).
o Method Used: isFull()
o Relation to Game: Ends the game early if the stack is successfully
completed before reaching 10 attempts.
6. Display (Showing Stack Contents)
o Prints the current stack elements to the console.
o Method Used: display()
o Relation to Game: Provides a visual representation of progress,
helping players make decisions.
2. How Stack Operations Relate to the Game
The stack-based implementation of the Card Tower Game creates a structured
way of playing:
The player must carefully choose when to push, pop, or discard cards.
The LIFO nature of stacks means that removing a card only affects the
most recent one, making strategic decision-making crucial.
The game rewards careful planning (pushing higher cards) and penalizes
mistakes (losing points when popping).
TEST CASES :
Test Case 1: Winning the Game (Stacking 5 Cards Successfully)
Input: Player keeps pushing valid cards until the stack reaches 5.
Expected Output: "Congratulations! You have successfully built the
tower!"
o Final Score > 0
o Stack contains 5 cards.
Test Case 2: Losing the Game (Failing to Stack 5 Cards in 10 Attempts)
Input: Player discards too many cards or fails to push valid ones.
Expected Output: "You Lose! Could not complete the tower in 10
attempts."
o Final Score might be low or negative.
o Stack contains fewer than 5 cards.
3. Randomization & Boundary Cases
Test Case 7: All Random Cards are in Increasing Order
Input: Random number generator provides increasing cards.
Expected Output: Player wins easily by stacking without popping.
Test Case 8: All Random Cards are in Decreasing Order
Input: Random numbers are strictly decreasing.
Expected Output: Player will have to pop frequently, making it harder to
win.
Test Case 9: Getting the Same Card Multiple Times
Input: A card appears multiple times in different attempts.
Expected Output: Handling repeated numbers properly.
Test Case 10: Only Low-Value Cards Appear
Input: Random numbers are between 1 and 5.
Expected Output: Likely a loss due to frequent discarding.
Test Case 13: Maximum Possible Score
Input: Pushes valid cards without popping.
Expected Output: Score is maximum.
Test Case 14: Minimum Possible Score
Input: Pops multiple times and discards too much.
Expected Output: Score is negative or very low.
SAMPLE WORKING