Life in one dimension
From Rosetta Code
Programming Task
This is a programming task. It lays out a problem which Rosetta Code users are encouraged to solve, using languages they know.
One dimensional cellular automata
Assume an array of cells with an initial distribution of live and dead cells, and imaginary cells off the end of the array having fixed values.
Cells in the next generation of the array are calculated based on the value of the cell and its left and right nearest neighbours in the current generation. If, in the following table, a live cell is represented by 1 and a dead cell by 0 then to generate the value of the cell at a particular index in the array of cellular values you use the following table:
000 -> 0 # 001 -> 0 # 010 -> 0 # Dies without enough neighbours 011 -> 1 # Needs one neighbour to survive 100 -> 0 # 101 -> 1 # Two neighbours giving birth 110 -> 1 # Needs one neighbour to survive 111 -> 0 # Starved to death.
Contents |
[edit] Ada
with Ada.Text_IO; use Ada.Text_IO; procedure Cellular_Automata is type Petri_Dish is array (Positive range <>) of Boolean; procedure Step (Culture : in out Petri_Dish) is Left : Boolean := False; This : Boolean; Right : Boolean; begin for Index in Culture'First..Culture'Last - 1 loop Right := Culture (Index + 1); This := Culture (Index); Culture (Index) := (This and (Left xor Right)) or (not This and Left and Right); Left := This; end loop; Culture (Culture'Last) := Culture (Culture'Last) and not Left; end Step; procedure Put (Culture : Petri_Dish) is begin for Index in Culture'Range loop if Culture (Index) then Put ('#'); else Put ('_'); end if; end loop; end Put; Culture : Petri_Dish := ( False, True, True, True, False, True, True, False, True, False, True, False, True, False, True, False, False, True, False, False ); begin for Generation in 0..9 loop Put ("Generation" & Integer'Image (Generation) & ' '); Put (Culture); New_Line; Step (Culture); end loop; end Cellular_Automata;
The implementation defines Petri dish type with Boolean items identifying whether a place is occupied by a living cell. State transition is determined by a simple Boolean expression of three arguments. Sample output:
Generation 0 _###_##_#_#_#_#__#__ Generation 1 _#_#####_#_#_#______ Generation 2 __##___##_#_#_______ Generation 3 __##___###_#________ Generation 4 __##___#_##_________ Generation 5 __##____###_________ Generation 6 __##____#_#_________ Generation 7 __##_____#__________ Generation 8 __##________________ Generation 9 __##________________
[edit] ALGOL 68
[edit] Using the low level packed arrays of BITS manipulation operators
INT stop generation = 9;
INT universe width = 20;
FORMAT alive or dead = $b("#","_")$;
BITS universe := 2r01110110101010100100;
# universe := BIN ( ENTIER ( random * max int ) ); #
INT upb universe = bits width;
INT lwb universe = bits width - universe width + 1;
PROC couple = (BITS parent, INT lwb, upb)BOOL: (
SHORT INT sum := 0;
FOR bit FROM lwb TO upb DO
sum +:= ABS (bit ELEM parent)
OD;
sum = 2
);
FOR generation FROM 0 WHILE
printf(($"Generation "d": "$, generation,
$f(alive or dead)$, []BOOL(universe)[lwb universe:upb universe],
$l$));
# WHILE # generation < stop generation DO
BITS next universe := 2r0;
# process the first event horizon manually #
IF couple(universe,lwb universe,lwb universe + 1) THEN
next universe := 2r10
FI;
# process the middle kingdom in a loop #
FOR bit FROM lwb universe + 1 TO upb universe - 1 DO
IF couple(universe,bit-1,bit+1) THEN
next universe := next universe OR 2r1
FI;
next universe := next universe SHL 1
OD;
# process the last event horizon manually #
IF couple(universe, upb universe - 1, upb universe) THEN
next universe := next universe OR 2r1
FI;
universe := next universe
OD
[edit] Using high level BOOL arrays
INT stop generation = 9;
INT upb universe = 20;
FORMAT alive or dead = $b("#","_")$;
BITS bits universe := 2r01110110101010100100;
# bits universe := BIN ( ENTIER ( random * max int ) ); #
[upb universe] BOOL universe := []BOOL(bits universe)[bits width - upb universe + 1:];
PROC couple = (REF[]BOOL parent)BOOL: (
SHORT INT sum := 0;
FOR bit FROM LWB parent TO UPB parent DO
sum +:= ABS (parent[bit])
OD;
sum = 2
);
FOR generation FROM 0 WHILE
printf(($"Generation "d": "$, generation,
$f(alive or dead)$, universe,
$l$));
# WHILE # generation < stop generation DO
[UPB universe]BOOL next universe;
# process the first event horizon manually #
next universe[1] := couple(universe[:2]);
# process the middle kingdom in a loop #
FOR bit FROM LWB universe + 1 TO UPB universe - 1 DO
next universe[bit] := couple(universe[bit-1:bit+1])
OD;
# process the last event horizon manually #
next universe[UPB universe] := couple(universe[UPB universe - 1: ]);
universe := next universe
OD
Output:
Generation 0: _###_##_#_#_#_#__#__ Generation 1: _#_#####_#_#_#______ Generation 2: __##___##_#_#_______ Generation 3: __##___###_#________ Generation 4: __##___#_##_________ Generation 5: __##____###_________ Generation 6: __##____#_#_________ Generation 7: __##_____#__________ Generation 8: __##________________ Generation 9: __##________________
[edit] BASIC
Works with: QuickBasic version 4.5
Translation of: Java
DECLARE FUNCTION life$ (lastGen$) DECLARE FUNCTION getNeighbors! (group$) CLS start$ = "_###_##_#_#_#_#__#__" numGens = 10 FOR i = 0 TO numGens - 1 PRINT "Generation"; i; ": "; start$ start$ = life$(start$) NEXT i FUNCTION getNeighbors (group$) ans = 0 IF (MID$(group$, 1, 1) = "#") THEN ans = ans + 1 IF (MID$(group$, 3, 1) = "#") THEN ans = ans + 1 getNeighbors = ans END FUNCTION FUNCTION life$ (lastGen$) newGen$ = "" FOR i = 1 TO LEN(lastGen$) neighbors = 0 IF (i = 1) THEN 'left edge IF MID$(lastGen$, 2, 1) = "#" THEN neighbors = 1 ELSE neighbors = 0 END IF ELSEIF (i = LEN(lastGen$)) THEN 'right edge IF MID$(lastGen$, LEN(lastGen$) - 1, 1) = "#" THEN neighbors = 1 ELSE neighbors = 0 END IF ELSE 'middle neighbors = getNeighbors(MID$(lastGen$, i - 1, 3)) END IF IF (neighbors = 0) THEN 'dies or stays dead with no neighbors newGen$ = newGen$ + "_" END IF IF (neighbors = 1) THEN 'stays with one neighbor newGen$ = newGen$ + MID$(lastGen$, i, 1) END IF IF (neighbors = 2) THEN 'flips with two neighbors IF MID$(lastGen$, i, 1) = "#" THEN newGen$ = newGen$ + "_" ELSE newGen$ = newGen$ + "#" END IF END IF NEXT i life$ = newGen$ END FUNCTION
Output:
Generation 0 : _###_##_#_#_#_#__#__ Generation 1 : _#_#####_#_#_#______ Generation 2 : __##___##_#_#_______ Generation 3 : __##___###_#________ Generation 4 : __##___#_##_________ Generation 5 : __##____###_________ Generation 6 : __##____#_#_________ Generation 7 : __##_____#__________ Generation 8 : __##________________ Generation 9 : __##________________
[edit] Fortran
Works with: Fortran version 90 and later
PROGRAM LIFE_1D
IMPLICIT NONE
LOGICAL :: cells(20) = (/ .FALSE., .TRUE., .TRUE., .TRUE., .FALSE., .TRUE., .TRUE., .FALSE., .TRUE., .FALSE., &
.TRUE., .FALSE., .TRUE., .FALSE., .TRUE., .FALSE., .FALSE., .TRUE., .FALSE., .FALSE. /)
INTEGER :: i
DO i = 0, 9
WRITE(*, "(A,I0,A)", ADVANCE = "NO") "Generation ", i, ": "
CALL Drawgen(cells)
CALL Nextgen(cells)
END DO
CONTAINS
SUBROUTINE Nextgen(cells)
LOGICAL, INTENT (IN OUT) :: cells(:)
LOGICAL :: left, centre, right
INTEGER :: i
left = .FALSE.
DO i = 1, SIZE(cells)-1
centre = cells(i)
right = cells(i+1)
IF (left .AND. right) THEN
cells(i) = .NOT. cells(i)
ELSE IF (.NOT. left .AND. .NOT. right) THEN
cells(i) = .FALSE.
END IF
left = centre
END DO
cells(SIZE(cells)) = left .AND. right
END SUBROUTINE Nextgen
SUBROUTINE Drawgen(cells)
LOGICAL, INTENT (IN OUT) :: cells(:)
INTEGER :: i
DO i = 1, SIZE(cells)
IF (cells(i)) THEN
WRITE(*, "(A)", ADVANCE = "NO") "#"
ELSE
WRITE(*, "(A)", ADVANCE = "NO") "_"
END IF
END DO
WRITE(*,*)
END SUBROUTINE Drawgen
END PROGRAM LIFE_1D
Output
Generation 0: _###_##_#_#_#_#__#__ Generation 1: _#_#####_#_#_#______ Generation 2: __##___##_#_#_______ Generation 3: __##___###_#________ Generation 4: __##___#_##_________ Generation 5: __##____###_________ Generation 6: __##____#_#_________ Generation 7: __##_____#__________ Generation 8: __##________________ Generation 9: __##________________
[edit] Haskell
module Life1D where
import Data.List
import System.Random
import Control.Monad
import Control.Arrow
bnd :: [Char] -> Char
bnd bs =
case bs of
"_##" -> '#'
"#_#" -> '#'
"##_" -> '#'
_ -> '_'
donxt xs = unfoldr(\xs -> case xs of [_,_] -> Nothing ;
_ -> Just (bnd $ take 3 xs, drop 1 xs)) $ '_':xs++"_"
lahmahgaan xs = init.until (liftM2 (==) last (last. init)) (ap (++)(return. donxt. last)) $ [xs, donxt xs]
main = do
g <- newStdGen
let oersoep = map ("_#"!!). take 36 $ randomRs(0,1) g
mapM_ print . lahmahgaan $ oersoep
Some output:
*Life1D> mapM_ print . lahmahgaan $ "_###_##_#_#_#_#__#__" "_###_##_#_#_#_#__#__" "_#_#####_#_#_#______" "__##___##_#_#_______" "__##___###_#________" "__##___#_##_________" "__##____###_________" "__##____#_#_________" "__##_____#__________" "__##________________" *Life1D> main "__##_##__#____###__#__#_______#_#_##" "__#####_______#_#______________#_###" "__#___#________#________________##_#" "________________________________###_" "________________________________#_#_" "_________________________________#__" "____________________________________"
[edit] J
life1d=: '_#'{~]@(([:3&(2=+/\)0,],0:)^:a:)
Example use:
life1d ? 20 # 2 _###_##_#_#_#_#__#__ _#_#####_#_#_#______ __##___##_#_#_______ __##___###_#________ __##___#_##_________ __##____###_________ __##____#_#_________ __##_____#__________ __##________________
[edit] Java
This example requires a starting generation of at least length two (which is what you need for anything interesting anyway).
public class Life{ public static void main(String[] args) throws Exception{ String start= "_###_##_#_#_#_#__#__"; int numGens = 10; for(int i= 0; i < numGens; i++){ System.out.println("Generation " + i + ": " + start); start= life(start); } } public static String life(String lastGen){ String newGen= ""; for(int i= 0; i < lastGen.length(); i++){ int neighbors= 0; if (i == 0){//left edge neighbors= lastGen.charAt(1) == '#' ? 1 : 0; } else if (i == lastGen.length() - 1){//right edge neighbors= lastGen.charAt(lastGen.length() - 2) == '#' ? 1 : 0; } else{//middle neighbors= getNeighbors(lastGen.substring(i - 1, i + 2)); } if (neighbors == 0){//dies or stays dead with no neighbors newGen+= "_"; } if (neighbors == 1){//stays with one neighbor newGen+= lastGen.charAt(i); } if (neighbors == 2){//flips with two neighbors newGen+= lastGen.charAt(i) == '#' ? "_" : "#"; } } return newGen; } public static int getNeighbors(String group){ int ans= 0; if (group.charAt(0) == '#') ans++; if (group.charAt(2) == '#') ans++; return ans; } }
Output:
Generation 0: _###_##_#_#_#_#__#__ Generation 1: _#_#####_#_#_#______ Generation 2: __##___##_#_#_______ Generation 3: __##___###_#________ Generation 4: __##___#_##_________ Generation 5: __##____###_________ Generation 6: __##____#_#_________ Generation 7: __##_____#__________ Generation 8: __##________________ Generation 9: __##________________
[edit] OCaml
let get g i = try g.(i) with _ -> 0 let next_cell g i = match get g (i-1), get g (i), get g (i+1) with | 0, 0, 0 -> 0 | 0, 0, 1 -> 0 | 0, 1, 0 -> 0 | 0, 1, 1 -> 1 | 1, 0, 0 -> 0 | 1, 0, 1 -> 1 | 1, 1, 0 -> 1 | 1, 1, 1 -> 0 | _ -> assert(false) let next g = let old_g = Array.copy g in for i = 0 to pred(Array.length g) do g.(i) <- (next_cell old_g i) done let print_g g = for i = 0 to pred(Array.length g) do if g.(i) = 0 then print_char '_' else print_char '#' done; print_newline()
put the code above in a file named "life.ml", and then use it in the ocaml toplevel like this:
#use "life.ml" ;;
let iter n g =
for i = 0 to n do
Printf.printf "Generation %d: " i; print_g g;
next g;
done
;;
let g_of_string str =
let f = (function '_' -> 0 | '#' -> 1 | _ -> assert false) in
Array.init (String.length str) (fun i -> f str.[i])
;;
# iter 9 (g_of_string "_###_##_#_#_#_#__#__") ;;
Generation 0: _###_##_#_#_#_#__#__
Generation 1: _#_#####_#_#_#______
Generation 2: __##___##_#_#_______
Generation 3: __##___###_#________
Generation 4: __##___#_##_________
Generation 5: __##____###_________
Generation 6: __##____#_#_________
Generation 7: __##_____#__________
Generation 8: __##________________
Generation 9: __##________________
- : unit = ()
[edit] Python
import random printdead, printlive = '_#' maxgenerations = 10 cellcount = 20 offendvalue = '0' universe = ''.join(random.choice('01') for i in range(cellcount)) neighbours2newstate = { '000': '0', '001': '0', '010': '0', '011': '1', '100': '0', '101': '1', '110': '1', '111': '0', } for i in range(maxgenerations): print "Generation %3i: %s" % ( i, universe.replace('0', printdead).replace('1', printlive) ) universe = offendvalue + universe + offendvalue universe = ''.join(neighbours2newstate[universe[i:i+3]] for i in range(cellcount))
Sample output:
Generation 0: _###_##_#_#_#_#__#__ Generation 1: _#_#####_#_#_#______ Generation 2: __##___##_#_#_______ Generation 3: __##___###_#________ Generation 4: __##___#_##_________ Generation 5: __##____###_________ Generation 6: __##____#_#_________ Generation 7: __##_____#__________ Generation 8: __##________________ Generation 9: __##________________The following implementation uses boolean operations to realize the function.
import random nquads = 5 maxgenerations = 10 fmt = '%%0%ix'%nquads nbits = 4*nquads a = random.getrandbits(nbits) << 1 #a = int('01110110101010100100', 2) << 1 endmask = (2<<nbits)-2; endvals = 0<<(nbits+1) | 0 tr = ('____', '___#', '__#_', '__##', '_#__', '_#_#', '_##_', '_###', '#___', '#__#', '#_#_', '#_##', '##__', '##_#', '###_', '####' ) for i in range(maxgenerations): print "Generation %3i: %s" % (i,(''.join(tr[int(t,16)] for t in (fmt%(a>>1))))) a |= endvals a = ((a&((a<<1) | (a>>1))) ^ ((a<<1)&(a>>1))) & endmask
[edit] Vedit macro language
This implementation writes the calculated patterns into an edit buffer, where the results can viewed and saved into a file if required. The edit buffer also acts as storage during calculations.
IT("Gen 0: ..###.##.#.#.#.#..#.....") // initial pattern
#9 = Cur_Col
for (#8 = 1; #8 < 10; #8++) { // 10 generations
Goto_Col(7)
Reg_Empty(20)
while (Cur_Col < #9-1) {
if (Match("|{##|!#,#.#,|!###}")==0) {
Reg_Set(20, "#", APPEND)
} else {
Reg_Set(20, ".", APPEND)
}
Char
}
EOL IN
IT("Gen ") Num_Ins(#8, LEFT+NOCR) IT(": ")
Reg_Ins(20)
}
Sample output:
Gen 0: ..###.##.#.#.#.#..#..... Gen 1: ..#.#####.#.#.#......... Gen 2: ...##...##.#.#.......... Gen 3: ...##...###.#........... Gen 4: ...##...#.##............ Gen 5: ...##....###............ Gen 6: ...##....#.#............ Gen 7: ...##.....#............. Gen 8: ...##................... Gen 9: ...##...................
Categories: Programming Tasks | Games | Ada | ALGOL 68 | BASIC | Fortran | Haskell | J | Java | OCaml | Python | Vedit macro language

