2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,11 +1,12 @@
|
|||
{{omit from|GUISS}}
|
||||
|
||||
[[wp:Wireworld|Wireworld]] is a cellular automaton with some similarities to [[Conway's Game of Life]].
|
||||
|
||||
It is capable of doing sophisticated computations with appropriate programs
|
||||
(it is actually [[wp:Turing-complete|Turing complete]]),
|
||||
and is much simpler to program for.
|
||||
|
||||
A wireworld arena consists of a cartesian grid of cells,
|
||||
A Wireworld arena consists of a Cartesian grid of cells,
|
||||
each of which can be in one of four states.
|
||||
All cell transitions happen simultaneously.
|
||||
|
||||
|
|
@ -37,7 +38,9 @@ The cell transition rules are this:
|
|||
| otherwise
|
||||
|}
|
||||
|
||||
To implement this task, create a program that reads a wireworld program from a file and displays an animation of the processing. Here is a sample description file (using "<tt>H</tt>" for an electron head, "<tt>t</tt>" for a tail, "<tt>.</tt>" for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate:
|
||||
|
||||
;Task:
|
||||
Create a program that reads a Wireworld program from a file and displays an animation of the processing. Here is a sample description file (using "<tt>H</tt>" for an electron head, "<tt>t</tt>" for a tail, "<tt>.</tt>" for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate:
|
||||
<pre>
|
||||
tH.........
|
||||
. .
|
||||
|
|
@ -46,3 +49,4 @@ tH.........
|
|||
Ht.. ......
|
||||
</pre>
|
||||
While text-only implementations of this task are possible, mapping cells to pixels is advisable if you wish to be able to display large designs. The logic is not significantly more complex.
|
||||
<br><br>
|
||||
|
|
|
|||
84
Task/Wireworld/Elixir/wireworld.elixir
Normal file
84
Task/Wireworld/Elixir/wireworld.elixir
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
defmodule Wireworld do
|
||||
@empty " "
|
||||
@head "H"
|
||||
@tail "t"
|
||||
@conductor "."
|
||||
@neighbours (for x<- -1..1, y <- -1..1, do: {x,y}) -- [{0,0}]
|
||||
|
||||
def set_up(string) do
|
||||
lines = String.split(string, "\n", trim: true)
|
||||
grid = Enum.with_index(lines)
|
||||
|> Enum.flat_map(fn {line,i} ->
|
||||
String.codepoints(line)
|
||||
|> Enum.with_index
|
||||
|> Enum.map(fn {char,j} -> {{i, j}, char} end)
|
||||
end)
|
||||
|> Enum.into(Map.new)
|
||||
width = Enum.map(lines, fn line -> String.length(line) end) |> Enum.max
|
||||
height = length(lines)
|
||||
{grid, width, height}
|
||||
end
|
||||
|
||||
# to string
|
||||
defp to_s(grid, width, height) do
|
||||
Enum.map_join(0..height-1, fn i ->
|
||||
Enum.map_join(0..width-1, fn j -> Map.get(grid, {i,j}, @empty) end) <> "\n"
|
||||
end)
|
||||
end
|
||||
|
||||
# transition all cells simultaneously
|
||||
defp transition(grid) do
|
||||
Enum.into(grid, Map.new, fn {{x, y}, state} ->
|
||||
{{x, y}, transition_cell(grid, state, x, y)}
|
||||
end)
|
||||
end
|
||||
|
||||
# how to transition a single cell
|
||||
defp transition_cell(grid, current, x, y) do
|
||||
case current do
|
||||
@empty -> @empty
|
||||
@head -> @tail
|
||||
@tail -> @conductor
|
||||
_ -> if neighbours_with_state(grid, x, y) in 1..2, do: @head, else: @conductor
|
||||
end
|
||||
end
|
||||
|
||||
# given a position in the grid, find the neighbour cells with a particular state
|
||||
def neighbours_with_state(grid, x, y) do
|
||||
Enum.count(@neighbours, fn {dx,dy} -> Map.get(grid, {x+dx, y+dy}) == @head end)
|
||||
end
|
||||
|
||||
# run a simulation up to a limit of transitions, or until a recurring
|
||||
# pattern is found
|
||||
# This will print text to the console
|
||||
def run(string, iterations\\25) do
|
||||
{grid, width, height} = set_up(string)
|
||||
Enum.reduce(0..iterations, {grid, %{}}, fn count,{grd, seen} ->
|
||||
IO.puts "Generation : #{count}"
|
||||
IO.puts to_s(grd, width, height)
|
||||
|
||||
if seen[grd] do
|
||||
IO.puts "I've seen this grid before... after #{count} iterations"
|
||||
exit(:normal)
|
||||
else
|
||||
{transition(grd), Map.put(seen, grd, count)}
|
||||
end
|
||||
end)
|
||||
IO.puts "ran through #{iterations} iterations"
|
||||
end
|
||||
end
|
||||
|
||||
# this is the "2 Clock generators and an XOR gate" example from the wikipedia page
|
||||
text = """
|
||||
......tH
|
||||
. ......
|
||||
...Ht... .
|
||||
....
|
||||
. .....
|
||||
....
|
||||
tH...... .
|
||||
. ......
|
||||
...Ht...
|
||||
"""
|
||||
|
||||
Wireworld.run(text)
|
||||
99
Task/Wireworld/GML/wireworld-1.gml
Normal file
99
Task/Wireworld/GML/wireworld-1.gml
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
//Create event
|
||||
/*
|
||||
Wireworld first declares constants and then reads a wireworld from a textfile.
|
||||
In order to implement wireworld in GML a single array is used.
|
||||
To make it behave properly, there need to be states that are 'in-between' two states:
|
||||
0 = empty
|
||||
1 = conductor from previous state
|
||||
2 = electronhead from previous state
|
||||
5 = electronhead that was a conductor in the previous state
|
||||
3 = electrontail from previous state
|
||||
4 = electrontail that was a head in the previous state
|
||||
*/
|
||||
empty = 0;
|
||||
conduc = 1;
|
||||
eHead = 2;
|
||||
eTail = 3;
|
||||
eHead_to_eTail = 4;
|
||||
coduc_to_eHead = 5;
|
||||
working = true;//not currently used, but setting it to false stops wireworld. (can be used to pause)
|
||||
toroidalMode = false;
|
||||
factor = 3;//this is used for the display. 3 means a single pixel is multiplied by three in size.
|
||||
|
||||
var tempx,tempy ,fileid, tempstring, gridid, listid, maxwidth, stringlength;
|
||||
tempx = 0;
|
||||
tempy = 0;
|
||||
tempstring = "";
|
||||
maxwidth = 0;
|
||||
|
||||
//the next piece of code loads the textfile containing a wireworld.
|
||||
//the program will not work correctly if there is no textfile.
|
||||
if file_exists("WW.txt")
|
||||
{
|
||||
fileid = file_text_open_read("WW.txt");
|
||||
gridid = ds_grid_create(0,0);
|
||||
listid = ds_list_create();
|
||||
while !file_text_eof(fileid)
|
||||
{
|
||||
tempstring = file_text_read_string(fileid);
|
||||
stringlength = string_length(tempstring);
|
||||
ds_list_add(listid,stringlength);
|
||||
if maxwidth < stringlength
|
||||
{
|
||||
ds_grid_resize(gridid,stringlength,ds_grid_height(gridid) + 1)
|
||||
maxwidth = stringlength
|
||||
}
|
||||
else
|
||||
{
|
||||
ds_grid_resize(gridid,maxwidth,ds_grid_height(gridid) + 1)
|
||||
}
|
||||
|
||||
for (i = 1; i <= stringlength; i +=1)
|
||||
{
|
||||
switch (string_char_at(tempstring,i))
|
||||
{
|
||||
case ' ': ds_grid_set(gridid,tempx,tempy,empty); break;
|
||||
case '.': ds_grid_set(gridid,tempx,tempy,conduc); break;
|
||||
case 'H': ds_grid_set(gridid,tempx,tempy,eHead); break;
|
||||
case 't': ds_grid_set(gridid,tempx,tempy,eTail); break;
|
||||
default: break;
|
||||
}
|
||||
tempx += 1;
|
||||
}
|
||||
file_text_readln(fileid);
|
||||
tempy += 1;
|
||||
tempx = 0;
|
||||
}
|
||||
file_text_close(fileid);
|
||||
//fill the 'open' parts of the grid
|
||||
tempy = 0;
|
||||
repeat(ds_list_size(listid))
|
||||
{
|
||||
tempx = ds_list_find_value(listid,tempy);
|
||||
repeat(maxwidth - tempx)
|
||||
{
|
||||
ds_grid_set(gridid,tempx,tempy,empty);
|
||||
tempx += 1;
|
||||
}
|
||||
tempy += 1;
|
||||
}
|
||||
boardwidth = ds_grid_width(gridid);
|
||||
boardheight = ds_grid_height(gridid);
|
||||
//the contents of the grid are put in a array, because arrays are faster.
|
||||
//the grid was needed because arrays cannot be resized properly.
|
||||
tempx = 0;
|
||||
tempy = 0;
|
||||
repeat(boardheight)
|
||||
{
|
||||
repeat(boardwidth)
|
||||
{
|
||||
board[tempx,tempy] = ds_grid_get(gridid,tempx,tempy);
|
||||
tempx += 1;
|
||||
}
|
||||
tempy += 1;
|
||||
tempx = 0;
|
||||
}
|
||||
//the following code clears memory
|
||||
ds_grid_destroy(gridid);
|
||||
ds_list_destroy(listid);
|
||||
}
|
||||
218
Task/Wireworld/GML/wireworld-2.gml
Normal file
218
Task/Wireworld/GML/wireworld-2.gml
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//Step event
|
||||
/*
|
||||
This step event executes each 1/speed seconds.
|
||||
It checks everything on the board using an x and a y through two repeat loops.
|
||||
The variables westN,northN,eastN,southN, resemble the space left, up, right and down respectively,
|
||||
seen from the current x & y.
|
||||
1 -> 5 (conductor is changing to head)
|
||||
2 -> 4 (head is changing to tail)
|
||||
3 -> 1 (tail became conductor)
|
||||
*/
|
||||
|
||||
var tempx,tempy,assignhold,westN,northN,eastN,southN,neighbouringHeads,T;
|
||||
tempx = 0;
|
||||
tempy = 0;
|
||||
westN = 0;
|
||||
northN = 0;
|
||||
eastN = 0;
|
||||
southN = 0;
|
||||
neighbouringHeads = 0;
|
||||
T = 0;
|
||||
|
||||
if working = 1
|
||||
{
|
||||
repeat(boardheight)
|
||||
{
|
||||
repeat(boardwidth)
|
||||
{
|
||||
switch board[tempx,tempy]
|
||||
{
|
||||
case empty: assignhold = empty; break;
|
||||
case conduc:
|
||||
neighbouringHeads = 0;
|
||||
if toroidalMode = true //this is disabled, but otherwise lets wireworld behave toroidal.
|
||||
{
|
||||
if tempx=0
|
||||
{
|
||||
westN = boardwidth -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
westN = tempx-1;
|
||||
}
|
||||
if tempy=0
|
||||
{
|
||||
northN = boardheight -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
northN = tempy-1;
|
||||
}
|
||||
if tempx=boardwidth -1
|
||||
{
|
||||
eastN = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
eastN = tempx+1;
|
||||
}
|
||||
if tempy=boardheight -1
|
||||
{
|
||||
southN = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
southN = tempy+1;
|
||||
}
|
||||
|
||||
T=board[westN,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[tempx,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[eastN,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[westN,tempy];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[eastN,tempy];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[westN,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[tempx,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
T=board[eastN,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
else//this is the default mode that works for the provided example.
|
||||
{//the next code checks whether coordinates fall outside the array borders.
|
||||
//and counts all the neighbouring electronheads.
|
||||
if tempx=0
|
||||
{
|
||||
westN = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
westN = tempx - 1;
|
||||
T=board[westN,tempy];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if tempy=0
|
||||
{
|
||||
northN = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
northN = tempy - 1;
|
||||
T=board[tempx,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if tempx = boardwidth -1
|
||||
{
|
||||
eastN = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
eastN = tempx + 1;
|
||||
T=board[eastN,tempy];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if tempy = boardheight -1
|
||||
{
|
||||
southN = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
southN = tempy + 1;
|
||||
T=board[tempx,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if westN != -1 and northN != -1
|
||||
{
|
||||
T=board[westN,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if eastN != -1 and northN != -1
|
||||
{
|
||||
T=board[eastN,northN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if westN != -1 and southN != -1
|
||||
{
|
||||
T=board[westN,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
if eastN != -1 and southN != -1
|
||||
{
|
||||
T=board[eastN,southN];
|
||||
if T=eHead or T=eHead_to_eTail
|
||||
{
|
||||
neighbouringHeads += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if neighbouringHeads = 1 or neighbouringHeads = 2
|
||||
{
|
||||
assignhold = coduc_to_eHead;
|
||||
}
|
||||
else
|
||||
{
|
||||
assignhold = conduc;
|
||||
}
|
||||
break;
|
||||
|
||||
case eHead: assignhold = eHead_to_eTail; break;
|
||||
case eTail: assignhold = conduc; break;
|
||||
default: break;
|
||||
}
|
||||
board[tempx,tempy] = assignhold;
|
||||
tempx += 1;
|
||||
}
|
||||
tempy += 1;
|
||||
tempx = 0;
|
||||
}
|
||||
}
|
||||
62
Task/Wireworld/GML/wireworld-3.gml
Normal file
62
Task/Wireworld/GML/wireworld-3.gml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
//Draw event
|
||||
/*
|
||||
This event occurs whenever the screen is refreshed.
|
||||
It checks everything on the board using an x and a y through two repeat loops and draws it.
|
||||
It is an important step, because all board values are changed to the normal versions:
|
||||
5 -> 2 (conductor changed to head)
|
||||
4 -> 3 (head changed to tail)
|
||||
*/
|
||||
//draw sprites and text first
|
||||
|
||||
//now draw wireworld
|
||||
var tempx,tempy;
|
||||
tempx = 0;
|
||||
tempy = 0;
|
||||
|
||||
repeat(boardheight)
|
||||
{
|
||||
repeat(boardwidth)
|
||||
{
|
||||
switch board[tempx,tempy]
|
||||
{
|
||||
case empty:
|
||||
//draw_point_color(tempx,tempy,c_black);
|
||||
draw_set_color(c_black);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
break;
|
||||
case conduc:
|
||||
//draw_point_color(tempx,tempy,c_yellow);
|
||||
draw_set_color(c_yellow);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
break;
|
||||
case eHead:
|
||||
//draw_point_color(tempx,tempy,c_red);
|
||||
draw_set_color(c_blue);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
draw_rectangle_color(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,c_red,c_red,c_red,c_red,false);
|
||||
break;
|
||||
case eTail:
|
||||
//draw_point_color(tempx,tempy,c_blue);
|
||||
draw_set_color(c_red);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
break;
|
||||
case coduc_to_eHead:
|
||||
//draw_point_color(tempx,tempy,c_red);
|
||||
draw_set_color(c_blue);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
board[tempx,tempy] = eHead;
|
||||
break;
|
||||
case eHead_to_eTail:
|
||||
//draw_point_color(tempx,tempy,c_blue);
|
||||
draw_set_color(c_red);
|
||||
draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
|
||||
board[tempx,tempy] = eTail;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
tempx += 1
|
||||
}
|
||||
tempy += 1;
|
||||
tempx = 0;
|
||||
}
|
||||
draw_set_color(c_black);
|
||||
|
|
@ -1,61 +1,60 @@
|
|||
/*REXX program displays a wire world cartesian grid of four─state cells. */
|
||||
signal on halt /*handle any cell growth interruptus. */
|
||||
parse arg iFID . '(' generations rows cols bare head tail wire clearScreen reps
|
||||
if iFID=='' then iFID='WIREWORLD.TXT' /*should default input file be used? */
|
||||
blank = 'BLANK' /*the "name" for a blank. */
|
||||
generations = p(generations 100 ) /*number generations allowed. */
|
||||
rows = p(rows 3 ) /*the number of cell rows. */
|
||||
cols = p(cols 3 ) /* " " " " cols. */
|
||||
bare = pickChar(bare blank ) /*an empty cell character. */
|
||||
clearScreen = p(clearScreen 0 ) /*1 means to clear the screen*/
|
||||
head = pickchar(head 'H' ) /*pick the char for the head.*/
|
||||
tail = pickchar(tail 't' ) /* " " " " " tail.*/
|
||||
wire = pickchar(wire . ) /* " " " " " wire.*/
|
||||
reps = p(reps 2 ) /*stop program if two repeats.*/
|
||||
fents=max(linesize()-1,cols) /*the fence width used after displaying*/
|
||||
#reps=0; $.=bare /*at start, universe is new and barren.*/
|
||||
gens=abs(generations) /*use for convenience (and short name).*/
|
||||
/* [↓] read the input file. */
|
||||
do r=1 while lines(iFID)\==0 /*keep reading until the End─Of─File. */
|
||||
q=strip(linein(iFID),'T') /*get single line from the input file. */
|
||||
_=length(q) /*obtain the length of this (input) row*/
|
||||
cols=max(cols,_) /*calculate the maximum number of cols.*/
|
||||
do c=1 for _; $.r.c=substr(q,c,1); end /*assign the row cells.*/
|
||||
/*REXX program displays a wire world Cartesian grid of four─state cells. */
|
||||
signal on halt /*handle any cell growth interruptus. */
|
||||
parse arg iFID . '(' generations rows cols bare head tail wire clearScreen reps
|
||||
if iFID=='' then iFID="WIREWORLD.TXT" /*should default input file be used? */
|
||||
blank = 'BLANK' /*the "name" for a blank. */
|
||||
generations = p(generations 100 ) /*number generations that are allowed. */
|
||||
rows = p(rows 3 ) /*the number of cell rows. */
|
||||
cols = p(cols 3 ) /* " " " " columns. */
|
||||
bare = pickChar(bare blank ) /*an empty cell character. */
|
||||
clearScreen = p(clearScreen 0 ) /*1 means to clear the screen. */
|
||||
head = pickChar(head 'H' ) /*pick the character for the head. */
|
||||
tail = pickChar(wire . ) /* " " " " " wire. */
|
||||
reps = p(reps 2 ) /*stop program if there are 2 repeats.*/
|
||||
fents=max(linesize()-1,cols) /*the fence width used after displaying*/
|
||||
#reps=0; $.=bare /*at start, universe is new and barren.*/
|
||||
gens=abs(generations) /*use for convenience (and short name).*/
|
||||
/* [↓] read the input file. */
|
||||
do r=1 while lines(iFID)\==0 /*keep reading until the End─Of─File. */
|
||||
q=strip(linein(iFID), 'T') /*get single line from the input file. */
|
||||
_=length(q) /*obtain the length of this (input) row*/
|
||||
cols=max(cols, _) /*calculate the maximum number of cols.*/
|
||||
do c=1 for _; $.r.c=substr(q, c, 1); end /*assign the row cells.*/
|
||||
end /*r*/
|
||||
rows=r-1 /*adjust the row number (from DO loop).*/
|
||||
life=0; !.=0; call showCells /*display initial state of the cells. */
|
||||
/*watch cells evolve, 4 possible states*/
|
||||
do life=1 for gens; @.=bare /*perform for the number of generations*/
|
||||
rows=r-1 /*adjust the row number (from DO loop).*/
|
||||
life=0; !.=0; call showCells /*display initial state of the cells. */
|
||||
/*watch cells evolve, 4 possible states*/
|
||||
do life=1 for gens; @.=bare /*perform for the number of generations*/
|
||||
|
||||
do r=1 for rows /*process each of the rows.*/
|
||||
do c=1 for cols; ?=$.r.c; ??=? /* " " " " cols.*/
|
||||
select /*determine type of cell. */
|
||||
do r=1 for rows /*process each of the rows. */
|
||||
do c=1 for cols; ?=$.r.c; ??=? /* " " " " columns. */
|
||||
select /*determine the type of cell. */
|
||||
when ?==head then ??=tail
|
||||
when ?==tail then ??=wire
|
||||
when ?==wire then do; n=hood(); if n==1|n==2 then ??=head; end
|
||||
when ?==wire then do; n=hood(); if n==1 | n==2 then ??=head; end
|
||||
otherwise nop
|
||||
end /*select*/
|
||||
@.r.c=??
|
||||
end /*c*/
|
||||
end /*r*/
|
||||
|
||||
call assign$ /*assign alternate cells ──► real world*/
|
||||
call assign$ /*assign alternate cells ──► real world*/
|
||||
if generations>0 | life==gens then call showCells
|
||||
end /*life*/
|
||||
/*stop watching the universe (or life).*/
|
||||
halt: if life-1\==gens then say 'The ~~~Wireworld~~~ program was interrupted.'
|
||||
done: exit /*stick a fork in it, we are all done.*/
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
showCells: if clearScreen then 'CLS' /*◄──change this for the OS.*/
|
||||
call showRows /*show rows in proper order.*/
|
||||
say right(copies('═',fents)life,fents) /*display a bunch of cells. */
|
||||
if _=='' then signal done /*No life? Then stop run. */
|
||||
if !._ then #reps=#reps+1 /*detected repeated pattern.*/
|
||||
!._=1 /*it is now existence state.*/
|
||||
if reps\==0 & #reps<=reps then return /*so far, so good, no reps. */
|
||||
/*stop watching the universe (or life).*/
|
||||
halt: if life-1\==gens then say 'The ~~~Wireworld~~~ program was interrupted.'
|
||||
done: exit /*stick a fork in it, we are all done.*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
showCells: if clearScreen then 'CLS' /*◄──change this for the OS.*/
|
||||
call showRows /*show rows in proper order.*/
|
||||
say right(copies('═',fents)life,fents) /*display a bunch of cells. */
|
||||
if _=='' then signal done /*No life? Then stop run. */
|
||||
if !._ then #reps=#reps+1 /*detected repeated pattern.*/
|
||||
!._=1 /*it is now existence state.*/
|
||||
if reps\==0 & #reps<=reps then return /*so far, so good, no reps. */
|
||||
say '"Wireworld" repeated itself' reps "times, program is stopping."
|
||||
signal done /*exit program, we're done. */
|
||||
/*───────────────────────────────one─liner subroutines─────────────────────────────────────────────────────────────────────*/
|
||||
signal done /*exit program, we're done. */
|
||||
/*─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
|
||||
$: parse arg _row,_col; return ($._row._col==head)
|
||||
assign$: do r=1 for rows; do c=1 for cols; $.r.c=@.r.c; end; end; return
|
||||
err: say; say center(' error! ',max(40,linesize()%2),"*"); say; do j=1 for arg(); say arg(j); say; end; say; exit 13
|
||||
|
|
|
|||
46
Task/Wireworld/Standard-ML/wireworld.ml
Normal file
46
Task/Wireworld/Standard-ML/wireworld.ml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
(* Maximilian Wuttke 12.04.2016 *)
|
||||
|
||||
type world = char vector vector
|
||||
|
||||
fun getstate (w:world, (x, y)) = (Vector.sub (Vector.sub (w, y), x)) handle Subscript => #" "
|
||||
|
||||
fun conductor (w:world, (x, y)) =
|
||||
let
|
||||
val s = [getstate (w, (x-1, y-1)) = #"H", getstate (w, (x-1, y)) = #"H", getstate (w, (x-1, y+1)) = #"H",
|
||||
getstate (w, (x, y-1)) = #"H", getstate (w, (x, y+1)) = #"H",
|
||||
getstate (w, (x+1, y-1)) = #"H", getstate (w, (x+1, y)) = #"H", getstate (w, (x+1, y+1)) = #"H"]
|
||||
(* Count `true` in s *)
|
||||
val count = List.length (List.filter (fn x => x=true) s)
|
||||
in
|
||||
if count = 1 orelse count = 2 then #"H" else #"."
|
||||
end
|
||||
|
||||
fun translate (w:world, (x, y)) =
|
||||
case getstate (w, (x, y)) of
|
||||
#" " => #" "
|
||||
| #"H" => #"t"
|
||||
| #"t" => #"."
|
||||
| #"." => conductor (w, (x, y))
|
||||
| s => s
|
||||
|
||||
fun next_world (w : world) = Vector.mapi (fn (y, row) => Vector.mapi (fn (x, _) => translate (w, (x, y))) row) w
|
||||
|
||||
|
||||
(* Test *)
|
||||
|
||||
(* makes a list of strings into a world *)
|
||||
fun make_world (rows : string list) : world =
|
||||
Vector.fromList (map (fn (row : string) => Vector.fromList (explode row)) rows)
|
||||
|
||||
|
||||
(* word_str reverses make_world *)
|
||||
fun vec_str (r:char vector) = implode (List.tabulate (Vector.length r, fn x => Vector.sub (r, x)))
|
||||
fun world_str (w:world) = List.tabulate (Vector.length w, fn y => vec_str (Vector.sub (w, y)))
|
||||
fun print_world (w:world) = (map (fn row_str => print (row_str ^ "\n")) (world_str w); ())
|
||||
|
||||
val test = make_world [
|
||||
"tH.........",
|
||||
". . ",
|
||||
" ... ",
|
||||
". . ",
|
||||
"Ht.. ......"]
|
||||
Loading…
Add table
Add a link
Reference in a new issue