#!/usr/bin/env ruby # frozen_string_literal: true require 'gosu' require 'optparse' require 'minehunt' class GosuHunt < Gosu::Window def initialize( number_of_mines, scale ) @scale = scale @sprite_size = 6 @number_of_mines = number_of_mines @field = MineHunt::Board.new( @number_of_mines ) @finished = false @state = { dead: false, victory: false } @font = Gosu::Font.new( 20 ) @images = { explorer: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '000000001100011110011110001100000000' ) ), dead_explorer: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '100001010010001100001100010010100001' ) ), door: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '010101101010' * ( @sprite_size / 2 ) ) ), mine: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '111111110011100001100001110011111111' ) ), cell: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '1' * @sprite_size * @sprite_size ) ), visited_cell: Gosu::Image.from_blob( @sprite_size * @scale, @sprite_size * @scale, bits_to_rgbas( '0' * @sprite_size * @sprite_size ) ) } super ( ( @sprite_size + 1 ) * @field.width * @scale ) + @scale, ( ( @sprite_size + 1 ) * @field.height * @scale ) + @scale + 20 self.caption = 'Gosu Hunt' end def bits_to_rgbas( bits ) bits.scan(/.{#{@sprite_size}}/).map do |line| line.gsub( '0', "\0\0\0\0" * @scale ).gsub( '1', "\255\255\255\255" * @scale ) * @scale end.join end def new_level @field = MineHunt::Board.new( @number_of_mines ) @finished = false @state = { dead: false, victory: false } end def button_up(id) if @finished case id when Gosu::KB_ESCAPE, Gosu::KB_Q close when Gosu::KB_R new_level else super end else case id when Gosu::KB_ESCAPE, Gosu::KB_Q close when Gosu::KB_R new_level when Gosu::KB_NUMPAD_1 @state = @field.move 'down-left' when Gosu::KB_NUMPAD_2, Gosu::KB_DOWN @state = @field.move 'down' when Gosu::KB_NUMPAD_3 @state = @field.move 'down-right' when Gosu::KB_NUMPAD_4, Gosu::KB_LEFT @state = @field.move 'left' when Gosu::KB_NUMPAD_6, Gosu::KB_RIGHT @state = @field.move 'right' when Gosu::KB_NUMPAD_7 @state = @field.move 'up-left' when Gosu::KB_NUMPAD_8, Gosu::KB_UP @state = @field.move 'up' when Gosu::KB_NUMPAD_9 @state = @field.move 'up-right' else super end end @finished = @state[:dead] || @state[:victory] end def update; end def draw self.caption = if @state[:dead] "You blew up!! :(, score: #{@field.score} " elsif @state[:victory] "You won!! :), score: #{@field.score} " else "Near #{@field.count_nearby_mines} mines, score: #{@field.score}" end @font.draw_text( caption, 0, 0, 0 ) @field.height.times do |y| @field.width.times do |x| ( if [@field.explorer_x, @field.explorer_y] == [x, y] @state[:dead] ? @images[:dead_explorer] : @images[:explorer] elsif [@field.width, @field.height] == [x + 1, y + 1] @images[:door] elsif @field.field[[x, y]].open @images[:visited_cell] elsif @field.field[[x, y]].mine && ( @state[:dead] || @state[:victory] ) @images[:mine] else @images[:cell] end ).draw ( ( @sprite_size + 1 ) * x * @scale ) + @scale, ( ( @sprite_size + 1 ) * y * @scale ) + @scale + 20, 0 end end end end options = { number_of_mines: 20, scale: 3 } OptionParser.new do |opts| opts.banner = 'Usage: gosuhunt ' opts.on( '-m', '--mines INT' ) do |nb_mines| options[:number_of_mines] = nb_mines.to_i end opts.on( '-s', '--scale INT' ) do |scale| options[:scale] = scale.to_i end end .parse! GosuHunt.new( options[:number_of_mines], options[:scale] ) .show