-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgof.pl
131 lines (99 loc) · 4.54 KB
/
gof.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
% vim, please detect prolog
cell_new_state(dead_cell, 3, live_cell).
cell_new_state(live_cell, Neighbours, live_cell) :-
member(Neighbours, [2, 3]).
cell_new_state(_, _, dead_cell).
north(cell(X, Y), cell(X, NY)) :- NY is Y - 1.
south(cell(X, Y), cell(X, NY)) :- NY is Y + 1.
west(cell(X, Y), cell(NX, Y)) :- NX is X - 1.
east(cell(X, Y), cell(NX, Y)) :- NX is X + 1.
south_east(cell(X, Y), cell(NX, NY)) :-
south(cell(X, Y), cell(SX, SY)),
east(cell(SX, SY), cell(NX, NY)).
south_west(cell(X, Y), cell(NX, NY)) :-
south(cell(X, Y), cell(SX, SY)),
west(cell(SX, SY), cell(NX, NY)).
north_west(cell(X, Y), cell(NX, NY)) :-
north(cell(X, Y), cell(SX, SY)),
west(cell(SX, SY), cell(NX, NY)).
north_east(cell(X, Y), cell(NX, NY)) :-
north(cell(X, Y), cell(SX, SY)),
east(cell(SX, SY), cell(NX, NY)).
neighbours(Cell, Neighbours) :-
north_west(Cell, NW),
north(Cell, N),
north_east(Cell, NE),
east(Cell, E),
south_east(Cell, SE),
south(Cell, S),
south_west(Cell, SW),
west(Cell, W),
list_to_set([NW, N, NE, E, SE, S, SW, W], Neighbours).
empty_world(world([], [])).
world_add_cell(world(LiveCells, DeadCells), Cell, world(UnionLiveCells, NewDeadCells)) :-
union([Cell], LiveCells, UnionLiveCells),
neighbours(Cell, Neighbours),
union(DeadCells, Neighbours, DeadCellsUnion),
subtract(DeadCellsUnion, UnionLiveCells, NewDeadCells).
world_add_cells(World, [], World).
world_add_cells(World, [H|T], NewWorld) :-
world_add_cell(World, H, IntermediateWorld),
world_add_cells(IntermediateWorld, T, NewWorld).
live_neighbours_from_live_set(LiveCells, Cell, LiveNeighbours) :-
neighbours(Cell, Neighbours),
intersection(LiveCells, Neighbours, LiveNeighbours).
live_neighbours(world(LiveCells, _), Cell, LiveNeighbours) :-
live_neighbours_from_live_set(LiveCells, Cell, LiveNeighbours).
try_to_insert_cell_new_world(World, _, dead_cell, World).
try_to_insert_cell_new_world(World, Cell, live_cell, NewWorld) :-
world_add_cell(World, Cell, NewWorld).
evolve_util(InitialWorld, world(LiveCells, DeadCells), PartialNextGenWorld, NextGenWorld) :-
evolve_util_for_cells_set(live_cell, InitialWorld, LiveCells, PartialNextGenWorld, NextGenLiveEvolved),
evolve_util_for_cells_set(dead_cell, InitialWorld, DeadCells, NextGenLiveEvolved, NextGenWorld).
evolve_util_for_cells_set(_, _, [], NextGenWorld, NextGenWorld).
evolve_util_for_cells_set(ExpectedCellState, InitialWorld, [Cell|LiveTail], PartialNextGenWorld, NextGenWorld) :-
live_neighbours(InitialWorld, Cell, LiveNeighbours),
length(LiveNeighbours, NLiveNeighbours),
cell_new_state(ExpectedCellState, NLiveNeighbours, NewCellState),
try_to_insert_cell_new_world(PartialNextGenWorld, Cell, NewCellState, LessPartialNextGenWorld),
subtract([Cell|LiveTail], [Cell], LiveRemains), % keeps set structure
evolve_util_for_cells_set(ExpectedCellState, InitialWorld, LiveRemains, LessPartialNextGenWorld, NextGenWorld).
evolve(World, NextGenWorld) :-
empty_world(EmptyWorld),
evolve_util(World, World, EmptyWorld, NextGenWorld).
% 48 is ascii('0')
cell_to_string(world(LiveCells, _), X, Y, [48]) :-
intersection([cell(X, Y)], LiveCells, [cell(X, Y)]).
% 32 is ascii(' ')
cell_to_string(_, _, _, [32]).
% 10 is ascii('\n')
world_line_to_string(_, _, _, 0, Acc, WithBreakLine) :-
append(Acc, [10], WithBreakLine).
world_line_to_string(World, X, Y, Width, Acc, LineString) :-
NextX is X + 1,
RemainWidth is Width - 1,
cell_to_string(World, X, Y, CellString),
append(Acc, CellString, NewAcc),
world_line_to_string(World, NextX, Y, RemainWidth, NewAcc, LineString).
world_to_string_codes_util(_, world_window(_, _, 0, _), Acc, Acc).
world_to_string_codes_util(World, world_window(X, Y, Height, Width), Acc, WorldArray) :-
world_line_to_string(World, X, Y, Width, Acc, PartialArray),
NextLine is Y + 1,
RemainHeight is Height - 1,
world_to_string_codes_util(World, world_window(X, NextLine, RemainHeight, Width), PartialArray, WorldArray).
world_to_string_codes(World, Window, WorldArray) :-
world_to_string_codes_util(World, Window, [], WorldArray).
world_to_string(World, Window, WorldString) :-
world_to_string_codes(World, Window, WorldArray),
string_to_list(WorldString, WorldArray).
game_of_life_main_loop(World, Window) :-
world_to_string(World, Window, WorldString),
evolve(World, EvolvedWorld),
sleep(1), % sleeps 1s
write('\e[H\e[2J'), % clear screen
write(WorldString),
game_of_life_main_loop(EvolvedWorld, Window).
game_of_life(Cells, Window) :-
empty_world(EmptyWorld),
world_add_cells(EmptyWorld, Cells, NewWorld),
game_of_life_main_loop(NewWorld, Window).