Trying to show a balloon notification with Ruby - ruby

I'm trying to make a little class in ruby allowing me to make a system tray icon and use the notification balloons. But I'm having problems using structs with Win32API calls.
http://www.ruby-forum.com/topic/18102
Shell_NotifyIcon Function
NOTIFYICONDATA Struct
Heres the code I have now, all it does is add an icon to the system tray:
require 'Win32API'
NIF_MESSAGE = 1
NIF_ICON = 2
NIF_TIP = 4
NIF_STATE = 8
NIF_INFO = 10
NIM_ADD = 0
NIM_MODIFY = 1
NIM_DELETE = 2
NIS_HIDDEN = 1
NIS_SHAREDICON = 2
class NotifyIconData < Struct.new(:cbsize, :hwnd, :uid, :uflags, :ucallbackmessage, :hicon)#, :sztip, :dwstate, :dwstatemask, :szinfo, :utimeout, :uversion, :szinfotitle, :dwinfoflags, :guiditem, :hballoonicon)
def pack
values.pack('LLIIIL')
end
# def self.unpack(s)
# new(*s.unpack('LLIIIL'))
# end
end
#===---
ExtractIcon = Win32API.new('shell32', 'ExtractIcon', 'LPI', 'L')
Shell_NotifyIcon = Win32API.new('shell32', 'Shell_NotifyIconA', 'LP', 'I')
hicoY = ExtractIcon.call(0, 'C:\WINDOWS\SYSTEM32\INETCPL.CPL', 21) # Green tick
hicoN = ExtractIcon.call(0, 'C:\WINDOWS\SYSTEM32\INETCPL.CPL', 22) # Red minus
#===---
tiptxt = "hai"
nid = NotifyIconData.new
nid.cbsize = Marshal.dump(NotifyIconData).size#6*4+64
nid.hwnd = 0
nid.uid = 'ruby'.hash
nid.uflags = NIF_INFO
nid.ucallbackmessage = 0
nid.hicon = hicoY
ret = Shell_NotifyIcon.call( NIM_ADD, nid.pack << tiptxt << "\0"*(64 - tiptxt.size) )
p 'Err: NIM_ADD' if ret == 0
sleep(3) # <----<<
# pnid = [6*4+64, 0, 'ruby'.hash, NIF_ICON | NIF_TIP, 0, hicoN].pack('LLIIIL') << tiptxt << "\0"*(64 - tiptxt.size)
# ret = Shell_NotifyIcon.call(NIM_MODIFY, pnid)
# p 'Err: NIM_MODIFY' if ret == 0
# sleep(6) # <----<<
nid.uflags = 0
ret = Shell_NotifyIcon.call( NIM_DELETE, nid.pack << "\0" )
p 'Err: NIM_DELETE' if ret == 0

Check out visualuruby and its demo/example files. They got me some balloons quite readily.

Related

How I can fix NoMethodError in Ruby?

I write a multiplayer game(snake) with backend based on Ruby. This function must receive commands for frontend and send the current state of the game. But throw NoMethod error on the four line of my function for the changeside method and I don't know why because of that class method is present.
Class method example
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
Error example
2020-10-07 18:01:23 - NoMethodError - undefined method `[]' for nil:NilClass:
The function I'm run
def getStatus(game)
ans = {"opStatus"=>TRUE}
puts game
$games[game['gid'.to_i]]['game'].changeside(2,game['side'])
$games[game['gid'.to_i]]['game'].move(($games[game['gid']]['fid']==game['pid']?1:2))
ans["gameStatus"] = $games[game['id']]['game'].run
ans['timer'] = $games[game['id']]['game'].timer
ans['snake'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?1:2)].snake
ans['enemy'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?2:1)].snake
ans['food'] = $games[game['id']]['game'].food
end
Here is JSON sent to the function
{"gid"=>"1", "side"=>"R", "pid"=>"1"}
To fix that, I debugged that moment, but I couldn't go inside a class method.
Here is the full code of the class game.
It located in another file and called by
`require_relative 'game.rb'`
Full code of the class.
class Game
attr_accessor :players, :food, :walls, :timer, :run,:winner
def initialize()
#players = {}
#winner = -1
#players[1] = {'snake'=>[[9,2],[8,2],[7,2]]}
#players[1]['cx'] = 0
#players[1]['cy'] = -1
#players[1]['side'] = 'U'
#players[2] = {'snake'=>[[2,9],[2,8],[2,7]]}
#players[2]['cx'] = -1
#players[2]['cy'] = 0
#players[2]['side'] = 'L'
#timer = 0
#run = FALSE
genFood
end
def genFood()
#food = [rand(10)+1,rand(10)+1]
while players[1]['snake'].include?(food) || players[2]['snake'].include?(food)
#food = [rand(10)+1,rand(10)+1]
end
end
def move(nump)
if #run
#timer+=0.25
#players[nump]['snake'].shift
#players[nump]['snake'].push([#players[id]['snake'][0]+#players[id]['cx'],#players[id]['snake'][1]+#players[id]['cy']])
if #players[nump]['snake'][0] == food
#players[nump]['snake'][0].unshift(food)
#food = [rand(10)+1,rand(10)+1]
while players[nump]['snake'].include(food) or players[1]['snake'].include(food)
#food = [rand(10)+1,rand(10)+1]
end
end
if #player[nump]['snake'].count(#player[nump]['snake'][-1])==2 ||
#winner = ((nump==1)?2:1)
elsif #players[((nump==1)?2:1)]['snake'].count(#player[nump]['snake'][-1])==1
#winner = 0
else
if #timer==60
if #players[1]['snake'].length()>#players[2]['snake'].length()
#winner = 1
elsif #players[1]['snake'].length()<#players[2]['snake'].length()
winner = 2
else
winner = 0
end
end
end
end
end
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
end

Display number of bytes in data set

I wrote a program to create histograms of IP addresses, URLs, error codes, and frequency of IP visits, and would like to obtain the size, in bytes, of the data collected for each histogram. I looked around and saw a bit about the bytes method, but can't seem to get it to function.
Any idea on how to do that to this bit of code? I'd like to add the "byte puts" line after displaying the filename in each method.
class CommonLog
def initialize(logfile)
#logfile = logfile
end
def readfile
#readfile = File.readlines(#logfile).map { |line|
line.split()
}
#readfile = #readfile.to_s.split(" ")
end
def ip_histogram
#ip_count = 0
#readfile.each_index { |index|
if (#readfile[index] =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ )
puts #readfile[index]
puts #ip_count += 1
end
}
puts File.basename #logfile
end
def url_histogram
#url_count = 0
#readfile.each_index { |index|
if (#readfile[index] =~ /\/{1}(([a-z]{4,})|(\~{1}))\:{0}\S+/ )
puts #readfile[index]
puts #url_count += 1
end
}
puts File.basename #logfile
end
def requests_per_hour
#time_count2 = 0
#time_count3 = 0
#time_count4 = 0
#time_count5 = 0
#time_count6 = 0
#readfile.each_index { |index|
if (#readfile[index] =~ /\:\d{2}\:/ )
#new = #readfile[index].split(":")
if #new[1] == "02"
#time_count2 += 1
elsif #new[1] == "03"
#time_count3 += 1
elsif #new[1] == "04"
#time_count4 += 1
elsif #new[1] == "05"
#time_count5 += 1
elsif #new[1] == "06"
#time_count6 += 1
end
end
}
puts "#{#time_count2} instances during hour 2"
puts "#{#time_count3} instances during hour 3"
puts "#{#time_count4} instances during hour 4"
puts "#{#time_count5} instances during hour 5"
puts "#{#time_count6} instances during hour 6"
puts File.basename #logfile
end
def sorted_list
#codearray = Array.new
#http_code_count = 0
#count200 = 0
#count304 =0
#count301 = 0
#count403 = 0
#readfile.each_index { |index|
if #readfile[index] =~ /([2][0][0]")|([3][0][4])|([3][0][1])|([4][0][3])/
#codearray << #readfile[index]
#http_code_count += 1
if #readfile[index] == '200'
#count200 += 1
elsif #readfile[index] == "304"
#count304 += 1
elsif #readfile[index] == "301"
#count301 += 1
elseif #readfile[index] == "403"
#count403 += 1
end
end
}
#hash_count = 0
#frequencies = Hash.new(0)
#codearray.each { |word| #frequencies[word] += 1 }
#frequencies = #frequencies.sort_by { |a, b| a}
#frequencies.each { |word, frequency| #hash_count += frequency}
#frequencies.each { |key, value|
puts "Error #{key} : #{(value.to_f/#hash_count.to_f)*100}%"
}
puts File.basename #logfile
end
end
my_file = CommonLog.new("test_log")
my_file.readfile
my_file.ip_histogram
my_file.url_histogram
my_file.requests_per_hour
my_file.sorted_list
Assuming that the number of bytes processed is the entire size of each log file you could do something like this:
class CommonLog
attr_reader :bytes_read
def initialize(logfile)
#logfile = logfile
#bytes_read = File.size(logfile)
end
# ... now simply print "bytes_read" when desired ...

Ruby noobster does not understand arrays

I'm not a programmer, but I want to become one. So, I read books, I do tutorials and I ask questions. Here is the question:
I'm trying to do a Ruby quiz – the one with the Solitaire cypher (http://rubyquiz.com/quiz1.html). I wrote some code that works pretty well, except that at one point it alters the key_deck array which should be a reference to the end of the program. I do not know where this happens or why.
Here is my noobish code:
$characters = Array ('A' .. 'Z')
def encode to_encode, input_deck
trekljdfg = input_deck
edeck = input_deck
work_string = ''
to_encode.upcase.split("").each do |char|
if $characters.include?(char)
work_string.concat(char)
end
end
work_string = work_string + ('X' * ((5 - (work_string.length % 5)) % 5))
keystream_string = ''
while keystream_string.length < work_string.length do # <-- generate keystream
edeck = permutation(edeck)
keystream_string.concat(get_letter(edeck))
end
encoded = combine_with_keystream(work_string, keystream_string)
encoded = split_string_in_groups(encoded)
return encoded
end
def decode to_decode, input_deck
ddeck = input_deck
to_decode = to_decode.delete(' ')
keystream_string = ''
while keystream_string.length < to_decode.length do # <-- generate keystream
ddeck = permutation(ddeck)
keystream_string.concat(get_letter(ddeck))
end
array_to_decode = text_to_numbers to_decode
array_keystream_string = text_to_numbers keystream_string
decoded = ''
for i in 0..(array_to_decode.length-1)
if array_to_decode[i] >= array_keystream_string[i]
decoded.concat($characters[(array_to_decode[i] - array_keystream_string[i])-1])
else
decoded.concat($characters[(array_to_decode[i] + 26 - array_keystream_string[i])-1])
end
end
decoded = split_string_in_groups decoded
return decoded
end
def permutation deck_to_change
deck = deck_to_change
def swap array, joker
work_array = array
joker_position = work_array.index(joker)
if joker_position == (work_array.length-1)
temp_array = work_array.slice!(1..(work_array.length-2))
work_array = work_array + temp_array
else
work_array[joker_position], work_array[joker_position+1] = work_array[joker_position+1], work_array[joker_position]
end
return work_array
end
deck = swap(deck, 'A') # <-- swap first joker
2.times do # <-- swap second joker
deck = swap(deck, 'B')
end
if deck.index('A') < deck.index('B') # <-- triple cut
joker_position1 = deck.index('A')
joker_position2 = deck.index('B') - joker_position1
else
joker_position1 = deck.index('B')
joker_position2 = deck.index('A') - joker_position1
end
if joker_position1 == 0
temp_array1 = []
else
temp_array1 = deck.slice!(0..joker_position1-1)
end
if joker_position2 == deck.length-1
temp_array2 = []
else
temp_array2 = deck.slice!(joker_position2+1..deck.length-1)
end
deck = temp_array2 + deck + temp_array1
if (deck.last != 'A') | (deck.last != 'B') # <-- count cut
temp_array1 = deck.slice!(0..deck.last.to_i-1)
temp_array2 = deck.pop(1)
deck = deck + temp_array1 + temp_array2
end
return deck
end
def get_letter deck
first = deck.first
case first
when 'A'
first = '53'
when 'B'
first = '53'
end
if (deck[first.to_i] == 'A') | (deck[first.to_i] == 'B')
return ''
else
return $characters[((deck[first.to_i]).to_i-1) % 26]
end
end
def text_to_numbers text
array = []
text.upcase.split("").each do |char|
array.push($characters.index(char)+1)
end
return array
end
def combine_with_keystream string1, string2
temp_array1 = text_to_numbers string1
temp_array2 = text_to_numbers string2
string = ''
for i in 0..(temp_array1.length-1)
tmp = temp_array1[i] + temp_array2[i]
if tmp > 26
tmp = tmp - 26
end
string.concat($characters[tmp-1])
end
return string
end
def split_string_in_groups string
return string.scan(/.{1,5}/).join(" ")
end
#-begin-------------------------
key_deck = ('1' .. '52').to_a + ['A', 'B'] # <-- this is the key deck ^^
string_to_encode = 'Code in Ruby live longer!' # <-- this is the string to be encoded
string_to_decode = 'GLNCQ MJAFF FVOMB JIYCB' # <-- this is the string to be decoded
puts "Your encoded text is: #{encode(string_to_encode, key_deck)}"
puts "Your decoded text is: #{decode(string_to_decode, key_deck)}"
You are using slice! to find your deck's permutations, which changes the input array.
The easiest solution is to dup the array before working on it:
def encode to_encode, input_deck
trekljdfg = input_deck.dup
edeck = input_deck.dup
# ..
end
def decode to_decode, input_deck
ddeck = input_deck.dup
# ..
end
dup creates a copy of the array, which you can safely mutilate.
Your permutation function alters the deck. You pass it a reference to the original deck, so any changes you do on the reference will actually change the original. Try something like this instead:
key_deck = [....]
...
puts "#{encode(string_to_encode, key_dec.clone}"
The clone method will make a new copy of the array for you so all changes will only apply to the copy.
Or you can just avoit the entire problem by using the Array#shuffle method:
puts "#{encode(string_to_encode, key_dec.shuffle}"
That will give an already shuffled deck to the encode function.

Ruby Array Variable Reference Lost During Loop

I am writing a parsing routine in Ruby 2.1 for a spreadsheet. The code works properly through the first array of pricing data. Unfortunately, on the fifth loop through datatable, while processing the second set of pricing data, the variable termtable is not set, even though #tmptermtables is modified by the shift method in this statement on line 72: termtable = #tmptermtables.shift if termtable.empty? This is possibly a scope problem and I am hoping someone can explain to me why the reference is lost.
Below is a copy of the code. Thank you in advance for lending me your brain.
def sp_parser()
begin
pricing_date = Date.new(2014,2,7)
tz = DateTime.parse(Time.now.to_s).strftime('%z')
expires = DateTime.new(pricing_date.year,pricing_date.mon,pricing_date.mday,17,00,00,tz)
datatable = Array.new
datatable << ["Zone","Business - Low Load Factor",nil,nil,nil,"Business - Medium Load Factor",nil,nil,nil,"Business - High Load Factor",nil,nil,nil]
datatable << [nil,6,9,12,15,6,9,12,15,6,9,12,15]
datatable << [nil,"Daily Pricing",nil,nil,nil,"Daily Pricing",nil,nil,nil,"Daily Pricing",nil,nil,nil]
datatable << ["COAST",6.41,6.55,6.19,6.01,6.07,6.18,5.88,5.74,5.63,5.71,5.48,5.37]
datatable << ["NORTH",6.58,6.74,6.35,6.15,6.02,6.13,5.85,5.68,5.61,5.68,5.47,5.33]
datatable << [nil,3/1/2014,nil,nil,nil,3/1/2014,nil,nil,nil,3/1/2014,nil,nil,nil]
datatable << ["COAST",7.08,6.53,6.20,6.00,6.63,6.17,5.89,5.73,6.06,5.69,5.49,5.36]
datatable << ["NORTH",7.34,6.72,6.36,6.13,6.60,6.10,5.86,5.66,6.06,5.65,5.48,5.31]
loadprofiles = Array.new
termtables = Array.new
pvalue = 0
load_factor_found = false
daily_pricing_found = false
dataset = []
datatable.each_index {|row|
record = datatable[row]
termtable = Array.new
#tmptermtables = Array.new(termtables)
#tmploadprofiles = Array.new(loadprofiles)
record.each_index {|col|
val = record[col]
## Build the load profile table
loadprofiles << "LOW" if val.to_s.downcase.match(/ low/)
loadprofiles << "MEDIUM" if val.to_s.downcase.match(/medium/)
loadprofiles << "HIGH" if val.to_s.downcase.match(/high/)
load_factor_found = true if val.to_s.downcase.match(/load factor/)
daily_pricing_found = true if val.to_s.downcase.match(/daily pricing/)
## Build the term tables for each load profile
if load_factor_found and !daily_pricing_found
isinteger = val.is_a? Integer
if isinteger
cvalue = val
if cvalue > pvalue
termtable << cvalue
pvalue = cvalue
termtables << termtable if col == record.length - 1
else
unless termtable.empty?
termtables << termtable
termtable = []
termtable << cvalue
pvalue = cvalue
end
end
else
cvalue = 0
end
end
if daily_pricing_found
#start_date = pricing_date if val.to_s.downcase.match(/daily pricing/)
#start_date = val if val.is_a? Date
#zone = "CenterPoint" if val.to_s.downcase.match(/coast/)
#zone = "Oncor" if val.to_s.downcase.match(/north/)
if val.is_a? Float
#load = #tmploadprofiles.shift if termtable.empty?
# Here is where it breaks
termtable = #tmptermtables.shift if termtable.empty?
term = termtable.shift unless termtable.empty?
price = (val/100).round(4)
r = {
:loaded => Time.now,
:start => #start_date,
:load => #load,
:term => term,
:zone => #zone,
:price => price,
:expiration => expires,
:product => "Fixed"
}
dataset << r
end
end
}
}
return dataset
rescue => err
puts "\n" + DateTime.parse(Time.now.to_s).strftime("%Y-%m-%d %r") + " Exception: #{__callee__} in #{__FILE__} generated an error: #{err}\n"
err
end
end
x = sp_parser()

A very specific Conway's Game of Life (Ruby beginner)

Looking for feedback on obvious logic errors on this, not optimizing. I keep getting weird tick counts on the end game message (ex: 1 tick turns into 11 ticks)
The largest error I can spot while running the code is on the 2nd tick, a very large amount of alive cells appear. I am too new to this to understand why, but it seems like the #alive_cells is not resetting back to 0 after each check.
Here is my entire code, its large but it should be child's play to anyone with experience.
class CellGame
def initialize
puts "How big do you want this game?"
#size = gets.chomp.to_i
#cell_grid = Array.new(#size) { Array.new(#size) }
#grid_storage = Array.new(#size) { Array.new(#size) }
#tick_count = 0
fill_grid_with_random_cells
end
def fill_grid_with_random_cells
#cell_grid.each do |row|
row.map! do |cell|
roll = rand(10)
if roll > 9
"•"
else
" "
end
end
end
check_cells_for_future_state
end
def check_for_any_alive_cells
#cell_grid.each do |row|
if row.include?("•")
check_cells_for_future_state
break
else
end_game_print_result
end
end
end
def check_cells_for_future_state
#cell_grid.each_with_index do |row, row_index|
row.each_with_index do |cell, cell_index|
#live_neighbors = 0
add_row_shift = (row_index + 1)
if add_row_shift == #size
add_row_shift = 0
end
add_cell_shift = (cell_index + 1)
if add_cell_shift == #size
add_cell_shift = 0
end
def does_this_include_alive(cell)
if cell.include?("•")
#live_neighbors +=1
end
end
top_left_cell = #cell_grid[(row_index - 1)][(cell_index - 1)]
does_this_include_alive(top_left_cell)
top_cell = #cell_grid[(row_index - 1)][(cell_index)]
does_this_include_alive(top_cell)
top_right_cell = #cell_grid[(row_index - 1)][(add_cell_shift)]
does_this_include_alive(top_right_cell)
right_cell = #cell_grid[(row_index)][(add_cell_shift)]
does_this_include_alive(right_cell)
bottom_right_cell = #cell_grid[(add_row_shift)][(add_cell_shift)]
does_this_include_alive(bottom_right_cell)
bottom_cell = #cell_grid[(add_row_shift)][(cell_index)]
does_this_include_alive(bottom_cell)
bottom_left_cell = #cell_grid[(add_row_shift)][(cell_index - 1)]
does_this_include_alive(bottom_left_cell)
left_cell = #cell_grid[(row_index)][(cell_index - 1)]
does_this_include_alive(left_cell)
if #live_neighbors == 2 || #live_neighbors == 3
#grid_storage[row_index][cell_index] = "•"
else
#grid_storage[row_index][cell_index] = " "
end
end
end
update_cell_grid
end
def update_cell_grid
#cell_grid = #grid_storage
print_cell_grid_and_counter
end
def print_cell_grid_and_counter
system"clear"
#cell_grid.each do |row|
row.each do |cell|
print cell + " "
end
print "\n"
end
#tick_count += 1
print "\n"
print "Days passed: #{#tick_count}"
sleep(0.25)
check_for_any_alive_cells
end
def end_game_print_result
print "#{#tick_count} ticks were played, end of game."
exit
end
end
I couldn't see where your code went wrong. It does have a recursive call which can easily cause strange behavior. Here is what I came up with:
class CellGame
def initialize(size)
#size = size; #archive = []
#grid = Array.new(size) { Array.new(size) { rand(3).zero? } }
end
def lives_on?(row, col)
neighborhood = (-1..1).map { |r| (-1..1).map { |c| #grid[row + r] && #grid[row + r][col + c] } }
its_alive = neighborhood[1].delete_at(1)
neighbors = neighborhood.flatten.count(true)
neighbors == 3 || neighbors == 2 && its_alive
end
def next_gen
(0...#size).map { |row| (0...#size).map { |col| lives_on?(row, col) } }
end
def play
tick = 0; incr = 1
loop do
#archive.include?(#grid) ? incr = 0 : #archive << #grid
sleep(0.5); system "clear"; #grid = next_gen
puts "tick - #{tick += incr}"
puts #grid.map { |row| row.map { |cell| cell ? '*' : ' ' }.inspect }
end
end
end
cg = CellGame.new 10
cg.play
The tick count stops but the program keeps running through the oscillator at the end.
I wanted to revisit this and confidently say I have figured it out! Here is my new solution - still super beginner focused. Hope it helps someone out.
class Game
# Uses constants for values that won't change
LIVE = "🦄"
DEAD = " "
WIDTH = 68
HEIGHT = 34
def initialize
# Sets our grid to a new empty grid (set by method below)
#grid = empty_grid
# Randomly fills our grid with live cells
#grid.each do |row|
# Map will construct our new array, we use map! to edit the #grid
row.map! do |cell|
if rand(10) == 1
LIVE # Place a live cell
else
DEAD # Place a dead cell
end
end
end
# Single line implimentation
# #grid.each {|row|row.map! {|cell|rand(10) == 1 ? LIVE : DEAD}}
loop_cells #start the cycle
end
def empty_grid
Array.new(HEIGHT) do
# Creates an array with HEIGHT number of empty arrays
Array.new(WIDTH) do
# Fills each array with a dead cell WIDTH number of times
DEAD
end
end
# Single line implimentation
# Array.new(HEIGHT){ Array.new(WIDTH) { DEAD } }
end
def print_grid # Prints our grid to the terminal
system "clear" # Clears the terminal window
# Joins cells in each row with an empty space
rows = #grid.map do |row|
row.join(" ")
end
# Print rows joined by a new line
print rows.join("\n")
# Single line implimentation
# print #grid.map{|row| row.join(" ")}.join("\n")
end
def loop_cells
print_grid # Start by printing the current grid
new_grid = empty_grid # Set an empty grid (this will be the next life cycle)
# Loop through every cell in every row
#grid.each_with_index do |row, row_index|
row.each_with_index do |cell, cell_index|
# Find the cells friends
friends = find_friends(row_index, cell_index)
# Apply life or death rules
if cell == LIVE
state = friends.size.between?(2,3)
else
state = friends.size == 3
end
# Set cell in new_grid for the next cycle
new_grid[row_index][cell_index] = state ? LIVE : DEAD
end
end
# Replace grid and start over
#grid = new_grid
start_over
end
def find_friends(row_index, cell_index)
# Ruby can reach backwards through arrays and start over at the end - but it cannot reach forwards. If we're going off the grid, start over at 0
row_fix = true if (row_index + 1) == HEIGHT
cell_fix = true if (cell_index + 1) == WIDTH
# You'll see below I will use 0 if one of these values is truthy when checking cells to the upper right, right, lower right, lower, and lower left.
# Check each neighbor, use 0 if we're reaching too far
friends = [
#grid[(row_index - 1)][(cell_index - 1)],
#grid[(row_index - 1)][(cell_index)],
#grid[(row_index - 1)][(cell_fix ? 0 : cell_index + 1)],
#grid[(row_index)][(cell_fix ? 0 : cell_index + 1)],
#grid[(row_fix ? 0 : row_index + 1)][(cell_fix ? 0 : cell_index + 1)],
#grid[(row_fix ? 0 : row_index + 1)][(cell_index)],
#grid[(row_fix ? 0 : row_index + 1)][(cell_index - 1)],
#grid[(row_index)][(cell_index - 1)]
]
# Maps live neighbors into an array, removes nil values
friends.map{|x| x if x == LIVE}.compact
end
def start_over
sleep 0.1
loop_cells
end
end
# Start game when file is run
Game.new

Resources