RosettaCodeData/Task/Flipping-bits-game/Elixir/flipping-bits-game.elixir

68 lines
1.9 KiB
Plaintext

defmodule Flip_game do
@az Enum.map(?a..?z, &List.to_string([&1]))
@in2i Enum.concat(Enum.map(1..26, fn i -> {to_string(i), i} end),
Enum.with_index(@az) |> Enum.map(fn {c,i} -> {c,-i-1} end))
|> Enum.into(Map.new)
def play(n) when n>2 do
target = generate_target(n)
display(n, "Target: ", target)
board = starting_config(n, target)
play(n, target, board, 1)
end
def play(n, target, board, moves) do
display(n, "Board: ", board)
ans = IO.gets("row/column to flip: ") |> String.strip |> String.downcase
new_board = case @in2i[ans] do
i when i in 1..n -> flip_row(n, board, i)
i when i in -1..-n -> flip_column(n, board, -i)
_ -> IO.puts "invalid input: #{ans}"
board
end
if target == new_board do
display(n, "Board: ", new_board)
IO.puts "You solved the game in #{moves} moves"
else
IO.puts ""
play(n, target, new_board, moves+1)
end
end
defp generate_target(n) do
for i <- 1..n, j <- 1..n, into: Map.new, do: {{i, j}, :rand.uniform(2)-1}
end
defp starting_config(n, target) do
Enum.concat(1..n, -1..-n)
|> Enum.take_random(n)
|> Enum.reduce(target, fn x,acc ->
if x>0, do: flip_row(n, acc, x),
else: flip_column(n, acc, -x)
end)
end
defp flip_row(n, board, row) do
Enum.reduce(1..n, board, fn col,acc ->
Map.update!(acc, {row,col}, fn bit -> 1 - bit end)
end)
end
defp flip_column(n, board, col) do
Enum.reduce(1..n, board, fn row,acc ->
Map.update!(acc, {row,col}, fn bit -> 1 - bit end)
end)
end
defp display(n, title, board) do
IO.puts title
IO.puts " #{Enum.join(Enum.take(@az,n), " ")}"
Enum.each(1..n, fn row ->
:io.fwrite "~2w ", [row]
IO.puts Enum.map_join(1..n, " ", fn col -> board[{row, col}] end)
end)
end
end
Flip_game.play(3)