Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
143
Task/Maze-generation/Erlang/maze-generation-1.erl
Normal file
143
Task/Maze-generation/Erlang/maze-generation-1.erl
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
-module( maze ).
|
||||
|
||||
-export( [cell_accessible_neighbours/1, cell_content/1, cell_content_set/2, cell_pid/3, cell_position/1, display/1, generation/2, stop/1, task/0] ).
|
||||
|
||||
-record( maze, {dict, max_x, max_y, start} ).
|
||||
-record( state, {content=" ", controller, is_dug=false, max_x, max_y, neighbours=[], position, walls=[north, south, east, west], walk_done} ).
|
||||
|
||||
cell_accessible_neighbours( Pid ) -> read( Pid, accessible_neighbours ).
|
||||
|
||||
cell_content( Pid ) -> read( Pid, content ).
|
||||
|
||||
cell_content_set( Pid, Content ) -> Pid ! {content, Content, erlang:self()}.
|
||||
|
||||
cell_pid( X, Y, Maze ) -> dict:fetch( {X, Y}, Maze#maze.dict ).
|
||||
|
||||
cell_position( Pid ) -> read( Pid, position ).
|
||||
|
||||
display( #maze{dict=Dict, max_x=Max_x, max_y=Max_y} ) ->
|
||||
Position_pids = dict:to_list( Dict ),
|
||||
display( Max_x, Max_y, reads(Position_pids, content), reads(Position_pids, walls) ).
|
||||
|
||||
generation( Max_x, Max_y ) ->
|
||||
Controller = erlang:self(),
|
||||
Position_pids = cells_create( Controller, Max_x, Max_y ),
|
||||
Pids = [Y || {_X, Y} <- Position_pids],
|
||||
[X ! {position_pids, Position_pids} || X <- Pids],
|
||||
{Position, Pid} = lists:nth( random:uniform(Max_x * Max_y), Position_pids ),
|
||||
Pid ! {dig, Controller},
|
||||
receive
|
||||
{dig_done} -> ok
|
||||
end,
|
||||
#maze{dict=dict:from_list(Position_pids), max_x=Max_x, max_y=Max_y, start=Position}.
|
||||
|
||||
stop( #maze{dict=Dict} ) ->
|
||||
Controller = erlang:self(),
|
||||
Pids = [Y || {_X, Y} <- dict:to_list(Dict)],
|
||||
[X ! {stop, Controller} || X <- Pids],
|
||||
ok.
|
||||
|
||||
task() ->
|
||||
Maze = generation( 16, 8 ),
|
||||
io:fwrite( "Starting at ~p~n", [Maze#maze.start] ),
|
||||
display( Maze ),
|
||||
stop( Maze ).
|
||||
|
||||
|
||||
|
||||
cells_create( Controller, Max_x, Max_y ) -> [{{X, Y}, cell_create(Controller, Max_x, Max_y, {X, Y})} || X <- lists:seq(1, Max_x), Y<- lists:seq(1, Max_y)].
|
||||
|
||||
cell_create( Controller, Max_x, Max_y, {X, Y} ) -> erlang:spawn_link( fun() -> random:seed( X*1000, Y*1000, (X+Y)*1000 ), loop( #state{controller=Controller, max_x=Max_x, max_y=Max_y, position={X, Y}} ) end ).
|
||||
|
||||
display( Max_x, Max_y, Position_contents, Position_walls ) ->
|
||||
All_rows = [display_row( Max_x, Y, Position_contents, Position_walls ) || Y <- lists:seq(Max_y, 1, -1)],
|
||||
[io:fwrite("~s+~n~s|~n", [North, West]) || {North, West} <- All_rows],
|
||||
io:fwrite("~s+~n", [lists:flatten(lists:duplicate(Max_x, display_row_north(true)))] ).
|
||||
|
||||
display_row( Max_x, Y, Position_contents, Position_walls ) ->
|
||||
North_wests = [display_row_walls(proplists:get_value({X,Y}, Position_contents), proplists:get_value({X,Y}, Position_walls)) || X <- lists:seq(1, Max_x)],
|
||||
North = lists:append( [North || {North, _West} <- North_wests] ),
|
||||
West = lists:append( [West || {_X, West} <- North_wests] ),
|
||||
{North, West}.
|
||||
|
||||
display_row_walls( Content, Walls ) -> {display_row_north( lists:member(north, Walls) ), display_row_west( lists:member(west, Walls), Content )}.
|
||||
|
||||
display_row_north( true ) -> "+---";
|
||||
display_row_north( false ) -> "+ ".
|
||||
|
||||
display_row_west( true, Content ) -> "| " ++ Content ++ " ";
|
||||
display_row_west( false, Content ) -> " " ++ Content ++ " ".
|
||||
|
||||
loop( State ) ->
|
||||
receive
|
||||
{accessible_neighbours, Pid} ->
|
||||
Pid ! {accessible_neighbours, loop_accessible_neighbours( State#state.neighbours, State#state.walls ), erlang:self()},
|
||||
loop( State );
|
||||
{content, Pid} ->
|
||||
Pid ! {content, State#state.content, erlang:self()},
|
||||
loop( State );
|
||||
{content, Content, _Pid} ->
|
||||
loop( State#state{content=Content} );
|
||||
{dig, Pid} ->
|
||||
Not_dug_neighbours = loop_not_dug( State#state.neighbours ),
|
||||
New_walls = loop_dig( Not_dug_neighbours, lists:delete( loop_wall_from_pid(Pid, State#state.neighbours), State#state.walls), Pid ),
|
||||
loop( State#state{is_dug=true, walls=New_walls, walk_done=Pid} );
|
||||
{dig_done} ->
|
||||
Not_dug_neighbours = loop_not_dug( State#state.neighbours ),
|
||||
New_walls = loop_dig( Not_dug_neighbours, State#state.walls, State#state.walk_done ),
|
||||
loop( State#state{walls=New_walls} );
|
||||
{is_dug, Pid} ->
|
||||
Pid ! {is_dug, State#state.is_dug, erlang:self()},
|
||||
loop( State );
|
||||
{position, Pid} ->
|
||||
Pid ! {position, State#state.position, erlang:self()},
|
||||
loop( State );
|
||||
{position_pids, Position_pids} ->
|
||||
{_My_position, Neighbours} = lists:foldl( fun loop_neighbours/2, {State#state.position, []}, Position_pids ),
|
||||
erlang:garbage_collect(), % Shrink process after using large Pid_positions. For memory starved systems.
|
||||
loop( State#state{neighbours=Neighbours} );
|
||||
{stop, Controller} when Controller =:= State#state.controller ->
|
||||
ok;
|
||||
{walls, Pid} ->
|
||||
Pid ! {walls, State#state.walls, erlang:self()},
|
||||
loop( State )
|
||||
end.
|
||||
|
||||
loop_accessible_neighbours( Neighbours, Walls ) -> [Pid || {Direction, Pid} <- Neighbours, not lists:member(Direction, Walls)].
|
||||
|
||||
loop_dig( [], Walls, Pid ) ->
|
||||
Pid ! {dig_done},
|
||||
Walls;
|
||||
loop_dig( Not_dug_neighbours, Walls, _Pid ) ->
|
||||
{Dig_pid, Dig_direction} = lists:nth( random:uniform(erlang:length(Not_dug_neighbours)), Not_dug_neighbours ),
|
||||
Dig_pid ! {dig, erlang:self()},
|
||||
lists:delete( Dig_direction, Walls ).
|
||||
|
||||
loop_neighbours( {{X, Y}, Pid}, {{X, My_y}, Acc} ) when Y =:= My_y + 1 -> {{X, My_y}, [{north, Pid} | Acc]};
|
||||
loop_neighbours( {{X, Y}, Pid}, {{X, My_y}, Acc} ) when Y =:= My_y - 1 -> {{X, My_y}, [{south, Pid} | Acc]};
|
||||
loop_neighbours( {{X, Y}, Pid}, {{My_x, Y}, Acc} ) when X =:= My_x + 1 -> {{My_x, Y}, [{east, Pid} | Acc]};
|
||||
loop_neighbours( {{X, Y}, Pid}, {{My_x, Y}, Acc} ) when X =:= My_x - 1 -> {{My_x, Y}, [{west, Pid} | Acc]};
|
||||
loop_neighbours( _Position_pid, Acc ) -> Acc.
|
||||
|
||||
loop_not_dug( Neighbours ) ->
|
||||
My_pid = erlang:self(),
|
||||
[Pid ! {is_dug, My_pid} || {_Direction, Pid} <- Neighbours],
|
||||
[{Pid, Direction} || {Direction, Pid} <- Neighbours, not read_receive(Pid, is_dug)].
|
||||
|
||||
loop_wall_from_pid( Pid, Neighbours ) -> loop_wall_from_pid_result( lists:keyfind(Pid, 2, Neighbours) ).
|
||||
loop_wall_from_pid_result( {Direction, _Pid} ) -> Direction;
|
||||
loop_wall_from_pid_result( false ) -> controller.
|
||||
|
||||
read( Pid, Key ) ->
|
||||
Pid ! {Key, erlang:self()},
|
||||
read_receive( Pid, Key ).
|
||||
|
||||
read_receive( Pid, Key ) ->
|
||||
receive
|
||||
{Key, Value, Pid} -> Value
|
||||
end.
|
||||
|
||||
reads( Position_pids, Key ) ->
|
||||
My_pid = erlang:self(),
|
||||
[Pid ! {Key, My_pid} || {_Position, Pid} <- Position_pids],
|
||||
[{Position, read_receive(Pid, Key)} || {Position, Pid} <- Position_pids].
|
||||
114
Task/Maze-generation/Erlang/maze-generation-2.erl
Normal file
114
Task/Maze-generation/Erlang/maze-generation-2.erl
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
-module(maze).
|
||||
-record(maze, {g, m, n}).
|
||||
-export([generate_default/0, generate_MxN/2]).
|
||||
|
||||
make_maze(M, N) ->
|
||||
Maze = #maze{g = digraph:new(), m = M, n = N},
|
||||
lists:foreach(fun(X) -> digraph:add_vertex(Maze#maze.g, X) end, lists:seq(0, M * N - 1)),
|
||||
Maze.
|
||||
|
||||
row_at(V, Maze) -> trunc(V / Maze#maze.n).
|
||||
col_at(V, Maze) -> V - row_at(V, Maze) * Maze#maze.n.
|
||||
vertex_at(Row, Col, Maze) -> Cell_Exists = cell_exists(Row, Col, Maze), if Cell_Exists -> Row * Maze#maze.n + Col; true -> -1 end.
|
||||
cell_exists(Row, Col, Maze) -> (Row >= 0) and (Row < Maze#maze.m) and (Col >= 0) and (Col < Maze#maze.n).
|
||||
|
||||
adjacent_cells(V, Maze) -> % ordered: left, up, right, down
|
||||
adjacent_cell(cell_left, V, Maze)++adjacent_cell(cell_up, V, Maze)++adjacent_cell(cell_right, V, Maze)++adjacent_cell(cell_down, V, Maze).
|
||||
|
||||
adjacent_cell(cell_left, V, Maze) -> case (col_at(V, Maze) == 0) of true -> []; _Else -> [V - 1] end;
|
||||
adjacent_cell(cell_up, V, Maze) -> case (row_at(V, Maze) == 0) of true -> []; _Else -> [V - Maze#maze.n] end;
|
||||
adjacent_cell(cell_right, V, Maze) -> case (col_at(V, Maze) == Maze#maze.n - 1) of true -> []; _Else -> [V + 1] end;
|
||||
adjacent_cell(cell_down, V, Maze) -> case (row_at(V, Maze) == Maze#maze.m - 1) of true -> []; _Else -> [V + Maze#maze.n] end.
|
||||
|
||||
connect_all(V, Maze) ->
|
||||
lists:foreach(fun(X) -> digraph:add_edge(Maze#maze.g, V, X) end, adjacent_cells(V, Maze)).
|
||||
|
||||
make_maze(M, N, all_connected) ->
|
||||
Maze = make_maze(M, N),
|
||||
lists:foreach(fun(X) -> connect_all(X, Maze) end, lists:seq(0, M * N - 1)),
|
||||
Maze.
|
||||
|
||||
maze_parts(Maze) ->
|
||||
SPR = Maze#maze.n + 1, % slots per row is #columns + 1
|
||||
NPR = (Maze#maze.m * 2) + 1, % # part rows is #(rows * 2) + 1
|
||||
[make_part(Maze, trunc(Index/SPR), Index - trunc(Index/SPR) * SPR) || Index <- lists:seq(0, (SPR * NPR) - 1)].
|
||||
|
||||
draw_part(Part) ->
|
||||
case Part of
|
||||
{pwall, pclosed} -> io:format("+---");
|
||||
{pwall, popen} -> io:format("+ ");
|
||||
{pwall, pend} -> io:format("+~n");
|
||||
{phall, pclosed} -> io:format("| ");
|
||||
{phall, popen} -> io:format(" ");
|
||||
{phall, pend} -> io:format("|~n")
|
||||
end.
|
||||
|
||||
has_neighbour(Maze, Row, Col, Direction) ->
|
||||
V = vertex_at(Row, Col, Maze),
|
||||
if
|
||||
V >= 0 ->
|
||||
Adjacent = adjacent_cell(Direction, V, Maze),
|
||||
if
|
||||
length(Adjacent) > 0 ->
|
||||
Neighbours = digraph:out_neighbours(Maze#maze.g, lists:nth(1, Adjacent)),
|
||||
lists:member(V, Neighbours);
|
||||
true -> false
|
||||
end;
|
||||
true -> false
|
||||
end.
|
||||
|
||||
make_part(Maze, DoubledRow, Col) ->
|
||||
if
|
||||
trunc(DoubledRow/2) * 2 == DoubledRow -> % --- (even row) making a wall above the cell
|
||||
make_part(Maze, trunc(DoubledRow/2), Col, cell_up, pwall);
|
||||
true -> % ---otherwise (odd row) making a hall through the cell
|
||||
make_part(Maze, trunc(DoubledRow/2), Col, cell_left, phall)
|
||||
end.
|
||||
|
||||
make_part(Maze, _, Col, _, Part_Type) when Col == Maze#maze.n -> {Part_Type, pend};
|
||||
make_part(Maze, Row, Col, Direction, Part_Type) ->
|
||||
Has_Neighbour = has_neighbour(Maze, Row, Col, Direction),
|
||||
if
|
||||
Has_Neighbour -> {Part_Type, popen};
|
||||
true -> {Part_Type, pclosed}
|
||||
end.
|
||||
|
||||
shuffle([], Acc) -> Acc;
|
||||
shuffle(List, Acc) ->
|
||||
Elem = lists:nth(random:uniform(length(List)), List),
|
||||
shuffle(lists:delete(Elem, List), Acc++[Elem]).
|
||||
|
||||
processDepthFirst(Maze) ->
|
||||
if
|
||||
Maze#maze.m * Maze#maze.n == 0 -> [{pwall, pend}];
|
||||
true ->
|
||||
Visited = array:new([{size, Maze#maze.m * Maze#maze.n},{fixed,true},{default,false}]),
|
||||
{_, Path} = processDepthFirst(Maze, -1, random:uniform(Maze#maze.m * Maze#maze.n) - 1, {Visited, []}),
|
||||
Path
|
||||
end.
|
||||
|
||||
processDepthFirst(Maze, Vfrom, V, VandP) ->
|
||||
{Visited, Path} = VandP,
|
||||
Was_Visited = array:get(V, Visited),
|
||||
if
|
||||
not Was_Visited ->
|
||||
Walker = fun(X, Acc) -> processDepthFirst(Maze, V, X, Acc) end,
|
||||
Random_Neighbours = shuffle(digraph:out_neighbours(Maze#maze.g, V), []),
|
||||
lists:foldl(Walker, {array:set(V, true, Visited), Path++[{Vfrom, V}]}, Random_Neighbours);
|
||||
true -> VandP
|
||||
end.
|
||||
|
||||
open_wall(_, {-1, _}) -> ok;
|
||||
open_wall(Maze, {V, V2}) ->
|
||||
case (V2 > V) of true -> digraph:add_edge(Maze#maze.g, V, V2); _Else -> digraph:add_edge(Maze#maze.g, V2, V) end.
|
||||
|
||||
generate_MxN(M, N) ->
|
||||
Maze = make_maze(M, N),
|
||||
Matrix = make_maze(M, N, all_connected),
|
||||
Trail = processDepthFirst(Matrix),
|
||||
lists:foreach(fun(X) -> open_wall(Maze, X) end, Trail),
|
||||
Parts = maze_parts(Maze),
|
||||
lists:foreach(fun(X) -> draw_part(X) end, Parts).
|
||||
|
||||
generate_default() ->
|
||||
generate_MxN(9, 9).
|
||||
Loading…
Add table
Add a link
Reference in a new issue