Permalink
Browse files

First commit.

  • Loading branch information...
razielgn committed Apr 25, 2012
0 parents commit 884b6c4e3d84376cf31ed678fd4c7a8786f03861
Showing with 245 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +69 −0 rakefile
  3. +49 −0 src/gol.erl
  4. +125 −0 test/gol.hrl
@@ -0,0 +1,2 @@
+*.beam
+ebin/
@@ -0,0 +1,69 @@
+# Original version by Gabriele Lana. See https://github.com/gabrielelana/katas/blob/master/string_calculator_erlang/rakefile
+
+require "rake/clean"
+require 'fileutils'
+
+CLEAN.include("ebin")
+SOURCE = FileList[ "src/*.erl" ]
+MODULES = SOURCE.pathmap("%{src,ebin}X.beam")
+
+SHELL_FLAGS = "+K true"
+COMPILER_FLAGS = "-I include -Wall"
+
+directory "ebin"
+verbose(false)
+
+desc "compile all source *.erl files under src/"
+task :compile => [ "ebin" ] + MODULES
+rule ".beam" => [ "%{ebin,src}X.erl", "%{ebin,test}X.hrl" ] do | task |
+ puts "compile: #{task.source}"
+ sh "erlc -pa ebin -DTEST -W #{COMPILER_FLAGS} -o ebin #{task.source}"
+end
+
+desc "run tests for all modules under ebin/"
+task :test => [ :compile ] do
+ MODULES.each do | module_file |
+ module_name = File.basename(module_file, ".beam")
+ if File.exist?("test/#{module_name}.hrl")
+ puts "module: #{module_name}"
+ sh "erl -noshell -pa ebin -run #{module_name} test -run init stop"
+ puts "---"
+ end
+ end
+end
+
+task :shell => [ :compile ] do
+ sh "erl #{SHELL_FLAGS} -pa ebin"
+end
+
+desc "create module src and test files"
+task :create, :module do |t, args|
+ mod = args[:module]
+
+ FileUtils.mkdir 'src' unless Dir.exists?('src')
+ FileUtils.mkdir 'test' unless Dir.exists?('test')
+
+ File.open("src/#{mod}.erl", 'w') do |f|
+ f.puts <<-SRC
+-module(#{mod}).
+-export([]).
+
+-ifdef(TEST).
+-include_lib("../test/#{mod}.hrl").
+-endif.
+ SRC
+ end
+
+ File.open("test/#{mod}.hrl", 'w') do |f|
+ f.puts <<-TEST
+-include_lib("eunit/include/eunit.hrl").
+
+assert_the_truth_test() ->
+ ?assertEqual(true, true).
+ TEST
+ end
+
+ puts "Files for module #{mod} created."
+end
+
+task :default => :compile
@@ -0,0 +1,49 @@
+-module(gol).
+-compile(export_all).
+
+pot_neighbors({ X1, Y1 }) ->
+ XX = lists:seq(X1 - 1, X1 + 1),
+ YY = lists:seq(Y1 - 1, Y1 + 1),
+ % generate all possible neighbors, excluding self
+ [ {X, Y} || X <- (XX), Y <- (YY), not( (X == X1) and (Y == Y1) ) ].
+
+neighbors(Cell, Grid) ->
+ PotNeighbors = pot_neighbors(Cell),
+ Neighbors = sets:intersection(sets:from_list(Grid),
+ sets:from_list(PotNeighbors)),
+ sets:to_list(Neighbors).
+
+next_state(State, 2) -> State;
+next_state(_, 3) -> alive;
+next_state(_, _) -> dead.
+
+curr_state(Cell, Grid) ->
+ case lists:member(Cell, Grid) of
+ true -> alive;
+ false -> dead
+ end.
+
+tick_cell(Cell, Grid) ->
+ CurrState = curr_state(Cell, Grid),
+ Neighbors = neighbors(Cell, Grid),
+ NeighborsCount = length(Neighbors),
+ next_state(CurrState, NeighborsCount).
+
+min_cell(Grid) -> lists:min(Grid).
+max_cell(Grid) -> lists:max(Grid).
+
+all_possible_cells(Grid) ->
+ { MinX, MinY } = min_cell(Grid),
+ { MaxX, MaxY } = max_cell(Grid),
+ [ { X, Y } || X <- lists:seq(MinX - 1, MaxX + 1),
+ Y <- lists:seq(MinY - 1, MaxY + 1) ].
+
+tick(Grid) ->
+ AliveFilter = fun(Cell) ->
+ tick_cell(Cell, Grid) == alive
+ end,
+ lists:filter(AliveFilter, all_possible_cells(Grid)).
+
+-ifdef(TEST).
+-include_lib("../test/gol.hrl").
+-endif.
@@ -0,0 +1,125 @@
+-include_lib("eunit/include/eunit.hrl").
+
+assert_generates_potential_neighbors_correctly_test() ->
+ Cell = { 4, 5 },
+ PotNeighbors = [{ 3, 4 }, { 4, 4 }, { 5, 4 },
+ { 3, 5 }, { 5, 5 },
+ { 3, 6 }, { 4, 6 }, { 5, 6 }],
+ ?assertEqual(gol:pot_neighbors(Cell), lists:sort(PotNeighbors)).
+
+assert_finds_0_neighbors_test() ->
+ Cell = { 4, 5 },
+ Grid = [Cell],
+ Neighbors = [],
+ ?assertEqual(gol:neighbors(Cell, Grid), Neighbors).
+
+assert_finds_1_neighbors_test() ->
+ Cell = { 4, 5 },
+ Grid = [Cell, { 5, 5 }],
+ Neighbors = [{ 5, 5 }],
+ ?assertEqual(gol:neighbors(Cell, Grid), Neighbors).
+
+assert_finds_1_neighbors_with_stranger_cells_test() ->
+ Cell = { 4, 5 },
+ Grid = [Cell, { 5, 5 }, { 9, 9 }],
+ Neighbors = [{ 5, 5 }],
+ ?assertEqual(gol:neighbors(Cell, Grid), Neighbors).
+
+assert_any_live_cell_with_0_neighbors_dies_test() ->
+ Cell = { 5, 5 },
+ Grid = [Cell],
+ ?assertEqual(gol:tick_cell(Cell, Grid), dead).
+
+assert_any_live_cell_with_1_neighbors_dies_test() ->
+ Cell = { 5, 5 },
+ Grid = [Cell, { 5, 6 }],
+ ?assertEqual(gol:tick_cell(Cell, Grid), dead).
+
+assert_any_live_cell_with_2_neighbors_alive_test() ->
+ Cell = { 5, 5 },
+ Grid = [Cell, { 5, 6 }, { 4, 5 }],
+ ?assertEqual(gol:tick_cell(Cell, Grid), alive).
+
+assert_next_state_is_dead_if_lower_than_2_test() ->
+ ?assertEqual(dead, gol:next_state(alive, 0)),
+ ?assertEqual(dead, gol:next_state(alive, 1)).
+
+assert_next_state_is_dead_if_current_state_is_dead_and_has_2_neighbors_test() ->
+ ?assertEqual(dead, gol:next_state(dead, 2)).
+
+assert_next_state_is_alive_if_current_state_is_alive_and_has_more_than_2_neighbors_test() ->
+ ?assertEqual(alive, gol:next_state(alive, 2)).
+
+assert_next_state_is_dead_if_greater_than_3_test() ->
+ ?assertEqual(dead, gol:next_state(alive, 4)),
+ ?assertEqual(dead, gol:next_state(alive, 5)),
+ ?assertEqual(dead, gol:next_state(alive, 6)),
+ ?assertEqual(dead, gol:next_state(alive, 7)),
+ ?assertEqual(dead, gol:next_state(alive, 8)).
+
+assert_next_state_is_alive_if_has_3_neighbors() ->
+ ?assertEqual(alive, gol:next_state(dead, 3)),
+ ?assertEqual(alive, gol:next_state(alive, 3)).
+
+assert_world_any_live_cell_with_0_neighbors_dies_test() ->
+ Grid = [{ 5, 5 }],
+ NextGrid = gol:tick(Grid),
+ ?assertNot(lists:member({ 5, 5 }, NextGrid)).
+
+assert_world_any_live_cell_with_1_neighbors_dies_test() ->
+ Grid = [ { 5, 5 }, { 5, 6 }],
+ NextGrid = gol:tick(Grid),
+ ?assertNot(lists:member({ 5, 5 }, NextGrid)).
+
+assert_world_any_live_cell_with_2_neighbors_lives_test() ->
+ Grid = [ { 4, 5 },
+ { 5, 5 }, { 5, 6 } ],
+ NextGrid = gol:tick(Grid),
+ ?assert(lists:member({ 4, 5 }, NextGrid)).
+
+assert_min_cell_is_the_most_left_and_above_test() ->
+ MinCell = { 0, 0 },
+ Grid = [ { 4, 4 }, MinCell ],
+ ?assertEqual(MinCell, gol:min_cell(Grid)).
+
+assert_max_cell_is_the_most_right_and_below_test() ->
+ MaxCell = { 4, 4 },
+ Grid = [ { 0, 0 }, MaxCell ],
+ ?assertEqual(MaxCell, gol:max_cell(Grid)).
+
+assert_still_life_block_test() ->
+ Grid = [ { 1, 1 }, { 1, 2 },
+ { 2, 1 }, { 2, 2 } ],
+ ?assertEqual(Grid, gol:tick(Grid)).
+
+assert_still_life_beehive_test() ->
+ Grid = [ { 1, 2 }, { 1, 3 },
+ { 2, 1 }, { 2, 4 },
+ { 3, 2 }, { 3, 3 } ],
+ ?assertEqual(Grid, gol:tick(Grid)).
+
+assert_still_life_boat_test() ->
+ Grid = [ { 1, 1 }, { 1, 2 },
+ { 2, 1 }, { 2, 3 },
+ { 3, 2 } ],
+ ?assertEqual(Grid, gol:tick(Grid)).
+
+assert_oscillator_blinker_period_1_test() ->
+ Grid = [ { 1, 1 }, { 1, 2 }, { 1, 3 } ],
+ NextGrid = [ { 0, 2 },
+ { 1, 2 },
+ { 2, 2 } ],
+ ?assertEqual(NextGrid, gol:tick(Grid)),
+ ?assertEqual(Grid, gol:tick(NextGrid)).
+
+assert_oscillator_beacon_test() ->
+ Grid = [ { 1, 1 }, { 1, 2 },
+ { 2, 1 },
+ { 3, 4 },
+ { 4, 3 }, { 4, 4 } ],
+ NextGrid = [ { 1, 1 }, { 1, 2 },
+ { 2, 1 }, { 2, 2 },
+ { 3, 3 }, { 3, 4 },
+ { 4, 3 }, { 4, 4 } ],
+ ?assertEqual(NextGrid, gol:tick(Grid)),
+ ?assertEqual(Grid, gol:tick(NextGrid)).

0 comments on commit 884b6c4

Please sign in to comment.