Last active
August 29, 2015 14:02
-
-
Save rserur/7554d140acffca6b99c8 to your computer and use it in GitHub Desktop.
LA Minesweeper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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