Skip to content

Instantly share code, notes, and snippets.

@rserur
Last active August 29, 2015 14:02
Show Gist options
  • Select an option

  • Save rserur/7554d140acffca6b99c8 to your computer and use it in GitHub Desktop.

Select an option

Save rserur/7554d140acffca6b99c8 to your computer and use it in GitHub Desktop.
LA Minesweeper
require 'pry'
class Minefield
attr_reader :row_count, :column_count
def initialize(row_count, column_count, mine_count)
@column_count = column_count
@row_count = row_count
@empty_cells = (column_count * row_count) - mine_count
@clear_count = 0
@mine_count = mine_count
@minefield = {}
@any_mines_detonated = false
@all_cells_cleared = false
@contains_mine = false
for y in 0..@column_count
for x in 0..@row_count
@minefield[[x,y]] = { clear: false, mine: false }
end
end
@mine_count.times do
rand_x = Random.rand(@column_count)
rand_y = Random.rand(@row_count)
@minefield[[rand_x,rand_y]] = { clear: false, mine: true }
end
end
# Return true if the cell been uncovered, false otherwise.
def cell_cleared?(row, col)
if @minefield[[row, col]][:clear] == false
false
else
true
end
end
# Uncover the given cell. If there are no adjacent mines to this cell
# it should also clear any adjacent cells as well. This is the action
# when the player clicks on the cell.
def clear(row, col)
if @minefield[[row, col]][:clear] == false
# clear cell if not cleared already
@minefield[[row, col]][:clear] = true
@clear_count += 1
# if cell isn't 0,0, clear adjacent upper-left cell
if row != 0 && col != 0
@minefield[[row - 1, col - 1]][:clear] = true
@clear_count += 1
end
# if cell isn't in top row, clear adjacent above & upper-right cells
if row != 0
@minefield[[row - 1, col + 0]][:clear] = true
@minefield[[row - 1, col + 1]][:clear] = true
@clear_count += 2
end
# if cell isn't in left-most column, clear adjacent left and bottom-left cells
if col != 0
@minefield[[row + 1, col - 1]][:clear] = true
@minefield[[row + 0, col - 1]][:clear] = true
@clear_count += 2
end
# if cell isn't in last cell, clear bottom-right cell
if row != @row_count && col != @column_count
@minefield[[row + 1, col + 1]][:clear] = true
@clear_count += 1
end
# if cell isn't in bottom row, clear adjacent bottom cell
if row != @row_count
@minefield[[row + 1, col + 0]][:clear] = true
@clear_count += 1
end
# if cell isn't in right-most column, clear adjacent right cell
if col != @column_count
@minefield[[row + 0, col + 1]][:clear] = true
@clear_count += 1
end
end
end
# Check if any cells have been uncovered that also contained a mine. This is
# the condition used to see if the player has lost the game.
def any_mines_detonated?
@minefield.each do | key, value |
if value[:clear] == true and value[:mine] == true
@any_mines_detonated = true
break
else
@any_mines_detonated = false
end
end
@any_mines_detonated
end
# Check if all cells that don't have mines have been uncovered. This is the
# condition used to see if the player has won the game.
def all_cells_cleared?
if @clear_count == @empty_cells
return true
else
return false
end
end
# Returns the number of mines that are surrounding this cell (maximum of 8).
def adjacent_mines(row, col)
count = 0
if row != 0 && col != 0
if @minefield[[row - 1, col - 1]][:mine] == true
count += 1
end
end
if row != 0
if @minefield[[row - 1, col + 0]][:mine] == true
count += 1
end
if @minefield[[row - 1, col + 1]][:mine] == true
count += 1
end
end
if col != 0
if @minefield[[row + 1, col - 1]][:mine] == true
count += 1
end
if @minefield[[row + 0, col - 1]][:mine] == true
count += 1
end
end
if row != @row_count && col != @column_count
if @minefield[[row + 1, col + 1]][:mine] == true
count += 1
end
end
if row != @row_count
if @minefield[[row + 1, col + 0]][:mine] == true
count += 1
end
end
if col != @column_count
if @minefield[[row + 0, col + 1]][:mine] == true
count += 1
end
end
count
end
def contains_mine?(row, col)
if @minefield[[row, col]][:mine] == true
@contains_mine = true
else
@contains_mine = false
end
@contains_mine
end
end
require 'gosu'
require 'pry'
require_relative 'minefield'
class Minesweeper < Gosu::Window
SCREEN_WIDTH = 1028
SCREEN_HEIGHT = 720
attr_reader :field, :mine_font, :large_font, :state
def initialize
super(SCREEN_WIDTH, SCREEN_HEIGHT, false)
@field = Minefield.new(20, 20, 50)
@mine_font = Gosu::Font.new(self, "Arial", (cell_size / 1.2).to_i)
@large_font = Gosu::Font.new(self, "Arial", screen_height / 6)
@state = :running
end
def button_down(key)
case key
when Gosu::MsLeft
if state == :running
if within_field?(mouse_x, mouse_y)
row, col = screen_coord_to_cell(mouse_x, mouse_y)
field.clear(row, col)
if field.any_mines_detonated?
@state = :lost
elsif field.all_cells_cleared?
@state = :cleared
end
end
end
when Gosu::KbEscape
close
when Gosu::KbSpace
if state != :running
reset
end
end
end
def reset
@field = Minefield.new(20, 20, 50)
@state = :running
end
def draw
draw_rect(0, 0, screen_width, screen_height, Gosu::Color::BLACK)
draw_rect(start_x, start_y, field_width, field_height, Gosu::Color::BLACK)
dark_gray = Gosu::Color.new(50, 50, 50)
gray = Gosu::Color.new(127, 127, 127)
light_gray = Gosu::Color.new(200, 200, 200)
(0...field.row_count).each do |row|
(0...field.column_count).each do |col|
x = start_x + (col * cell_size)
y = start_y + (row * cell_size)
adjacent_mines = 0
if !field.cell_cleared?(row, col)
color = gray
elsif field.contains_mine?(row, col)
color = Gosu::Color::RED
else
adjacent_mines = field.adjacent_mines(row, col)
color = light_gray
end
draw_rect(x, y, cell_size, cell_size, dark_gray)
draw_rect(x + 2, y + 2, cell_size - 4, cell_size - 4, color)
if adjacent_mines > 0
text_x = x + (cell_size - mine_font.text_width(adjacent_mines)) / 2
text_y = y + (cell_size - mine_font.height) / 2
draw_text(text_x, text_y, adjacent_mines, mine_font)
end
end
end
case state
when :lost
draw_text_centered("game over", large_font)
when :cleared
draw_text_centered("cleared!", large_font)
end
end
def cell_size
max_cell_width = (screen_width * 0.90) / field.column_count
max_cell_height = (screen_height * 0.90) / field.row_count
if max_cell_width > max_cell_height
max_cell_height
else
max_cell_width
end
end
def field_width
cell_size * field.column_count
end
def field_height
cell_size * field.row_count
end
def start_x
(screen_width - field_width) / 2.0
end
def start_y
(screen_height - field_height) / 2.0
end
def needs_cursor?
true
end
def draw_rect(x, y, width, height, color)
draw_quad(x, y, color,
x + width, y, color,
x + width, y + height, color,
x, y + height, color)
end
def draw_text(x, y, text, font)
font.draw(text, x, y, 1, 1, 1, Gosu::Color::BLACK)
end
def draw_text_centered(text, font)
x = (screen_width - font.text_width(text)) / 2
y = (screen_height - font.height) / 2
draw_text(x, y, text, font)
end
def within_field?(x, y)
x >= start_x && x < (start_x + field_width) &&
y >= start_y && y < (start_y + field_height)
end
def screen_coord_to_cell(x, y)
col = ((x - start_x) / cell_size).to_i
row = ((y - start_y) / cell_size).to_i
[row, col]
end
def screen_width
width
end
def screen_height
height
end
end
game = Minesweeper.new
game.show
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment