J. Munson
J. Munson

Reputation: 2885

Why are cards being lost in Javascript ES6 "Game of War"?

To gain a better understanding of Javascript ES6 and object oriented programming in general, I decided to try writing a simple Game of War.

At first glance, the game seems to run fine... it always returns the name of the winning player, and because it is a game of chance it seems to return any given player about 50% of the time.

However, upon closer inspection it appears that something is terribly wrong. The issue is that upon each successive turn, the total number of cards in the game is decreasing rather than staying at a constant 52.

The game utilizes five different classes, all listed below, and a war.js file that instantiates a game and logs the winner.

The source files may be found at: https://github.com/johncmunson/war

Run the game with node war.js

Card.js

class Card {
    constructor(rank, suit) {
        this.rank = rank
        this.suit = suit
    }
}

module.exports = Card

Deck.js

const Card = require('./Card.js')

class Deck {
    constructor() {
        const suits = [1, 2, 3, 4]
        const ranks = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
        this.cards = ranks.map(
            rank => suits.map(
                suit => new Card(rank, suit)
            )
        ).reduce(
            (cum, cur) => cum.concat(cur),
            []
        )
    }

    shuffle() {
        let currentIndex = this.cards.length
        let tempValue, randomIndex
        while (0 !== currentIndex) {
            randomIndex = Math.floor(Math.random() * currentIndex)
            currentIndex -= 1
            tempValue = this.cards[currentIndex]
            this.cards[currentIndex] = this.cards[randomIndex]
            this.cards[randomIndex] = tempValue
        }
    }

    deal(players) {
        let currentIndex = 0
        while (this.cards.length) {
            let dealtCard = this.cards.pop()
            players[currentIndex].receiveCard(dealtCard)
            if (currentIndex === players.length - 1) {
                currentIndex = 0
            } else {
                currentIndex += 1
            }
        }
    }
}

module.exports = Deck

Player.js

class Player {
    constructor(name) {
        this.name = name
        this.cards = []
        this.battleCard = null
    }

    playCard() {
        this.battleCard = this.cards.shift()
    }

    receiveCard(card) {
        this.cards.push(card)
    }

    winBattle(battleCard, potCards) {
        this.cards.push(battleCard)
        if (potCards.length) {
            for (let card of potCards) {
                this.cards.push(card)
            }
        }
    }

    tie(pot) {
        let burnCards = this.cards.length <= 3 ?
            this.cards.splice(0, this.cards.length) :
            this.cards.splice(0, 3)
        pot.receiveBurnCards(burnCards)
        pot.receiveBattleCard(this.battleCard)
    }
}

module.exports = Player

Pot.js

class Pot {
    constructor() {
        this.cards = []
    }

    receiveBattleCard(card) {
        this.cards.push(card)
    }

    receiveBurnCards(burnCards) {
        for (let card of burnCards) {
            this.cards.push(card)
        }
    }

    reset() {
        this.cards = []
    }
}

module.exports = Pot

Game.js

const Card = require('./Card.js')
const Deck = require('./Deck.js')
const Player = require('./Player.js')
const Pot = require('./Pot.js')

class Game {
    constructor(player1, player2, numberRounds) {
        this.player1 = new Player(player1)
        this.player2 = new Player(player2)
        this.rounds = numberRounds
        this.deck = new Deck()
        this.pot = new Pot()
    }

    _compare(card1, card2) {
        const rank1 = card1.rank === 1 ? 14 : card1.rank
        const rank2 = card2.rank === 1 ? 14 : card2.rank
        return rank2 - rank1
    }

    _battle() {
        this.player1.playCard()
        this.player2.playCard()
        const result = this._compare(this.player1.battleCard,                                         
        this.player2.battleCard)
        if (result < 0) {
            this.player1.winBattle(this.player2.battleCard, this.pot.cards)
            this.pot.reset()
        } else if (result > 0) {
            this.player2.winBattle(this.player1.battleCard, this.pot.cards)
            this.pot.reset()
        } else {
            this.player1.tie(this.pot)
            this.player2.tie(this.pot)
        }
    }

    _getWinner() {
        if (this.player1.cards.length > this.player2.cards.length) {
            return this.player1.name
        } else if (this.player1.cards.length < this.player2.cards.length) {
            return this.player2.name
        } else {
            return 'Tie!'
        }
    }

    play() {
        this.deck.shuffle()
        this.deck.deal([this.player1, this.player2])
        if (this.rounds) {
            while (this.rounds !== 0) {
                this._battle()
                this.rounds -= 1
                console.log('Number of Cards: ', this.pot.cards.length + this.player1.cards.length + this.player2.cards.length)
            }
        } else {
            while (this.player1.cards.length && this.player2.cards.length) {
                this._battle()
                console.log('Number of Cards: ', this.pot.cards.length + this.player1.cards.length + this.player2.cards.length)
            }
        }
        return this._getWinner()
    }
}

module.exports = Game

war.js

const Game = require('./Game.js')
const war = new Game('George', 'Abe')
console.log(war.play())

CONSOLE OUTPUT

Number of Cards:  52
Number of Cards:  51
Number of Cards:  50
Number of Cards:  49
Number of Cards:  48
Number of Cards:  47
Number of Cards:  47
Number of Cards:  46
Number of Cards:  45
Number of Cards:  45
Number of Cards:  44
Number of Cards:  43
Number of Cards:  42
Number of Cards:  41
Number of Cards:  40
Number of Cards:  39
Number of Cards:  38
Number of Cards:  37
Number of Cards:  36
Number of Cards:  35
Number of Cards:  34
Number of Cards:  33
Number of Cards:  32
Number of Cards:  31
Number of Cards:  30
Number of Cards:  29
Number of Cards:  28
Number of Cards:  27
Number of Cards:  26
Number of Cards:  25
Number of Cards:  24
Number of Cards:  23
Number of Cards:  22
Number of Cards:  21
Number of Cards:  20
Number of Cards:  19
Number of Cards:  18
George

Upvotes: 2

Views: 175

Answers (1)

Barak
Barak

Reputation: 1148

thats because the winner should also keep his own card.

on Player.js you should add

 winBattle(battleCard, potCards) {
    this.cards.push(this.battleCard) // this one
    this.cards.push(battleCard)
    if (potCards.length) {
        for (let card of potCards) {
            this.cards.push(card)
        }
    }
}

Upvotes: 1

Related Questions