[ Content | View menu ]

What’s in a game?

Written on May 20, 2008

Ever heard of the card game, ‘War’?

A deck of cards is evenly split between two players. The players compare the top cards from their respective piles. Comparison is performed by rank alone; suit is irrelevant. The player with the higher ranking card collects both cards and places them at the bottom of their pile. In the event that both cards have equal rank (a “War” situation), both players set aside three cards from their piles, and compare the new top card of their piles. The winner of this second comparison collects the other card, as well as all the cards laid aside, and the cards from the orignal comparison. Should the cards in the second comparison be equal, an additional three cards from each player’s pile are set aside, and another comparison is made, etc. etc.

In the event that a comparison causes one player’s pile to run out of cards, they lose the game.

According to some house rules, if a player has insufficient cards to lay aside for a “War” and its ensuing secondary comparison, they take the required cards from the other player’s pile.

It’s kind of a stupid game. Arguably it’s not a game at all. The winner and loser are determined entirely by the deal of the cards. No decision-making takes place; players cannot alter the outcome of the game in any fashion. Play amounts to a revelation of who was dealt the winning pile; nothing more. My (admittedly verbose) implementation comes in at a little under 100 lines of code and there’s one special case it doesn’t handle.

War has always fascinated me. Since players’ actions don’t affect the outcome, it’s not really a game as we understand games. But the social experience of it is very much a game; ask any kid and he’ll tell you.

Version 1

class WarGame
  attr_accessor :log_file 

  def initialize(deck_size = 52, suit_count = 4)
    @deck_size = deck_size
    @suit_count = suit_count
    @rank = @deck_size / @suit_count
    @deck = nil
    @p1_deck = nil
    @p2_deck = nil
    @compare_count = 0
    @log_file = File.new("logfile.txt","w")
  end 

  #expects an even deck size
  def shuffle_up_and_deal
    @deck = (1..@deck_size).to_a.sort_by {rand}
    @p1_deck = @deck[0,@deck_size/2]
    @p2_deck = @deck[@deck_size/2,@deck_size/2]
    @compare_count = 0
  end 

  def play_the_game
    game_over = false
    while(!game_over)
      #cards currently at stake are broken off into stacks
      #usually this is just the single card being matched
      #but this could conceivably be a large stack in the case of many 'wars'
      p1_stack = Array.new
      p2_stack = Array.new
      p1_stack << @p1_deck.slice!(0)
      p2_stack << @p2_deck.slice!(0)
      #start the (possibly) recursive comparison for this turn
      compare_stacks(p1_stack,p2_stack)
      @compare_count += 1
      if(@p1_deck.length == 0)
        puts "Player 2 wins"
        puts @compare_count
        game_over = true
      end
      if(@p2_deck.length == 0)
        puts "Player 1 wins"
        game_over = true
        puts @compare_count
      end
    end
  end 

  #not truly functional, depends on the (class) globals @p1_deck,@p2_deck
  def compare_stacks(p1_stack,p2_stack)
    @log_file.puts "Stack1 length: " + p1_stack.length.to_s
    @log_file.puts "Stack2 length: " + p2_stack.length.to_s
    p1_rank = p1_stack.last % @rank
    p2_rank = p2_stack.last % @rank
    if(p1_rank > p2_rank)
      @p1_deck.concat(p2_stack)
      @p1_deck.concat(p1_stack)
    elsif(p2_rank > p1_rank)
      @p2_deck.concat(p1_stack)
      @p2_deck.concat(p2_stack)
    else
      #WAR!
      @log_file.puts "WAR"
      if(@p1_deck.length < 4)
        @log_file.puts "P1 stealing from P2"
        to_steal = 4 - @p1_deck.length
        @p1_deck.concat(@p2_deck.slice!(0,to_steal))
      end
      if(@p2_deck.length < 4)
        @log_file.puts "P2 stealing from P1"
        to_steal = 4 - @p2_deck.length
        @p2_deck.concat(@p1_deck.slice!(0,to_steal))
      end
      p1_stack.concat(@p1_deck.slice!(0,4))
      p2_stack.concat(@p2_deck.slice!(0,4))
      compare_stacks(p1_stack,p2_stack)
    end
  end 

end 

wg = WarGame.new
wg.shuffle_up_and_deal
wg.play_the_game
wg.log_file.close

Version 2

result = rand(2)
puts "Player 1 wins" if(result == 0)
puts "Player 2 wins" if(result == 1)

To a computer, the only difference between the two is that the first one takes longer ;-)

Filed in: curios, technical.

No Comments

Write comment - TrackBack - RSS Comments

Write comment