Reputation: 2885
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
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