Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matt Haefling #405

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
103 changes: 101 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,102 @@
## War or Peace
# War or Peace

This is the starter repo for the BE Mod1 **War or Peace** project.
## About:
- War or Peace is a card game with two players with a deck of 52 cards being split between both players.
- Each player has 26 cards in their deck to start.
- Aces are considered high.
- The player that runs out of cards first loses.

## War or Peace has three different types of turns:

### Basic
- Each player draws a card.
- If both players draw a card that do not match ranks.
- Example:

| Player | Suit | Value | Rank |
| ----------- | ----------- | :---------: | :---------: |
| Player1 | Spade | 2 | 2 |
| **Player2** | Diamond | 8 | 8 |

- The player with the highest ranked card will win the turn. (**Player2**)
- The winner of the turn gets to keep both cards. (**2 Cards**)

### War
- Each player draws a card.
- If both players draw a card that have the same rank, each player will draw a second card and leave it face down.
- Each player will draw a third card.
- If both players draw a card that do not match ranks.
- Example:

| Player | Suit | Value | Rank |
| ----------- | ----------- | :---------: | :---------: |
| Player1 | Club | 9 | 9 |
| Player2 | Heart | 9 | 9 |
| Player1 | * | * | * |
| Player2 | * | * | * |
| **Player1** | Spade | King | 13 |
| Player2 | Club | 8 | 8 |

- The player with the highest ranked card on the third draw will win the turn. (**Player1**)
- The winner of the turn gets to keep all six cards. (**6 Cards**)

### Mutually Assured Destruction
- Each player draws a card.
- If both players draw a card that have the same rank, each player will draw a second card and leave it face down.
- Each player will draw a third card.
- If both players draw a card that have the same rank again, all 6 cards are removed from play.
- Example:

| Player | Suit | Value | Rank |
| ----------- | ----------- | :---------: | :---------: |
| Player1 | Spade | 2 | 2 |
| Player2 | Diamond | 2 | 2 |
| Player1 | * | * | * |
| Player2 | * | * | * |
| Player1 | Heart | King | 13 |
| Player2 | Club | King | 13 |

- Both players have lost this round.
- A total of (**6 Cards**) will be removed from the game.

## Built With:
- Ruby Version 3.2.2
- Rspec Version 3.13

## Getting Started

- Start by cloning this repository to your computer to make a local copy.
- From the repository in github, click the `<> Code` drop down menu and select the `Local` tab, then click the `SSH` tab, then copy your SSH key.
- From your terminal, navigate to the local directory you would like to download the project to.
- Enter: `git clone <your ssh key>`
- Change directories into the project directory `cd war_or_peace_project1`
- Then run the "war_of_peace_runner.rb" file by entering: `ruby war_of_peace_runner.rb`
- Type: `GO` and hit enter

## Testing

- To test each class in the game, navigate into the `war_or_peace_project1` directory
- To test each class enter `rspec ./spec/<class_name_spec.rb>`
- Tests are organized per class, starting from the ground up.
- In this order: `card`, `deck`, `player`, `turn`, `game`.
- Please note that each type of turn has its own test file: `turn_type_basic`, `turn_type_war`, `turn_type_mutual_assured_destruction`.

### Test Summary
- Each class test starts by confirming the instance of the class is indeed the correct class type.
- Each test will then test the initial setup of the objects instance.
- Classes that have functional methods will then test each functional method from top to bottom the confirm expected outputs.

## Challenges & Wins

- This was my first project built in Ruby, after 1 week of being in class at Turing school of Software and Design. Throughout this project I have learned clean code etiquette with correct indentation, building classes, and methods, and writing rspec test files.

- I made the mistake of writing the first few classes of this project prior to writing tests for them. I also have a edge case situation in my project that I wasn't able to solve in time where if a player starts a round with less than 3 cards in their deck the program will error as its unable to find the rank of the card at index 2 as the card doesn't exist.

- I went back and wrote detailed test files for each class confirming that everything passed prior to creating my game class.

- All projects moving forward, I will not write code prior to writing out rspec test files to determine first what my expected outputs should be.

## Authors

- Date: 15-OCT-2024
- Matt Haefling [Github Profile](https://github.com/mhaefling)
16 changes: 16 additions & 0 deletions lib/card.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Defining Card class to hold the attributes/values of each card.

class Card
attr_reader :suit,
:value,
:rank

def initialize(suit, value, rank)
# Each card has suit
@suit = suit
# Each card has a value
@value = value
# Each card has a rank
@rank = rank
end
end
40 changes: 40 additions & 0 deletions lib/deck.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require './lib/card'

# Defining Deck class to hold each players deck of cards

class Deck
attr_reader :cards

def initialize(cards)
# Each deck holds an array of cards
@cards = cards
end

# Return the rank of the card at the given index value
def rank_of_card_at(index)
@cards[index].rank
end

# Return an array of all the cards with a rank that is greater than or equal to 11
def high_ranking_cards
@cards.select do |card|
card.rank >=11
end
end

# Return a float providing the percent of high ranked cards in the players deck
def percent_high_ranking
percent_high_rank = high_ranking_cards.count.to_f / cards.count.to_f * 100
percent_high_rank.round(2)
end

# Removes a card from the players deck at index 0
def remove_card
@cards.shift
end

# Addes a card to the players deck at the highest index
def add_card(card)
@cards.append(card)
end
end
46 changes: 46 additions & 0 deletions lib/game.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require './lib/card'
require './lib/deck'
require './lib/player'
require './lib/turn'

class Game
attr_reader :player1,
:player2,
:turn

def initialize(player1, player2)
@player1 = player1
@player2 = player2
@turn = Turn.new(player1, player2)
@round = 0
end

def start
until @player1.has_lost? == true || @player2.has_lost? == true || @round == 1000001 do
@round +=1
turn_type = @turn.type
winner = @turn.winner
@turn.pile_cards
if @round == 1000001
p "---- DRAW ----"

elsif @turn.spoils_of_war.count == 0
p "Turn #{@round}: *#{turn_type}* - 6 cards removed from play"

elsif @turn.spoils_of_war.count == 2
p "Turn #{@round}: :#{turn_type} - #{winner.name} won 2 cards."
@turn.award_spoils(winner)

elsif @turn.spoils_of_war.count == 6
p "Turn #{@round}: :#{turn_type} - #{winner.name} won 6 cards."
@turn.award_spoils(winner)
end
end

if @player1.has_lost? == true
p "*~*~*~* #{@player2.name} has won the game! *~*~*~*"
elsif @player2.has_lost? == true
p "*~*~*~* #{@player1.name} has won the game! *~*~*~*"
end
end
end
21 changes: 21 additions & 0 deletions lib/player.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require './lib/card'
require './lib/deck'

# Defining Player class to hold all players attributes/values.

class Player
attr_reader :name,
:deck

def initialize(name, deck)
# Each player has a name.
@name = name
# Each player has a deck of cards.
@deck = deck
end

# Returns if player has lost by checking if they have ran out of cards in their deck
def has_lost?
deck.cards.empty?
end
end
91 changes: 91 additions & 0 deletions lib/turn.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
require './lib/card'
require './lib/deck'
require './lib/player'

# Defining Turn class to check the type of turn, the winner of the turn, compare and re-arrange cards

class Turn
attr_reader :player1,
:player2,
:spoils_of_war

def initialize(player1, player2)
# player1 variable holds player1's attributes, name, deck, cards
@player1 = player1
# player2 variable holds player1's attributes, name, deck, cards
@player2 = player2
# spoils_of_war array starts empty as cards get added to it during each turn
@spoils_of_war = []
end

# Returns the type of turn based on users card ranks
def type

# Compares both players cards at index 0 and index 2 to determine if they're both the same rank if true turn type is mutual assured destruction
if @player1.deck.rank_of_card_at(0) == @player2.deck.rank_of_card_at(0) && @player1.deck.rank_of_card_at(2) == @player2.deck.rank_of_card_at(2)
@type = :mutually_assured_destruction

# Compares both players cards at index 0 to determine if they're both the same rank if true turn type is war
elsif @player1.deck.rank_of_card_at(0) == @player2.deck.rank_of_card_at(0) && @player1.deck.rank_of_card_at(2) != @player2.deck.rank_of_card_at(2)
@type = :war

# Compares both players cards at index 0 to determine if they're NOT the same rank if true turn type is basic
elsif @player1.deck.rank_of_card_at(0) != @player2.deck.rank_of_card_at(0)
@type = :basic
end
end

# Returns who the winner of each turn is
def winner
if @type == :basic && @player1.deck.rank_of_card_at(0) > @player2.deck.rank_of_card_at(0)
@player1

elsif @type == :basic && @player1.deck.rank_of_card_at(0) < @player2.deck.rank_of_card_at(0)
@player2

elsif @type == :war && @player1.deck.rank_of_card_at(2) > @player2.deck.rank_of_card_at(2)
@player1

elsif @type == :war && @player1.deck.rank_of_card_at(2) < @player2.deck.rank_of_card_at(2)
@player2

elsif @type == :mutually_assured_destruction
"No Winner"
end
end

# Submits all players cards to the spoils of war array and removes the cards from the players decks
def pile_cards
if @type == :basic
@spoils_of_war << @player1.deck.remove_card
@spoils_of_war << @player2.deck.remove_card

elsif @type == :war
3.times do
@spoils_of_war << @player1.deck.remove_card
end
3.times do
@spoils_of_war << @player2.deck.remove_card
end

elsif @type == :mutually_assured_destruction
3.times do
@player1.deck.remove_card
end
3.times do
@player2.deck.remove_card
end
end
end

# Moves all the cards from the spoils of war array into the winners deck, and clears the spoils of war aray for the next round.
def award_spoils(player)
# @spoils_of_war.shuffle!
if player == "No Winner"
@spoils_of_war.clear
else
player.deck.cards.concat(@spoils_of_war)
@spoils_of_war.clear
end
end
end
23 changes: 12 additions & 11 deletions spec/card_spec.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
require 'rspec'
require './lib/card'

RSpec.describe Card do
it "exists" do
card = Card.new(:diamond, 'Queen', 12)
describe Card do
describe '#initialize' do

expect(card).to be_an_instance_of(Card)
end

it "has readable attributes" do
card = Card.new(:diamond, 'Queen', 12)
it "card is an instance of card" do
card = Card.new(:heart, 'Jack', 11)
expect(card).to be_an_instance_of(Card)
end

expect(card.suit).to eq(:diamond)
expect(card.value).to eq('Queen')
expect(card.rank).to eq(12)
it "has a suit, value, rank" do
card = Card.new(:heart, 'Jack', 11)
expect(card.suit).to eq(:heart)
expect(card.value).to eq('Jack')
expect(card.rank).to eq(11)
end
end
end
Loading