Created
April 3, 2013 10:27
-
-
Save edvardm/5300071 to your computer and use it in GitHub Desktop.
simple curses-based gof
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 'curses' | |
class GameOfLife | |
LIVE_CHAR = "0" | |
DEAD_CHAR = '.' | |
def initialize(nrows, ncols, opts={}, &block) | |
@nrows, @ncols = nrows, ncols | |
@opts = opts | |
@rows = (0..@nrows).each_with_object([]) { |i, acc| @ncols.times { (acc[i] ||= []) << DEAD_CHAR } } | |
block.call.each { |i, j| @rows[i][j] = LIVE_CHAR } if block | |
@generations = 0 | |
end | |
class Finished < StandardError; end | |
def run | |
curses_context do | |
begin | |
loop do | |
show | |
next_iteration | |
sleep @opts.fetch(:sleep_int, 0.25) | |
end | |
rescue Finished | |
print " Finished, press key when ready..." | |
STDIN.getc | |
end | |
end | |
end | |
private | |
def curses_context(&block) | |
Curses.init_screen | |
block.call | |
ensure | |
Curses.close_screen | |
end | |
def write_ch(row, col, char) | |
Curses.setpos(row, col) | |
Curses.addch(char) | |
end | |
def show | |
each_cell { |i, j| write_ch i, j, @rows[i][j] } | |
Curses.setpos(@nrows, 0) | |
Curses.addstr(@generations.to_s) | |
@generations += 1 | |
Curses.refresh | |
end | |
def each_cell | |
@nrows.times { |i| @ncols.times { |j| yield [i, j] } } | |
end | |
def next_iteration | |
@prev_state = @rows.flatten | |
new_rows = (0...@nrows).each_with_object([]) { |i, a| a << @rows[i].to_a } | |
each_cell do |i, j| | |
if (alive?(i, j) && live_neigh_count(i, j) < 2) || (alive?(i, j) && live_neigh_count(i, j) > 3) | |
new_rows[i][j] = DEAD_CHAR | |
elsif (alive?(i, j) && [2, 3].include?(live_neigh_count(i, j))) || (!alive?(i, j) && live_neigh_count(i, j) == 3) | |
new_rows[i][j] = LIVE_CHAR | |
end | |
end | |
@rows = new_rows | |
raise Finished if @rows.flatten == @prev_state | |
end | |
def alive?(i, j) | |
@rows[i][j] == LIVE_CHAR | |
end | |
def live_neigh_count(i, j) | |
neighbours(i, j).select { |i, j| alive?(i, j) }.size | |
end | |
def neighbours(i, j) | |
[[i-1, j-1], [i-1, j], [i-1, j+1], [i, j+1], [i+1, j+1], [i+1, j], [i+1, j-1], [i, j-1]].select { |i, j| valid_cell?(i, j) } | |
end | |
def valid_cell?(x, y) | |
0 <= x && x < @nrows && 0 <= y && y < @ncols | |
end | |
end | |
rows = 20 | |
cols = 40 | |
offset = [rows, cols].min / 2 | |
count = 20 | |
GameOfLife.new(rows, cols, sleep_int: 0.1) do | |
(1..count).map { |_| [rand(rows/4)+offset, rand(cols/4)+offset] } | |
end.run | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment