2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,33 +1,21 @@
|
|||
defmodule Sudoku do
|
||||
def display( grid ), do: ( for y <- 1..9, do: display_row(y, grid) )
|
||||
|
||||
def start( knowns ), do: :dict.from_list( knowns )
|
||||
def start( knowns ), do: Enum.into( knowns, Map.new )
|
||||
|
||||
def solve( grid ) do
|
||||
sure = solve_all_sure( grid )
|
||||
solve_unsure( potentials(sure), sure )
|
||||
end
|
||||
|
||||
def task do
|
||||
simple = [{{1, 1}, 3}, {{2, 1}, 9}, {{3, 1},4}, {{6, 1}, 2}, {{7, 1}, 6}, {{8, 1}, 7},
|
||||
{{4, 2}, 3}, {{7, 2}, 4},
|
||||
{{1, 3}, 5}, {{4, 3}, 6}, {{5, 3}, 9}, {{8, 3}, 2},
|
||||
{{2, 4}, 4}, {{3, 4}, 5}, {{7, 4}, 9},
|
||||
{{1, 5}, 6}, {{9, 5}, 7},
|
||||
{{3, 6}, 7}, {{7, 6}, 5}, {{8, 6}, 8},
|
||||
{{2, 7}, 1}, {{5, 7}, 6}, {{6, 7}, 7}, {{9, 7}, 8},
|
||||
{{3, 8}, 9}, {{6, 8}, 8},
|
||||
{{2, 9}, 2}, {{3, 9}, 6}, {{4, 9}, 4}, {{7, 9}, 7}, {{8, 9}, 3}, {{9, 9}, 5}]
|
||||
task( simple )
|
||||
difficult = [{{6, 2}, 3}, {{8, 2}, 8}, {{9, 2}, 5},
|
||||
{{3, 3}, 1}, {{5, 3}, 2},
|
||||
{{4, 4}, 5}, {{6, 4}, 7},
|
||||
{{3, 5}, 4}, {{7, 5}, 1},
|
||||
{{2, 6}, 9},
|
||||
{{1, 7}, 5}, {{8, 7}, 7}, {{9, 7}, 3},
|
||||
{{3, 8}, 2}, {{5, 8}, 1},
|
||||
{{5, 9}, 4}, {{9, 9}, 9}]
|
||||
task( difficult )
|
||||
def task( knowns ) do
|
||||
IO.puts "start"
|
||||
start = start( knowns )
|
||||
display( start )
|
||||
IO.puts "solved"
|
||||
solved = solve( start )
|
||||
display( solved )
|
||||
IO.puts ""
|
||||
end
|
||||
|
||||
defp bt( grid ), do: bt_reject( is_not_allowed(grid), grid )
|
||||
|
|
@ -35,7 +23,7 @@ defmodule Sudoku do
|
|||
defp bt_accept( true, board ), do: throw( {:ok, board} )
|
||||
defp bt_accept( false, grid ), do: bt_loop( potentials_one_position(grid), grid )
|
||||
|
||||
defp bt_loop( {position, values}, grid ), do: ( for x <- values, do: bt( :dict.store(position, x, grid) ) )
|
||||
defp bt_loop( {position, values}, grid ), do: ( for x <- values, do: bt( Map.put(grid, position, x) ) )
|
||||
|
||||
defp bt_reject( true, _grid ), do: :backtrack
|
||||
defp bt_reject( false, grid ), do: bt_accept( is_all_correct(grid), grid )
|
||||
|
|
@ -46,99 +34,96 @@ defmodule Sudoku do
|
|||
end
|
||||
|
||||
defp display_row_group( start, row, grid ) do
|
||||
for x <- [start, start+1, start+2], do: :io.fwrite(" ~c", [display_value(x, row, grid)])
|
||||
IO.write( " " )
|
||||
Enum.each(start..start+2, &IO.write " #{Map.get( grid, {&1, row}, ".")}")
|
||||
IO.write " "
|
||||
end
|
||||
|
||||
defp display_row_nl( n ) when n == 3 or n == 6 or n == 9, do: IO.puts "\n"
|
||||
defp display_row_nl( _N ), do: IO.puts ""
|
||||
defp display_row_nl( n ) when n in [3,6,9], do: IO.puts "\n"
|
||||
defp display_row_nl( _n ), do: IO.puts ""
|
||||
|
||||
defp display_value( x, y, grid ), do: display_value( :dict.find({x, y}, grid) )
|
||||
|
||||
defp display_value( :error ), do: ?.
|
||||
defp display_value( {:ok, value} ), do: value + ?0
|
||||
|
||||
defp is_all_correct( grid ), do: :dict.size( grid ) == 81
|
||||
defp is_all_correct( grid ), do: map_size( grid ) == 81
|
||||
|
||||
defp is_not_allowed( grid ) do
|
||||
is_not_allowed_rows( grid ) or is_not_allowed_columns( grid ) or is_not_allowed_groups( grid )
|
||||
end
|
||||
|
||||
defp is_not_allowed_columns( grid ), do: Enum.any?( values_all_columns(grid), fn x-> is_not_allowed_values(x) end)
|
||||
defp is_not_allowed_columns( grid ), do: values_all_columns(grid) |> Enum.any?(&is_not_allowed_values/1)
|
||||
|
||||
defp is_not_allowed_groups( grid ), do: Enum.any?( values_all_groups(grid), fn x-> is_not_allowed_values(x) end)
|
||||
defp is_not_allowed_groups( grid ), do: values_all_groups(grid) |> Enum.any?(&is_not_allowed_values/1)
|
||||
|
||||
defp is_not_allowed_rows( grid ), do: Enum.any?( values_all_rows(grid), fn x-> is_not_allowed_values(x) end)
|
||||
defp is_not_allowed_rows( grid ), do: values_all_rows(grid) |> Enum.any?(&is_not_allowed_values/1)
|
||||
|
||||
defp is_not_allowed_values( values ), do: length( values ) != length( Enum.uniq(values) )
|
||||
|
||||
defp group_positions( {x, y} ), do: ( for colum <- group_positions_close(x), row <- group_positions_close(y), do: {colum, row} )
|
||||
defp group_positions( {x, y} ) do
|
||||
for colum <- group_positions_close(x), row <- group_positions_close(y), do: {colum, row}
|
||||
end
|
||||
|
||||
defp group_positions_close( n ) when n < 4, do: [1,2,3]
|
||||
defp group_positions_close( n ) when n < 7, do: [4,5,6]
|
||||
defp group_positions_close( _n ) , do: [7,8,9]
|
||||
|
||||
defp positions_not_in_grid( grid ) do
|
||||
keys = :dict.fetch_keys( grid )
|
||||
for x <- 1..9, y <- 1..9, not Enum.member?(keys, {x, y}), do: {x, y}
|
||||
keys = Map.keys( grid )
|
||||
for x <- 1..9, y <- 1..9, not {x, y} in keys, do: {x, y}
|
||||
end
|
||||
|
||||
defp potentials_one_position( grid ) do
|
||||
[{_shortest, position, values} | _t] = Enum.sort( for {position, values} <- potentials( grid ), do: {length(values), position, values} )
|
||||
{position, values}
|
||||
Enum.min_by( potentials( grid ), fn {_position, values} -> length(values) end )
|
||||
end
|
||||
|
||||
defp potentials( grid ), do: List.flatten( for x <- positions_not_in_grid(grid), do: potentials(x, grid) )
|
||||
|
||||
defp potentials( position, grid ) do
|
||||
useds = potentials_used_values( position, grid )
|
||||
{position, (for value <- :lists.seq(1, 9) -- useds, do: value) }
|
||||
{position, Enum.to_list(1..9) -- useds }
|
||||
end
|
||||
|
||||
defp potentials_used_values( {x, y}, grid ) do
|
||||
row_values = (for row <- 1..9, row != x, do: {row, y}) |> potentials_values( grid )
|
||||
column_values = (for column <- 1..9, column != y, do: {x, column}) |> potentials_values( grid )
|
||||
group_values = List.delete( group_positions({x, y}), {x, y} ) |> potentials_values( grid )
|
||||
group_values = group_positions({x, y}) -- [ {x, y} ] |> potentials_values( grid )
|
||||
row_values ++ column_values ++ group_values
|
||||
end
|
||||
|
||||
defp potentials_values( keys, grid ) do
|
||||
row_values_unfiltered = for x <- keys, do: :dict.find(x, grid)
|
||||
for {:ok, value} <- row_values_unfiltered, do: value
|
||||
for x <- keys, val = grid[x], do: val
|
||||
end
|
||||
|
||||
defp values_all_columns( grid ), do: ( for x <- 1..9, do: values_all_columns(x, grid) )
|
||||
|
||||
defp values_all_columns( x, grid ) do
|
||||
( for y <- 1..9, do: {x, y} ) |> potentials_values( grid )
|
||||
defp values_all_columns( grid ) do
|
||||
for x <- 1..9, do:
|
||||
( for y <- 1..9, do: {x, y} ) |> potentials_values( grid )
|
||||
end
|
||||
|
||||
defp values_all_groups( grid ) do
|
||||
[[g1,g2,g3], [g4,g5,g6], [g7,g8,g9]] = for x <- [1, 4, 7], do: values_all_groups(x, grid)
|
||||
[[g1,g2,g3], [g4,g5,g6], [g7,g8,g9]] = for x <- [1,4,7], do: values_all_groups(x, grid)
|
||||
[g1,g2,g3,g4,g5,g6,g7,g8,g9]
|
||||
end
|
||||
|
||||
defp values_all_groups( x, grid ), do: ( for x_offset <- [x, x+1, x+2], do: values_all_groups(x, x_offset, grid) )
|
||||
defp values_all_groups( x, grid ) do
|
||||
for x_offset <- x..x+2, do: values_all_groups(x, x_offset, grid)
|
||||
end
|
||||
|
||||
defp values_all_groups( _x, x_offset, grid ) do
|
||||
( for y_offset <- group_positions_close(x_offset), do: {x_offset, y_offset} )
|
||||
|> potentials_values( grid )
|
||||
end
|
||||
|
||||
defp values_all_rows( grid ), do: ( for y <- 1..9, do: values_all_rows(y, grid) )
|
||||
|
||||
defp values_all_rows( y, grid ) do
|
||||
( for x <- 1..9, do: {x, y} ) |> potentials_values( grid )
|
||||
defp values_all_rows( grid ) do
|
||||
for y <- 1..9, do:
|
||||
( for x <- 1..9, do: {x, y} ) |> potentials_values( grid )
|
||||
end
|
||||
|
||||
defp solve_all_sure( grid ), do: solve_all_sure( solve_all_sure_values(grid), grid )
|
||||
|
||||
defp solve_all_sure( [], grid ), do: grid
|
||||
defp solve_all_sure( sures, grid ), do: solve_all_sure( List.foldl(sures, grid, fn(x,acc)-> solve_all_sure_store(x,acc) end) )
|
||||
defp solve_all_sure( sures, grid ) do
|
||||
solve_all_sure( Enum.reduce(sures, grid, &solve_all_sure_store/2) )
|
||||
end
|
||||
|
||||
defp solve_all_sure_values( grid ), do: (for{position, [value]} <- potentials(grid), do: {position, value} )
|
||||
|
||||
defp solve_all_sure_store( {position, value}, acc ), do: :dict.store( position, value, acc )
|
||||
defp solve_all_sure_store( {position, value}, acc ), do: Map.put( acc, position, value )
|
||||
|
||||
defp solve_unsure( [], grid ), do: grid
|
||||
defp solve_unsure( _potentials, grid ) do
|
||||
|
|
@ -148,16 +133,25 @@ defmodule Sudoku do
|
|||
{:ok, board} -> board
|
||||
end
|
||||
end
|
||||
|
||||
defp task( knowns ) do
|
||||
IO.puts "start"
|
||||
start = start( knowns )
|
||||
display( start )
|
||||
IO.puts "solved"
|
||||
solved = solve( start )
|
||||
display( solved )
|
||||
IO.puts ""
|
||||
end
|
||||
end
|
||||
|
||||
Sudoku.task
|
||||
simple = [{{1, 1}, 3}, {{2, 1}, 9}, {{3, 1},4}, {{6, 1}, 2}, {{7, 1}, 6}, {{8, 1}, 7},
|
||||
{{4, 2}, 3}, {{7, 2}, 4},
|
||||
{{1, 3}, 5}, {{4, 3}, 6}, {{5, 3}, 9}, {{8, 3}, 2},
|
||||
{{2, 4}, 4}, {{3, 4}, 5}, {{7, 4}, 9},
|
||||
{{1, 5}, 6}, {{9, 5}, 7},
|
||||
{{3, 6}, 7}, {{7, 6}, 5}, {{8, 6}, 8},
|
||||
{{2, 7}, 1}, {{5, 7}, 6}, {{6, 7}, 7}, {{9, 7}, 8},
|
||||
{{3, 8}, 9}, {{6, 8}, 8},
|
||||
{{2, 9}, 2}, {{3, 9}, 6}, {{4, 9}, 4}, {{7, 9}, 7}, {{8, 9}, 3}, {{9, 9}, 5}]
|
||||
Sudoku.task( simple )
|
||||
|
||||
difficult = [{{6, 2}, 3}, {{8, 2}, 8}, {{9, 2}, 5},
|
||||
{{3, 3}, 1}, {{5, 3}, 2},
|
||||
{{4, 4}, 5}, {{6, 4}, 7},
|
||||
{{3, 5}, 4}, {{7, 5}, 1},
|
||||
{{2, 6}, 9},
|
||||
{{1, 7}, 5}, {{8, 7}, 7}, {{9, 7}, 3},
|
||||
{{3, 8}, 2}, {{5, 8}, 1},
|
||||
{{5, 9}, 4}, {{9, 9}, 9}]
|
||||
Sudoku.task( difficult )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue