Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Trying to convert a procedural algorithm into an Elixir functional one.
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
You can’t perform that action at this time.