=begin                    __                    __                               
          __       __     \_\  __          __   \_\  __   __       __            
          \_\     /_/        \/_/         /_/      \/_/   \_\     /_/            
        .-.  \.-./  .-.   .-./  .-.   .-./  .-.   .-\   .-.  \.-./  .-.          
       //-\\_//-\\_//-\\_//-\\_//-\\_//-\\_// \\_//-\\_//-\\_//-\\_//-\\         
     __(   '-'   '-'\  '-'   '-'  /'-'   '-'\__'-'   '-'__/'-'   '-'\__          
    /_/))            \__       __/\          \_\       /_/           \_\         
 ___\_//              \_\     /_/  \__                                           
/_/  ((                             \_\                                          
      )) __                                                                      
__   // /_/                           NUMBAH CRONSHERS                           
\_\_((_/___                          For sister Margot,                         
     ))  \_\             Who teaches Math to Those Who Know it Not,              
     \\                 A Birthday game from my own early schooling,             
        \\              Shoddily recreated, shod in fact, using SHOES,           
          )) _              a neccesity for those wishing to play.               
    __   // /_/                 http://shoooes.net/downloads                     
    \_\_((_/___                                                                  
         ))       move about with arrow keys, press 'm' to cronsch a number.     
         ((           and DO watch out for the troggle, stupid as he is.         
         \\                   __                    __                           
         //    __       __     \_\  __          __   \_\  __   __       __       
      __  ))    \_\     /_/        \/_/         /_/      \/_/   \_\     /_/      
      \_\_((   .-.  \.-./  .-.   .-./  .-.   .-./  .-.   .-\   .-.  \.-./  .-.   
           \\_//-\\_//-\\_//-\\_//-\\_//-\\_//-\\_// \\_//-\\_//-\\_//-\\_//-\\  
            'dc\__'-'   '-'\  '-'   '-'  /'-'   '-'\__'-'   '-'__/'-'   '-'\__   
                \_\         \__       __/\          \_\       /_/           \_\  
                             \_\     /_/  \__                                    
                                           \_\                                   
=end                                                                             
                                                                                 
class Game                                                                       
  attr_reader   :level, :points_for_next_level, :grid
  attr_accessor :over         
                
  def self.grid_size; 24; end

  def initialize
    @level = Level.all_levels.first
    @points_for_next_level = 30
    build_new_grid
  end
  
  def build_new_grid
    @grid = []
    Game.grid_size.times do
      @grid << Square.new(rand(29) + 1)
    end
  end
  
  def advance_to_next_level
    @points_for_next_level += 30
    if @level = @level.next
      build_new_grid
    else
      self.over = "win!"
    end
  end
end

# a Level has a set of name and a "qualifier", which just means what numbers will be munchable 
class Level
  attr_reader :name, :qualifier
  
  def initialize(name, qualifier)
    @name, @qualifier = name, qualifier
    @munchable_square_count = 0
  end
  
  def self.all_levels
    @all ||= [
      new("Odd Numbers",    lambda{|x| x % 2 != 0}),
      new("Divisible by 3", lambda{|x| x % 3 == 0}),
  	  new("Factors of 16",  lambda{|x| 16 % x == 0}),
  	  new("Prime Numbers",  lambda{|x| [3,5,7,11,13,17,19, 23, 29].include? x })
  	]
  end
  
  def number
    Level.all_levels.index(self)
  end
  
  def next
    Level.all_levels[number + 1]
  end
  
  def munchable?(number)
    qualifier.call(number)
  end
end

# just a lil class to represent what numbers are where
class Square
  attr_accessor :number
  
  def initialize(num)
    @number = num 
  end
end

# a wee critter. you are one, as well as your enemy
class Cronsher
  attr_accessor :position, :score, :image_path
  
  def initialize(position = 0, image_path = 'http://s3.amazonaws.com/projectionist/cronsher.png')
    @position = position
    @score = 0
    @image_path = image_path
  end
  
  def move(offset)
    new_square_number = position + offset
    if new_square_number >= 0 && new_square_number <= Game.grid_size
      self.position = new_square_number
    end
  end
  
  def munch(square)
    square.number = nil
    self.score += 10
  end
end

# here is where it alls gets put together in a Shoes window
Shoes.app :title => "NUMBAH CRONSHERS", :width => 600, :height => 530 do
  $app = self
  @game = Game.new
	@cronsher = Cronsher.new(1)
	@troggle  = Cronsher.new(20, 'http://s3.amazonaws.com/projectionist/troggle.png')
  
  def draw_world
    background navy
    stack do
      subtitle @game.level.name, :align => "center", :stroke => limegreen, :weight => 'semibold'
      caption "Level #{@game.level.number}", :stroke => lightcyan
      caption "Score: #{@cronsher.score}", :stroke => lightcyan     
    end
    
    flow :height => 400, :width => 600 do
      @game.grid.each_with_index do |square, index|
        stack :width => 100, :height => 100 do
          border fuchsia, :strokewidth => 3
          title square.number, :stroke => white, :align => 'center'
          [@cronsher, @troggle].each {|guy| draw_character(guy) if guy.position == index}
        end
      end
    end 
  end
  
  def draw_character(cronsher)
    image(cronsher.image_path, :center => true, :bottom => 10, :left => 20)
  end
  
  def move_troggle
    @troggle.position -= 1
  end
  
  ## a loop that captures your keypresses, moves the troggle, 
  ## then clears and redraws the canvas
  animate do |frame|
    keypress do |key|      
      current_square = @game.grid[@cronsher.position]
      case key
      when :left
        @cronsher.move(-1)
      when :right
        @cronsher.move(1)
      when :down 
        @cronsher.move(6)
      when :up   
        @cronsher.move(-6)
      when 'm'
        if @game.level.munchable?(current_square.number)
          @cronsher.munch(current_square)
          @game.advance_to_next_level if @cronsher.score >= @game.points_for_next_level  
        end
      end
    end
    
    move_troggle if frame % 60 == 0
    @game.over = 'lose!' if @troggle.position == @cronsher.position
    
    $app.clear
    @game.over ? end_game : draw_world      
  end
  
  def end_game
    case @game.over
    when 'win!'
      background gradient(mintcream, mediumturquoise)
      banner "HAPPY BIRTHDAY, MARGOT! love, patrick", :stroke => mistyrose, :align => 'center', :weight => 'heavy', :top => 150
    when 'lose!'
      background gradient(white, black)
      banner "O, DEATH", :weight => 'heavy', :top => 300, :align => 'center'
    end
  end
end