sudoku_dice_game_solver.pl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 30 June 2013
  5. # https://github.com/trizen
  6. # Sudoku dice game solver
  7. use strict;
  8. use warnings;
  9. use List::Util qw(first shuffle);
  10. sub valid_move {
  11. my ($row, $col, $table) = @_;
  12. if (($row < 0 or not exists $table->[$row]) || ($col < 0 or not exists $table->[$row][$col])) {
  13. return;
  14. }
  15. return 1;
  16. }
  17. {
  18. my @moves = (
  19. {dir => 'left', pos => [+0, -1]},
  20. {dir => 'right', pos => [+0, +1]},
  21. {dir => 'up', pos => [-1, +0]},
  22. {dir => 'down', pos => [+1, +0]},
  23. );
  24. sub get_moves {
  25. my ($table, $row, $col, $number) = @_;
  26. my @next_pos;
  27. foreach my $move (@moves) {
  28. if (valid_move($row + $move->{pos}[0], $col + $move->{pos}[1], $table)) {
  29. if ( $table->[$row + $move->{pos}[0]][$col + $move->{pos}[1]] != 0
  30. and $table->[$row + $move->{pos}[0]][$col + $move->{pos}[1]] == $number + 1) {
  31. push @next_pos, $move;
  32. }
  33. }
  34. }
  35. return \@next_pos;
  36. }
  37. }
  38. my @steps;
  39. sub init_universe { # recursion at its best
  40. my ($table, $pos) = @_;
  41. my ($row, $col) = @{$pos};
  42. my $number = $table->[$row][$col];
  43. $table->[$row][$col] = 0;
  44. if ($number == 0) {
  45. pop @steps;
  46. return $table;
  47. }
  48. $number = 0 if $number == 3;
  49. my $moves = get_moves($table, $row, $col, $number);
  50. if (@{$moves}) {
  51. foreach my $move (@{$moves}) {
  52. push @steps, $move;
  53. my $universe = init_universe([map { [@{$_}] } @{$table}], [$row + $move->{pos}[0], $col + $move->{pos}[1]]);
  54. if (
  55. not first {
  56. first { $_ != 0 } @{$_};
  57. }
  58. @{$universe}
  59. ) {
  60. die "solved\n";
  61. }
  62. }
  63. return init_universe($table, [$row, $col]);
  64. }
  65. else {
  66. pop @steps;
  67. return $table;
  68. }
  69. }
  70. #
  71. ## MAIN
  72. #
  73. {
  74. my @rows = qw(
  75. 321321313
  76. 123312222
  77. 321213131
  78. 312231123
  79. 213112321
  80. 231323123
  81. 132231231
  82. 123113322
  83. 321322113
  84. );
  85. my @table;
  86. foreach my $row (@rows) {
  87. push @table, [split //, $row];
  88. }
  89. my @positions;
  90. foreach my $i (0 .. $#table) {
  91. foreach my $j (0 .. $#{$table[$i]}) {
  92. if ($table[$i][$j] == 1) {
  93. push @positions, [$i, $j];
  94. }
  95. }
  96. }
  97. foreach my $pos (shuffle @positions) { # tested solution from position[6]
  98. eval {
  99. init_universe([map { [@{$_}] } @table], $pos);
  100. };
  101. if ($@ eq "solved\n") {
  102. printf "** Locate row %d, column %d, click on it and follow the steps:\n", ($pos->[0] + 1, $pos->[1] + 1);
  103. my $i = 1;
  104. my $count = 1;
  105. my $prev_step = (shift @steps)->{dir};
  106. foreach my $step (@steps) {
  107. if ($step->{dir} eq $prev_step) {
  108. ++$count;
  109. }
  110. else {
  111. printf "%2d. Go %-8s%s", $i++, $prev_step, ($count == 1 ? "\n" : "($count times)\n");
  112. $count = 1;
  113. $prev_step = $step->{dir};
  114. }
  115. }
  116. print "\n";
  117. @steps = ();
  118. }
  119. }
  120. }