Skip to content

Instantly share code, notes, and snippets.

@JaciBrunning
Created July 30, 2015 10:01
Show Gist options
  • Save JaciBrunning/fecbe9205627676bea5d to your computer and use it in GitHub Desktop.
Save JaciBrunning/fecbe9205627676bea5d to your computer and use it in GitHub Desktop.
require 'io/console'
require 'optparse'
# Field Constants
@field_size = 10
@bomb_count = 10
OptionParser.new do |o|
o.on("-f SIZE", "--field", "Set the field size (square)") { |f| @field_size = f.to_i }
o.on("-b COUNT", "--bomb", "Set the bomb count") { |b| @bomb_count = b.to_i }
end.parse!
# Colors
RED = [31, 0]
GREEN = [32, 0]
BROWN = [33, 0]
WHITE = [0, 0]
GRAY = [37, 0]
BLACK = [30, 0]
WHITE_BG = [47, 0]
# The currently selected cell
SELECTED = [0, 0]
# Read character from input -- Parses arrows and other codes
def readchar
input = STDIN.getch
if input == "\e"
input << STDIN.read_nonblock(3) rescue nil
input << STDIN.read_nonblock(2) rescue nil
end
input
end
# Colorize a String
def col color, s
"\033[#{color[0]}m#{s}\033[#{color[1]}m"
end
# Symbol Constants
NONE = "-"
FLAG = col BROWN, "*"
BOMB = col RED, "x"
# Generate Bombs
@field = Array.new(@field_size).fill { Array.new(@field_size).fill { {:bomb => false, :revealed => false, :flagged => false, :adj => 0} } }
@bomb_count.times do |x|
sample = @field.sample.sample
while (sample[:bomb])
sample = @field.sample.sample
end
@field.sample.sample[:bomb] = true
end
# Get all adjacent cells
def get_adj cell
cells = []
3.times do |dx|
3.times do |dy|
nx = cell[0] + 1 - dx
ny = cell[1] + 1 - dy
if (nx != -1 && nx < @field_size && ny != -1 && ny < @field_size)
cells << [nx, ny]
end
end
end
cells
end
# Generate adjacents
@field.each_with_index do |row, x|
row.each_with_index do |cell, y|
unless cell[:bomb]
count = 0
cells = get_adj [x, y]
cells.each {|x| count += 1 if @field[x[0]][x[1]][:bomb] }
cell[:adj] = count
end
end
end
def sel
@field[SELECTED[0]][SELECTED[1]]
end
# Draw the board
def draw
@field.each_with_index do |row, rind|
print " "
row.each_with_index do |cell, cind|
s = [rind, cind] == SELECTED
txt = cell[:adj]
txt = NONE unless cell[:revealed]
txt = FLAG if cell[:flagged]
txt = BOMB if (cell[:revealed] && cell[:bomb])
if s
print col(WHITE_BG, col(BLACK, txt))
else
print txt
end
print " "
end
puts
end
end
# Delete the board
def del
@field_size.times do
print "\r\e[A\e[K"
end
end
draw
@do = true
# Lose game
def lose
@do = false
@field.each do |row|
row.each do |cell|
cell[:revealed] = true
cell[:flagged] = false
end
end
draw
puts col RED, "You Lose!"
readchar
end
# Win game
def win
@do = false
@field.each do |row|
row.each do |cell|
cell[:revealed] = true
end
end
draw
puts col GREEN, "You Win!"
readchar
exit
end
# Check for a win
def check_win
@rev = true
@flag = true
@field.each do |row|
row.each do |cell|
if cell[:flagged] && !cell[:bomb]
@rev = false
elsif !cell[:revealed] && !cell[:bomb]
@rev = false
end
if !cell[:flagged] && cell[:bomb]
@flag = false
end
end
end
win if (@flag || @rev)
end
# Reveal a cell, and adjacents if '0'
def reveal cell
c = @field[cell[0]][cell[1]]
unless c[:revealed]
c[:revealed] = true
if c[:adj] == 0
cells = get_adj cell
cells.map { |x| @field[x[0]][x[1]][:bomb] ? nil : x }.compact.each do |x|
reveal x
end
end
end
end
# Read keys
while @do
char = readchar
@do = false if char == "\u0003"
match = char.match /\e\[(\w)/
del
if match != nil
c = match[1]
if c == "A"
SELECTED[0] -= 1
SELECTED[0] = @field_size - 1 if SELECTED[0] == -1
elsif c == "B"
SELECTED[0] += 1
SELECTED[0] = 0 if SELECTED[0] == @field_size
elsif c == "C"
SELECTED[1] += 1
SELECTED[1] = 0 if SELECTED[1] == @field_size
elsif c == "D"
SELECTED[1] -= 1
SELECTED[1] = @field_size - 1 if SELECTED[1] == -1
end
elsif char == "f"
sel[:flagged] = !sel[:flagged]
elsif char == "\r"
unless (sel[:flagged] || sel[:revealed])
reveal(SELECTED)
if sel[:bomb]
lose
exit
end
end
end
check_win
draw
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment