This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
FelixMaxwell's profile picture

[1.0.0] Screensavers (Game of Life and Matrix)

Started by FelixMaxwell, 17 April 2013 - 07:25 PM
FelixMaxwell #1
Posted 17 April 2013 - 09:25 PM
Hello there computer craft forums!
This is my first post, so hopefully everything goes off without a hitch.
These are two screensaver programs I wrote over the last day or so as computercraft tests. Presently there is no way to exit them other than ctrl+t, but for a screensaver that should be a relatively minor issue :)/>

But enough talk, on to the content
Game of Life
SpoilerAfter watching https://www.youtube....h?v=m5DUoCiq6Ag I was inspired to write my own simulator for Conway's Game of Life

Code is under CC BY-SA 3.0
http://pastebin.com/YxKq7hqz
Spoiler

--(c) 2013 Felix Maxwell
--License: CC BY-SA 3.0
local fps = 8 --Determines how long the program will wait between each tick
local char = "#" --Live cells will look like this
function getMonitors()
local monitors = {}
if checkMonitorSide( "top" ) then table.insert( monitors, "top" ) end
if checkMonitorSide( "bottom" ) then table.insert( monitors, "bottom" ) end
if checkMonitorSide( "left" ) then table.insert( monitors, "left" ) end
if checkMonitorSide( "right" ) then table.insert( monitors, "right" ) end
if checkMonitorSide( "front" ) then table.insert( monitors, "front" ) end
if checkMonitorSide( "back" ) then table.insert( monitors, "back" ) end
return monitors
end
function checkMonitorSide( side )
if peripheral.isPresent( side ) then
  if peripheral.getType(side) == "monitor" then
   return true
  end
end
return false
end
function printMonitorStats( side )
local x, y = peripheral.call(side, "getSize")
local color = "No"
if peripheral.call(side, "isColor") then
  color = "Yes"
end
print("Side:"..side.." Size:("..x..", "..y..") Color?"..color)
end
function askMonitor()
local monitors = getMonitors()
if #monitors == 0 then
  print("No monitors found, add more!")
  return nill
elseif #monitors == 1 then
  return monitors[1]
else
  while true do
   print("Multiple monitors found, please pick one.")
   for i,v in ipairs(monitors) do
	write("["..(i).."] ")
	printMonitorStats( v )
   end
   write("Selection: ")
   local sel = tonumber(io.read())
   if sel < 1 or sel > #monitors then
	print("")
	print("Invalid number.")
   else
	return monitors[sel]
   end
  end
end
end
function printCharAt( monitor, x, y, char )
monitor.setCursorPos( x, y )
monitor.write( char )
end
function printGrid( monitor, grid )
monitor.clear()
for i=1,#grid do
  for o=1,#grid[i] do
   printCharAt( monitor, i, o, grid[i][o] )
  end
end
end
function getNumNeighborhood( grid, x, y )
local neighbors = 0
if x > 1 then
  if y > 1 then
   if grid[x-1][y-1] == char then neighbors = neighbors + 1 end
  end
  if grid[x-1][y] == char then neighbors = neighbors + 1 end
  if y < #grid[x] then
   if grid[x-1][y+1] == char then neighbors = neighbors + 1 end
  end
end

if y > 1 then
  if grid[x][y-1] == char then neighbors = neighbors + 1 end
end
if y < #grid[x] then
  if grid[x][y+1] == char then neighbors = neighbors + 1 end
end

if x < #grid then
  if y > 1 then
   if grid[x+1][y-1] == char then neighbors = neighbors + 1 end
  end
  if grid[x+1][y] == char then neighbors = neighbors + 1 end
  if y < #grid then
   if grid[x+1][y+1] == char then neighbors = neighbors + 1 end
  end
end

return neighbors
end
function lifeOrDeath( cur, neighbors )
if neighbors < 2 then
  return " "
elseif neighbors > 3 then
  return " "
elseif neighbors == 3 then
  return char
else
  return cur
end
end
function tick( grid )
local retGrid = {}
for x=1,#grid do
  retGrid[x] = {}
  for y=1,#grid[x] do
   local num = getNumNeighborhood( grid, x, y )
   retGrid[x][y] = lifeOrDeath( grid[x][y], num )
  end
end
return retGrid
end
function setup( w, h )
local grid = {}
for i=1,w do
  grid[i] = {}
  for o=1,h do
   if math.random(1, 5) == 1 then
	grid[i][o] = char
   else
	grid[i][o] = " "
   end
  end
end
return grid
end
function run()
local monitor = peripheral.wrap( askMonitor() )
if monitor.isColor() then
  monitor.setTextColor(colors.lime)
  monitor.setBackgroundColor(colors.black)
end
local w, h = monitor.getSize()
local grid = setup( w, h )
while true do
  printGrid( monitor, grid )
  grid = tick( grid )
  os.sleep(1/fps)
end
end
run()
--This one looks kind of cool
--  ###
--#	#
--#	#
--#	#
--
--  ###
Matrix
SpoilerAfter writing the Game of Life, I was inspired by Numerical's screensaver in the video listed in that spoiler, so I decided to see what I could do.
I am rather pleased with the end result.


As always, code is under CC BY-SA 3.0
http://pastebin.com/KQjmtASU
Spoiler

--(c) 2013 Felix Maxwell
--License: CC BY-SA 3.0
local fps = 8 --Determines how long the system will wait between each update
local maxLifetime = 40 --Max lifetime of each char
local minLifetime = 8 --Min lifetime of each char
local maxSourcesPerTick = 5 --Maximum number of sources created each tick
local sourceWeight = 0 --Affects the chance that no sources will be generated
local greenWeight = 8 --Threshhold out of 10 that determines when characters will switch from lime to green
local grayWeight = 2 --Same as about, but from green to gray
function getMonitors()
local monitors = {}
if checkMonitorSide( "top" ) then table.insert( monitors, "top" ) end
if checkMonitorSide( "bottom" ) then table.insert( monitors, "bottom" ) end
if checkMonitorSide( "left" ) then table.insert( monitors, "left" ) end
if checkMonitorSide( "right" ) then table.insert( monitors, "right" ) end
if checkMonitorSide( "front" ) then table.insert( monitors, "front" ) end
if checkMonitorSide( "back" ) then table.insert( monitors, "back" ) end
return monitors
end
function checkMonitorSide( side )
if peripheral.isPresent( side ) then
  if peripheral.getType(side) == "monitor" then
   return true
  end
end
return false
end
function printMonitorStats( side )
local x, y = peripheral.call(side, "getSize")
local color = "No"
if peripheral.call(side, "isColor") then
  color = "Yes"
end
print("Side:"..side.." Size:("..x..", "..y..") Color?"..color)
end
function askMonitor()
local monitors = getMonitors()
if #monitors == 0 then
  print("No monitors found, add more!")
  return nill
elseif #monitors == 1 then
  return monitors[1]
else
  while true do
   print("Multiple monitors found, please pick one.")
   for i,v in ipairs(monitors) do
	write("["..(i).."] ")
	printMonitorStats( v )
   end
   write("Selection: ")
   local sel = tonumber(io.read())
   if sel < 1 or sel > #monitors then
	print("")
	print("Invalid number.")
   else
	return monitors[sel]
   end
  end
end
end
function printCharAt( monitor, x, y, char )
monitor.setCursorPos( x, y )
monitor.write( char )
end
function printGrid( monitor, grid, color )
for i=1,#grid do
  for o=1,#grid[i] do
   if color then monitor.setTextColor( grid[i][o]["color"] ) end
   printCharAt( monitor, i, o, grid[i][o]["char"] )
  end
end
end
function colorLifetime( life, originalLifetime )
local lifetimePart = originalLifetime/10
if life < grayWeight*lifetimePart then
  return colors.gray
elseif life < greenWeight*lifetimePart then
  return colors.green
else
  return colors.lime
end
end
function getRandomChar()
local randTable = {"1","2","3","4","5","6","7","8","9","0","!","@","#","$","%","^","&amp;","*","(",")","_","-","+","=","~","`",",","<",">",".","/","?",":","{","}","[","]","\\","\"","\'"}
return randTable[math.random(1, #randTable)]
end
function tick( screen )
--update lifetimes
for x=1,#screen do
  for y=1,#screen[x] do
   screen[x][y]["curLife"] = screen[x][y]["curLife"] - 1
  end
end
--make the sources 'fall' and delete timed out chars
for x=1,#screen do
  for y=1,#screen[x] do
   if screen[x][y]["type"] == "source" and screen[x][y]["curLife"] == 0 then
	screen[x][y]["type"] = "char"
	screen[x][y]["lifetime"] = math.random(minLifetime, maxLifetime)
	screen[x][y]["curLife"] = screen[x][y]["lifetime"]
	screen[x][y]["color"] = colors.lime

	if y < #screen[x] then
	 screen[x][y+1]["char"] = getRandomChar()
	 screen[x][y+1]["lifetime"] = 1
	 screen[x][y+1]["curLife"] = 1
	 screen[x][y+1]["type"] = "source"
	 screen[x][y+1]["color"] = colors.white
	end
   elseif screen[x][y]["curLife"] < 0 then
	screen[x][y]["char"] = " "
	screen[x][y]["lifetime"] = 0
	screen[x][y]["curLife"] = 0
	screen[x][y]["type"] = "blank"
	screen[x][y]["color"] = colors.black
   elseif screen[x][y]["type"] == "char" then
	screen[x][y]["color"] = colorLifetime( screen[x][y]["curLife"], screen[x][y]["lifetime"] )
   end
  end
end

--create new character sources
local newSources = math.random( 0-sourceWeight, maxSourcesPerTick )
for i=1,newSources do
  local col = math.random(1, #screen)
  screen[col][1]["char"] = getRandomChar()
  screen[col][1]["lifetime"] = 1
  screen[col][1]["curLife"] = 1
  screen[col][1]["type"] = "source"
  screen[col][1]["color"] = colors.white
end

return screen
end
function setup( w, h )
local retTab = {}
for x=1,w do
  retTab[x] = {}
  for y=1,h do
   retTab[x][y] = {}
   retTab[x][y]["char"] = " "
   retTab[x][y]["lifetime"] = 0
   retTab[x][y]["curLife"] = 0
   retTab[x][y]["type"] = "blank"
   retTab[x][y]["color"] = colors.black
  end
end
return retTab
end
function run()
local monitor = peripheral.wrap( askMonitor() )
local color = monitor.isColor()
local w, h = monitor.getSize()
local screen = setup( w, h )
while true do
  screen = tick( screen )
  printGrid( monitor, screen, color )
  os.sleep(1/fps)
end
end
run()
oeed #2
Posted 17 April 2013 - 09:31 PM
These are really nice! How close is the game of life to the original version?
superaxander #3
Posted 17 April 2013 - 09:36 PM
Those are very good looking
Shnupbups #4
Posted 17 April 2013 - 09:42 PM
Good job! I was working on Matrix for my screensaver program too…
FelixMaxwell #5
Posted 17 April 2013 - 10:07 PM
These are really nice! How close is the game of life to the original version?

Rule wise it should be an exact simulation of the original rules, though the board of course is not infinite.
If you mean implementation, I belive Conway used the pieces from the game Go, so not very much in that respect.
oeed #6
Posted 18 April 2013 - 12:54 AM
Hmmm… I might take a look at this again later. I'm thinking of making a Powder Toy-esque game, and from what I've heard it uses a GoL system.
BigSHinyToys #7
Posted 18 April 2013 - 01:28 AM
Great screen savers. The matrix one is great. + 1
If you are having flickering problems then edit out line 69 monitor.clear()
BitLooter #8
Posted 18 April 2013 - 05:13 AM
I was just looking for something exactly like this. I'm going to have to build some advanced monitors just to run the Matrix 24/7.
FelixMaxwell #9
Posted 18 April 2013 - 06:49 AM
Hmmm… I might take a look at this again later. I'm thinking of making a Powder Toy-esque game, and from what I've heard it uses a GoL system.
Yes, most of them are cellular automata based.
Come to think, minecraft is partly cellular automata based.
FelixMaxwell #10
Posted 18 April 2013 - 06:54 AM
Great screen savers. The matrix one is great. + 1
If you are having flickering problems then edit out line 69 monitor.clear()
Ah! Thank you very much, I was wondering what was causing that.
The matrix file has been updated to include this fix, so hopefully it won't flicker on large monitors now
BigSHinyToys #11
Posted 18 April 2013 - 07:27 AM
Great screen savers. The matrix one is great. + 1
If you are having flickering problems then edit out line 69 monitor.clear()
Ah! Thank you very much, I was wondering what was causing that.
The matrix file has been updated to include this fix, so hopefully it won't flicker on large monitors now
The time between clearing the screen and writing the characters it is black, this looks like a flicker in active program. not clearing the screen and just drawing the new characters over the last ones means that the old character stays on until overwritten no black flicker I had this problem on other program that I had written that used complex UI's . It is more optimization than bug fix.
ElectricOverride #12
Posted 18 April 2013 - 10:47 AM
Hmmm… I might take a look at this again later. I'm thinking of making a Powder Toy-esque game, and from what I've heard it uses a GoL system.
Please do! That would be amazing!!
TheOddByte #13
Posted 18 April 2013 - 10:58 AM
I really think that the matrix one looks awesome.. But I'm kinda going to be stupid not knowing this but what is 'Game of Life' ?
And does this really look alot like it?
FelixMaxwell #14
Posted 18 April 2013 - 12:14 PM
I really think that the matrix one looks awesome.. But I'm kinda going to be stupid not knowing this but what is 'Game of Life' ?
And does this really look alot like it?
http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
Sariaz #15
Posted 18 April 2013 - 07:25 PM
Love the matrix one looks just like one I made same colors and everything :P/>. Only real difference is different approach which only leads to slightly different style. Both are colorful matrix screen savers, so obviously both are awesome I mean its the matrix people it couldn't be anything less :P/>.
BigSHinyToys #16
Posted 18 April 2013 - 09:52 PM
SO modifying matrix to use term and selecting multiple monitors with Monitor redirect controll - run many screens at ounce
results :
Spoiler
Sariaz #17
Posted 19 April 2013 - 05:16 AM
SO modifying matrix to use term and selecting multiple monitors with Monitor redirect controll - run many screens at ounce
results :
Spoiler

Nice