Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,54 +1,54 @@
import std.stdio, std.random, std.string, std.algorithm;
enum TREE_PROB = 0.55; // original tree probability
enum F_PROB = 0.01; // auto combustion probability
enum P_PROB = 0.01; // tree creation probability
enum treeProb = 0.55; // Original tree probability.
enum fProb = 0.01; // Auto combustion probability.
enum cProb = 0.01; // Tree creation probability.
enum Cell : char { empty=' ', tree='T', fire='#' }
alias Cell[][] World;
alias World = Cell[][];
bool hasBurningNeighbours(in World world, in int r, in int c)
pure nothrow {
foreach (rowShift; -1 .. 2)
foreach (colShift; -1 .. 2)
if ((r + rowShift) >= 0 && (r + rowShift) < world.length &&
(c + colShift) >= 0 && (c + colShift) < world[0].length &&
world[r + rowShift][c + colShift] == Cell.fire)
return true;
return false;
pure nothrow @safe @nogc {
foreach (immutable rowShift; -1 .. 2)
foreach (immutable colShift; -1 .. 2)
if ((r + rowShift) >= 0 && (r + rowShift) < world.length &&
(c + colShift) >= 0 && (c + colShift) < world[0].length &&
world[r + rowShift][c + colShift] == Cell.fire)
return true;
return false;
}
void nextState(in World world, World nextWorld) {
foreach (r, row; world)
foreach (c, elem; row)
final switch (elem) {
case Cell.empty:
nextWorld[r][c]= uniform(0.,1.)<P_PROB?Cell.tree:Cell.empty;
break;
void nextState(in World world, World nextWorld) /*nothrow*/ @safe /*@nogc*/ {
foreach (immutable r, const row; world)
foreach (immutable c, immutable elem; row)
final switch (elem) with (Cell) {
case empty:
nextWorld[r][c]= (uniform01 < cProb) ? tree : empty;
break;
case Cell.tree:
if (world.hasBurningNeighbours(r, c))
nextWorld[r][c] = Cell.fire;
else
nextWorld[r][c]=uniform(0.,1.)<F_PROB?Cell.fire:Cell.tree;
break;
case tree:
if (world.hasBurningNeighbours(r, c))
nextWorld[r][c] = fire;
else
nextWorld[r][c] = (uniform01 < fProb) ? fire : tree;
break;
case Cell.fire:
nextWorld[r][c] = Cell.empty;
break;
}
case fire:
nextWorld[r][c] = empty;
break;
}
}
void main() {
auto world = new World(8, 65);
foreach (row; world)
foreach (ref el; row)
el = uniform(0.0, 1.0) < TREE_PROB ? Cell.tree : Cell.empty;
auto nextWorld = new World(world.length, world[0].length);
void main() @safe {
auto world = new World(8, 65);
foreach (row; world)
foreach (ref el; row)
el = (uniform01 < treeProb) ? Cell.tree : Cell.empty;
auto nextWorld = new World(world.length, world[0].length);
foreach (i; 0 .. 4) {
nextState(world, nextWorld);
writeln(join(cast(string[])nextWorld, "\n"), "\n");
swap(world, nextWorld);
}
foreach (immutable i; 0 .. 4) {
nextState(world, nextWorld);
writefln("%(%(%c%)\n%)\n", nextWorld);
world.swap(nextWorld);
}
}

View file

@ -15,7 +15,6 @@ immutable white = Color(255, 255, 255),
void nextState(ref World world, ref World nextWorld,
ref Xorshift rnd, Image img) {
enum double div = typeof(rnd.front).max;
immutable nr = world.length;
immutable nc = world[0].length;
foreach (immutable r, const row; world)
@ -23,8 +22,7 @@ void nextState(ref World world, ref World nextWorld,
START: final switch (elem) with (Cell) {
case empty:
img.putPixel(c, r, white);
nextWorld[r][c] = (rnd.front / div) < P_PROB ? tree : empty;
rnd.popFront;
nextWorld[r][c] = rnd.uniform01 < P_PROB ? tree : empty;
break;
case tree:
@ -39,8 +37,7 @@ void nextState(ref World world, ref World nextWorld,
break START;
}
nextWorld[r][c]= (rnd.front / div) < F_PROB ? burning : tree;
rnd.popFront;
nextWorld[r][c]= rnd.uniform01 < F_PROB ? burning : tree;
break;
case burning:
@ -57,7 +54,7 @@ void main() {
auto world = new World(worldSide);
foreach (ref row; world)
foreach (ref el; row)
el = uniform(0.0, 1.0, rnd) < TREE_PROB ? Cell.tree : Cell.empty;
el = rnd.uniform01 < TREE_PROB ? Cell.tree : Cell.empty;
auto nextWorld = new World(world[0].length);
auto w= new SimpleWindow(world.length,world[0].length,"ForestFire");

View file

@ -0,0 +1,97 @@
-- ForestFire automaton implementation
-- Rules: at each step:
-- 1) a burning tree disappears
-- 2) a non-burning tree starts burning if any of its neighbours is
-- 3) an empty spot may generate a tree with prob P
-- 4) a non-burning tree may ignite with prob F
local socket = require 'socket' -- needed for socket.sleep
local curses = require 'curses'
local p_spawn, p_ignite = 0.005, 0.0002
local naptime = 0.03 -- seconds
local forest_x, forest_y = 60, 30
local forest = (function (x, y)
local wrl = {}
for i = 1, y do
wrl[i] = {}
for j = 1, x do
local rand = math.random()
wrl[i][j] = (rand < 0.5) and 1 or 0
end
end
return wrl
end)(forest_x, forest_y)
math.randomseed(os.time())
forest.step = function (self)
for i = 1, #self do
for j = 1, #self[i] do
if self[i][j] == 0 then
if math.random() < p_spawn then self[i][j] = 1 end
elseif self[i][j] == 1 then
if self:ignite(i, j) or math.random() < p_ignite then self[i][j] = 2 end
elseif self[i][j] == 2 then self[i][j] = 0
else error("Error: forest[" .. i .. "][" .. j .. "] is " .. self[i][j] .. "!")
end
end
end
end
forest.draw = function (self)
for i = 1, #self do
for j = 1, #self[i] do
if self[i][j] == 0 then win:mvaddch(i,j," ")
elseif self[i][j] == 1 then
win:attron(curses.color_pair(1))
win:mvaddch(i,j,"Y")
win:attroff(curses.color_pair(1))
elseif self[i][j] == 2 then
win:attron(curses.color_pair(2))
win:mvaddch(i,j,"#")
win:attroff(curses.color_pair(2))
else error("self[" .. i .. "][" .. j .. "] is " .. self[i][j] .. "!")
end
end
end
end
forest.ignite = function (self, i, j)
for k = i - 1, i + 1 do
if k < 1 or k > #self then goto continue1 end
for l = j - 1, j + 1 do
if l < 1 or
l > #self[i] or
math.abs((k - i) + (l - j)) ~= 1
then
goto continue2
end
if self[k][l] == 2 then return true end
::continue2::
end
::continue1::
end
return false
end
local it = 1
curses.initscr()
curses.start_color()
curses.echo(false)
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
win = curses.newwin(forest_y + 2, forest_x, 0, 0)
win:clear()
win:mvaddstr(forest_y + 1, 0, "p_spawn = " .. p_spawn .. ", p_ignite = " .. p_ignite)
repeat
forest:draw()
win:move(forest_y, 0)
win:clrtoeol()
win:addstr("Iteration: " .. it .. ", nap = " .. naptime*1000 .. "ms")
win:refresh()
forest:step()
it = it + 1
socket.sleep(naptime)
until false

View file

@ -1,16 +1,19 @@
constant RED = "\e[1;31m";
constant CLEAR = "\e[0m";
my $RED = "\e[1;31m";
my $YELLOW = "\e[1;33m";
my $GREEN = "\e[1;32m";
my $CLEAR = "\e[0m";
enum Cell-State <Empty Tree Burning>;
my @show = (' ', '', RED ~ '' ~ CLEAR);
enum Cell-State <Empty Tree Heating Burning>;
my @show = (' ', $GREEN ~ '', $YELLOW ~ '', $RED ~ '');
class Forest {
has Cell-State @!grid;
has @!grid;
has @!neighbors;
has Int $.height;
has Int $.width;
has $.p;
has $.f;
has @!cells = ^$!height X ^$!width;
method new(Int $height, Int $width, $p=0.01, $f=0.001) {
my $c = self.bless(:$height, :$width, :$p, :$f);
@ -24,36 +27,35 @@ class Forest {
}
method !init-neighbors {
for ^$!height X ^$!width -> $i, $j {
@!neighbors[$i][$j] = gather for
for @!cells -> $i, $j {
@!neighbors[$i][$j] = eager gather for
[-1,-1],[+0,-1],[+1,-1],
[-1,+0],( ),[+1,+0],
[-1,+1],[+0,+1],[+1,+1]
{
take-rw @!grid[$i + .[0]][$j + .[1]] // next;
}
}
}
}
method step {
my @new;
for ^$!height X ^$!width -> $i, $j {
my @heat;
for @!cells -> $i, $j {
given @!grid[$i][$j] {
when Empty { @new[$i][$j] = rand < $!p ?? Tree !! Empty }
when Tree { @new[$i][$j] =
(@!neighbors[$i][$j].any === Burning or rand < $!f) ?? Burning !! Tree;
}
when Burning { @new[$i][$j] = Empty }
when Empty { @!grid[$i][$j] = rand < $!p ?? Tree !! Empty }
when Tree { @!grid[$i][$j] = rand < $!f ?? Heating !! Tree }
when Heating { @!grid[$i][$j] = Burning; push @heat, $i, $j; }
when Burning { @!grid[$i][$j] = Empty }
}
}
for ^$!height X ^$!width -> $i, $j {
@!grid[$i][$j] = @new[$i][$j];
}
for @heat -> $i,$j {
$_ = Heating for @!neighbors[$i][$j].grep(Tree);
}
}
method Str {
join '', gather for ^$!height -> $i {
take @show[@!grid[$i].list], "\n";
method show {
for ^$!height -> $i {
say @show[@!grid[$i].list].join;
}
}
}
@ -64,7 +66,7 @@ print "\e[2J"; # ANSI clear screen
my $i = 0;
loop {
print "\e[H"; # ANSI home
say $i++;
say $f.Str;
say $CLEAR, $i++;
$f.show;
$f.step;
}

View file

@ -3,64 +3,60 @@
full version has many more options and enhanced displays.
*/
signal on syntax; signal on novalue /*handle REXX program errors. */
signal on halt /*handle cell growth interruptus.*/
parse arg peeps '(' generations rows cols bare! life! clearscreen every
@abc='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU
signal on halt /*handle growth interruptus. */
_= /*(below) nullify some options. */
parse var _ generations rows cols birth lightning bare! fire! tree!,
randseed clearscreen every
if randseed\=='' then call random ,,randseed
percent = 100 /*handy-dandy constant for using%*/
field = percent**2 /*size of the probability field. */
blank = 'BLANK'
generations = p(generations 100)
rows = p(rows 3)
cols = p(cols 3)
rows = p(rows word(scrsize(),1)-2)
cols = p(cols max(79,linesize())-1)
bare! = pickchar(bare! blank)
clearscreen = p(clearscreen 0)
fire! = pickchar(fire! '')
tree! = pickchar(tree! '18'x)
clearscreen = p(clearscreen 1)
every = p(every 999999999)
life! = pickchar(life! '')
fents=max(79,cols) /*fence width shown after display*/
$.=bare! /*the universe is new, and barren*/
birth = p(strip(birth,,'%') 50 )*percent
lightning = p(strip(lightning,,'%') 1/8)*percent
$.=bare! /*the forest is a treeless field.*/
@.=bare! /*also, the alternate universe. */
gens=abs(generations) /*use this for convenience. */
x=space(peeps) /*remove superfluous spaces. */
if x=='' then x='2,1 2,2 2,3'
do while x \==''
parse var x p x; parse var p r ',' c .; $.r=overlay(life!,$.r,c+1)
end
life=0; !.=0; call showCells /*show initial state of the cells*/
/*─────────────────────────────────────watch cell colony grow/live/die. */
do life=1 for gens
do r=1 for rows; rank=bare!
do c=2 for cols; ?=substr($.r,c,1); ??=?; n=neighbors()
select /*select da quickest choice first*/
when ?==bare! then if n==3 then ??=life!
otherwise if n<2 | n>3 then ??=bare!
end /*select*/
/*═════════════════════════════════════watch the forest grow and/or burn*/
do life=1 for gens /*process a forest life cycle. */
do r=1 for rows; rank=bare!
do c=2 for cols; ?=substr($.r,c,1); ??=?
select /*select da quickest choice first*/
when ?==tree! then if ignite?() then ??=fire!
when ?==bare! then if random(1,field)<=birth then ??=tree!
otherwise /*fire*/ ??=bare!
end /*select*/
rank=rank || ??
end /*c*/
end /*c*/ /*ignore column 1, start with 2.*/
@.r=rank
end /*c*/
end /*r*/
do r=1 for rows; $.r=@.r; end /*assign alternate cells ──► real*/
if life//every==0 | generations>0 | life==gens then call showCells
end /*life*/
/*─────────────────────────────────────stop watching the universe (life)*/
do r=1 for rows; $.r=@.r; end /*assign alternate cells ──► real*/
if life//every==0 | generations>0 | life==gens then call showForest
end /*life*/
/*═════════════════════════════════════stop watching the forest grow. */
halt: cycles=life-1; if cycles\==gens then say 'REXX program interrupted.'
exit /*stick a fork in it, we're done.*/
/*───────────────────────────────SHOWCELLS subroutine─-─────────────────*/
showCells: if clearscreen then 'CLS' /* ◄─── change this for your OS.*/
_=; do r=rows by -1 for rows /*show the forest in proper order*/
z=strip(substr($.r,2),'T') /*pick off the meat of the row. */
say z; _=_ || z /*be neat about trailing blanks. */
/*───────────────────────────────SHOWFOREST subroutine──────────────────*/
showForest: if clearscreen then 'CLS' /* ◄─── change this for your OS.*/
do r=rows by -1 for rows /*show the forest in proper order*/
say strip(substr($.r,2),'T') /*be neat about trailing blanks. */
end /*r*/
say right(copies('',fents)life,fents) /*show&tell for a stand of trees.*/
if _=='' then exit /*if no life, then stop the run. */
if !._ then do; say 'repeating ...'; exit; end
!._=1 /*assign a state & compare later.*/
say right(copies('',cols)life, cols) /*show&tell for a stand of trees.*/
return
/*───────────────────────────────NEIGHBORS subroutine───────────────────*/
neighbors: rp=r+1; cp=c+1; rm=r-1; cm=c-1 /*count 8 neighbors of a cell*/
return (substr($.rm,cm,1)==life!) + (substr($.rm,c ,1)==life!) + ,
(substr($.rm,cp,1)==life!) + (substr($.r ,cm,1)==life!) + ,
(substr($.r ,cp,1)==life!) + (substr($.rp,cm,1)==life!) + ,
(substr($.rp,c ,1)==life!) + (substr($.rp,cp,1)==life!)
/*───────────────────────────────1-liner subroutines────────────────────*/
/*──────────────────────────────────IGNITE? subroutine──────────────────*/
ignite?: if substr($.r,c+1,1)==fire! then return 1 /*east on fire ?*/
if substr($.r,c-1,1)==fire! then return 1; rp=r+1; rm=r-1
cm=c-1; if pos(fire!,substr($.rm,cm,3)substr($.rp,cm,3))\==0 then return 1
return random(1,field) <= lightning
/*───────────────────────────────1─liner subroutines─────────────────────────────────────────────────────────────────────────────────*/
err: say;say;say center(' error! ',max(40,linesize()%2),"*");say;do j=1 for arg();say arg(j);say;end;say;exit 13
novalue: syntax: call err 'REXX program' condition('C') "error",condition('D'),'REXX source statement (line' sigl"):",sourceline(sigl)
pickchar: _=p(arg(1));if translate(_)==blank then _=' ';if length(_) ==3 then _=d2c(_);if length(_) ==2 then _=x2c(_);return _

View file

@ -1,60 +1,44 @@
require 'enumerator'
class Forest_Fire
Neighborhood = [-1,0,1].product([-1,0,1]) - [0,0]
States = {empty:" ", tree:"T", fire:"#"}
def transition arr, tree_prob, fire_prob
arr.enum_with_index.map do |cell, i|
if i == 0 or i == arr.length - 1
# boundary conditions: cells are always empty here
:empty
else
case cell
when :fire
# burning cells become empty
:empty
when :empty
# empty cells grow a tree with probability tree_prob
rand < tree_prob ? :tree : :empty
when :tree
# check my neighbouring cells, are they on fire?
if arr[i - 1] == :fire or arr[i + 1] == :fire
:fire
def initialize(xsize, ysize=xsize, p=0.5, f=0.01)
@xsize, @ysize, @p, @f = xsize, ysize, p, f
@field = Array.new(xsize+1) {|i| Array.new(ysize+1, :empty)}
@generation = 0
end
def evolve
@generation += 1
work = @field.map{|row| row.map{|cell| cell}}
for i in 0...@xsize
for j in 0...@ysize
case cell=@field[i][j]
when :empty
cell = :tree if rand < @p
when :tree
cell = :fire if fire?(i,j)
else
# neighbours not on fire, but catch fire at random
rand < fire_prob ? :fire : :tree
cell = :empty
end
work[i][j] = cell
end
end
@field = work
end
def fire?(i,j)
rand < @f or Neighborhood.any? {|di,dj| @field[i+di][j+dj] == :fire}
end
def display
puts "Generation : #@generation"
puts @xsize.times.map{|i| @ysize.times.map{|j| States[@field[i][j]]}.join}
end
end
def pretty_print arr
# colour the trees green, the fires red, and the empty spaces black
print(arr.map { |cell|
"\e[3" +
case cell
when :tree
"2mT"
when :fire
"1mF"
when :empty
"0m "
end + "\e[0m"
}.join)
forest = Forest_Fire.new(10,30)
10.times do |i|
forest.evolve
forest.display
end
N = 20 # 20 trees
P = 0.5 # probability of growing a tree
F = 0.1 # probability of catching on fire
srand Time.now.to_i
# each cell has a 50/50 chance of being a tree
array = (1..N).map { rand < 0.5 ? :tree : :empty }
array[0] = array[-1] = :empty # boundary conditions
pretty_print array
puts
begin
array = transition(array, P, F)
pretty_print array
end while gets.chomp.downcase != "q"