lifewidget.rb

require './lifewidget_ui.rb'

require 'Qt'

class LifeWidget < Qt::Widget

slots 'change_speed(int)','compute_next_generation()','on_runB_clicked()',

'on_restartB_clicked()','on_stepB_clicked()',

'on_backB_clicked()'

attr_accessor :ui, :back_enabled

def initialize(parent=nil, gridw=100, gridh=100,gbv_w=200,gbv_h=200)

# grid width and height, gameboard_viewer width and height in pixels

super parent

@ui = Ui_LifeWidget.new

@ui.setupUi(self)

@timer = Qt::Timer.new(self)

@speed = 100

@gridw = gridw

@gridh = gridh

init_grids

@ui.gameboard_viewer.init @grid

@ui.horizontal_scrollbar.setMinimum(0)

@ui.horizontal_scrollbar.setMaximum(200)

@ui.horizontal_scrollbar.setValue 0

@ui.vertical_scrollbar.setMinimum(0)

@ui.vertical_scrollbar.setMaximum(100)

@ui.vertical_scrollbar.setValue 0

@ui.universe_sizeL.setText "#{@gridw}x#{@gridh}"

connect(@ui.zoom_slider,SIGNAL('valueChanged(int)'),@ui.gameboard_viewer, SLOT('change_zoom(int)'))

connect(@ui.horizontal_scrollbar,SIGNAL('valueChanged(int)'),@ui.gameboard_viewer,SLOT('change_x_offset(int)'))

connect(@ui.vertical_scrollbar,SIGNAL('valueChanged(int)'),@ui.gameboard_viewer,SLOT('change_y_offset(int)'))

connect(@ui.speed_slider,SIGNAL('valueChanged(int)'),self, SLOT('change_speed(int)'))

@ui.gameboard_viewer.connect(SIGNAL 'zoomChanged(int)') do |val|

@ui.zoom_slider.setValue(val)

end

@ui.clearB.connect(SIGNAL :clicked) do

init_grids

load_grid @grid

end

@ui.gameboard_viewer.setMinimumSize gbv_w,gbv_h

connect(@timer,SIGNAL('timeout()'),self,SLOT('compute_next_generation()'))

@running = false

@ticks = Time.now

@cells_to_add = Array.new

@cells_to_delete =Array.new

@back_enabled = false # whether you can can step back to previous generations

@ui.backCB.connect(SIGNAL 'stateChanged(int)') do |state|

if state == Qt::Checked

@back_enabled = true

@ui.backB.setEnabled true

else

@back_enabled = false

@ui.backB.setEnabled false

end

end

@back_buffer_size = 30

@ui.back_buffer_depthSB.connect(SIGNAL 'valueChanged(int)') do |val|

@back_buffer_size = val

end

@last_paint_time = Time.now

end

def init_grids #new grid and cleared history buffer

@grid = Array.new

@grid = (0..(@gridh-1)).to_a.map{|row| row=(0..(@gridw-1)).to_a.map{|x| x = 0}}

@generation = 0

@previous_grid = deep_copy_matrix @grid #each time run is pressed, it saves the grid, so you can rerun a setup

@previous_generation = 0

@grid[10][9] = 1

@grid[11][8] = 1

@grid[10][10] = 1

@grid[11][10] = 1

@grid[12][10] = 1

@grids = Array.new

end

def load_grid grid

@grid = grid

@ui.gameboard_viewer.set_grid @grid

@ui.gameboard_viewer.update

end

def change_speed speed

@speed = 200 - speed

@timer.setInterval(@speed)

end

def run

@previous_generation = @generation

@previous_grid = deep_copy_matrix @grid

@running = true

@timer.start(@speed)

@ui.runB.setText("Pause")

end

def stop

@running = false

@timer.stop

@ui.runB.setText("Run")

@ui.gameboard_viewer.update

end

def on_runB_clicked

if @running

stop

else

run

end

end

def get_grid

stop

@grid

end

def on_stepB_clicked

compute_next_generation

end

def on_backB_clicked

unless @grids.empty?

@grid = @grids.pop

@ui.gameboard_viewer.grid = @grid

@ui.gameboard_viewer.update

end

end

def push_grid

old_grid = deep_copy_matrix @grid

@grids << old_grid

if @grids.length > @back_buffer_size

@grids.shift #get rid of the oldest one

end

end

def compute_next_generation

push_grid if @back_enabled

@generation += 1

@ui.generationL.setText(@generation.to_s)

@cells_to_add.clear

@cells_to_delete.clear

row = 0

col = 0

0.upto(@gridh-1) do |row|

0.upto(@gridw-1) do |col|

num_neighbors = number_of_neighbors(row,col)

if @grid[row][col] == 1

if num_neighbors < 2 or num_neighbors > 3

@cells_to_delete << [row,col]

end

else

if num_neighbors == 3

@cells_to_add << [row,col]

end

end

col += 1

end

row += 1

end

@cells_to_add.each do |row,col|

@grid[row][col] = 1;

end

@cells_to_delete.each do |row, col|

@grid[row][col] = 0;

end

dt = Time.now - @last_paint_time

if dt > 1/30 #paint at a max of 30 frames /sec

@ui.gameboard_viewer.update

@last_paint_time = Time.now

end

end

def number_of_neighbors(row,col)

count = 0

for r in (row-1)..(row+1)

for c in (col-1)..(col+1)

unless r==row and c==col

count += 1 if @grid[r % @gridh][c % @gridw] == 1

end

end

end

count

end

def keyPressEvent event

if event.key == Qt::Key_R

run

elsif event.key == Qt::Key_S and event.modifiers == Qt::NoModifier

stop

else

event.ignore

end

end

def on_restartB_clicked

@grid = @previous_grid

@ui.gameboard_viewer.grid = @grid

@ui.gameboard_viewer.update

end

end