# frozen_string_literal: true module Conwaymp class Board attr_reader :grid def initialize(opts) @opts = opts @sleep_time = 0.5 # Seconds # Initialize the board @grid = [] # Initialize the stats @state = { tick: 0 } generate_grid seed_file = @opts[:load] || @opts[:seed] seed_grid(seed_file, !@opts[:seed].nil?) if seed_file end def generate_grid @opts[:rows].times do @grid << Array.new(@opts[:cols]) { Cell.new } end end def clear_grid @grid.flatten.map(&:die!) # Kill all cells end def seed_grid(path, is_included) clear_grid if is_included path = File.expand_path("../../../seeds/#{path}", __FILE__) end file = File.read(File.expand_path(path)) file.split.each_with_index do |r, ri| r.split(',').each_with_index do |c, ci| @grid[ri][ci].rebirth! if c == '1' end end end # TODO: This method feels wrong. # I'm sure there's something here that can be done with permutations? def possible_neighbours_of(row, col) [ [row - 1, col], # N [row, col + 1], # E [row + 1, col], # S [row, col - 1], # W [row + 1, col + 1], # SE [row - 1, col - 1], # NW [row + 1, col - 1], # SW [row - 1, col + 1], # NE ] .select do |r, c| # Ensure they're within bounds (0..@opts[:rows] - 1).cover?(r) && (0..@opts[:cols] - 1).cover?(c) end end def neighbours_of(row, col) cell = @grid[row][col] neighbours = [] possible_neighbours_of(row, col).each do |r, c| neighbours << @grid[r][c] end cell.living_neighbours = neighbours.select(&:alive?).count neighbours end def population @grid.flatten.select(&:alive?).count end def print_board puts "\e[H\e[2J" # Clear the screen map = @grid.map do |row| row.map(&:print).join('') end.join("\n") puts map end # TODO: Tidy? def print_stats puts ' + ' * @opts[:cols] puts "Tick: #{@state[:tick]}\t Pop.: #{population}" .center(@opts[:cols] * 3) end def display print_board print_stats end def tick @state[:tick] += 1 (0..(@opts[:rows] - 1)).each do |row| (0..(@opts[:cols] - 1)).each do |col| neighbours_of(row, col) end end @grid = @grid.map do |row| row.map do |cell| cell.tick cell end end sleep @sleep_time end end end