Created
February 8, 2018 01:05
-
-
Save pmarreck/29e2179ccc1d47e74518d5ce5a3937bb to your computer and use it in GitHub Desktop.
Trying to convert a procedural algorithm into an Elixir functional one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule OutcomesProcedural do | |
def partitions(cards, subtotal) do | |
Enum.sum( | |
for i <- 0..9, elem(cards,i)>0 do | |
case subtotal+i+1 do | |
x when x > 21 -> 0 | |
x when x==21 -> 1 | |
x when x < 21 -> 1+partitions(put_elem(cards, i, elem(cards,i)-1), x) | |
end | |
end | |
) | |
end | |
@deck Tuple.append(4 |> Tuple.duplicate(9), 16) # {4, 4, 4, 4, 4, 4, 4, 4, 4, 16} | |
def deck do | |
@deck | |
end | |
def dealer do | |
Enum.sum( | |
for i <- 0..9 do | |
new_deck = put_elem(deck(), i, elem(deck(), i)-1) | |
p = | |
Enum.sum( | |
for j <- 0..9 do | |
OutcomesProcedural.partitions(put_elem(new_deck, j, elem(new_deck, j)-1), j+1) | |
end | |
) | |
IO.puts "Dealer showing #{i} partitions = #{p}" | |
p | |
end | |
) | |
end | |
def run do | |
d = OutcomesProcedural.dealer() | |
IO.puts "Total partitions = #{d}" | |
d | |
end | |
end | |
defmodule OutcomesFunctional do | |
def partitions([_head | _tail] = cards, subtotal, i \\ 0) when i < 10 do | |
Enum.sum( | |
for i <- 0..9, Enum.at(cards, i) > 0 do | |
check_subtotal(subtotal + i, cards, i, &partitions/2) | |
end | |
) | |
end | |
defp check_subtotal(sub, _cards, _i, _func) when sub > 20, do: 0 | |
defp check_subtotal(sub, _cards, _i, _func) when sub == 20, do: 1 | |
defp check_subtotal(sub, cards, i, func) when sub < 20 do | |
1 + func.(List.update_at(cards, i, &(&1 - 1)), sub + 1) | |
end | |
@deck [4, 4, 4, 4, 4, 4, 4, 4, 4, 16] | |
def deck do | |
@deck | |
end | |
def dealer do | |
Enum.sum( | |
# new_deck = deck() |> Enum.map(&(&1 - 1)) | |
for i <- 0..9 do | |
new_deck = List.update_at(deck(), i, &(&1 - 1)) | |
p = | |
Enum.sum( | |
for j <- 0..9 do | |
OutcomesFunctional.partitions(List.update_at(new_deck, j, &(&1 - 1)), j+1) | |
end | |
) | |
IO.puts "Dealer showing #{i} partitions = #{p}" | |
p | |
end | |
) | |
end | |
def run do | |
d = OutcomesFunctional.dealer() | |
IO.puts "Total partitions = #{d}" | |
d | |
end | |
end | |
# run this inline suite with "elixir #{__ENV__.file} test" | |
if System.argv |> List.first == "test" do | |
ExUnit.start | |
defmodule OutcomesTest do | |
use ExUnit.Case, async: true | |
alias OutcomesProcedural, as: Old | |
alias OutcomesFunctional, as: New | |
test "old method" do | |
IO.puts "Old method" | |
assert Old.run() == 6398430 | |
end | |
# the following is currently *slower*. Trying to figure out | |
# how to make things more functional without adding time | |
test "new method" do | |
IO.puts "New method" | |
assert New.run() == 6398430 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment