about summary refs log tree commit diff stats
path: root/lib/Octans/CLI.rakumod
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2022-01-12 12:42:38 +0530
committerAndinus <andinus@nand.sh>2022-01-12 12:42:38 +0530
commit25f65f212c210638d15d73c0c8dfe1fc08bd96a2 (patch)
tree48a98fcd1b0440465eca8e3d8684a306605c3b28 /lib/Octans/CLI.rakumod
parent59d0cd4fbb98cffa28120714b87008573777f429 (diff)
downloadoctans-25f65f212c210638d15d73c0c8dfe1fc08bd96a2.tar.gz
Add visualize feature using Cairo
This takes parts from Fornax: https://github.com/andinus/fornax

Each step is visualized and a video solution is generated.
Diffstat (limited to 'lib/Octans/CLI.rakumod')
-rw-r--r--lib/Octans/CLI.rakumod34
1 files changed, 33 insertions, 1 deletions
diff --git a/lib/Octans/CLI.rakumod b/lib/Octans/CLI.rakumod
index f3501df..4d94b69 100644
--- a/lib/Octans/CLI.rakumod
+++ b/lib/Octans/CLI.rakumod
@@ -1,6 +1,7 @@
 use Octans::Puzzle;
 use Octans::WordSearch;
 use Octans::Puzzle::Get;
+use Octans::GenerateFrame;
 
 proto MAIN(|) is export { unless so @*ARGS { say $*USAGE; exit }; {*} }
 
@@ -9,6 +10,7 @@ multi sub MAIN(
     Str :$dict = (%?RESOURCES<mwords/354984si.ngl> //
                   "/usr/share/dict/words").Str, #= dictionary file
     Int :$length = 7, #= minimum word length (default: 7)
+    Bool :$visualize, #= produces a video output
     Bool :$verbose, #= increase verbosity
 ) is export {
     # @dict holds the sorted dictionary. Only consider words >= 7
@@ -31,18 +33,40 @@ multi sub MAIN(
         "    $_".say for $puzzle.grids;
     }
 
+    constant $SIDE = 128;
+    my Int %meta = :rows($puzzle.grids.elems), :cols($puzzle.grids[0].elems);
+    my Int %canvas = :width(%meta<cols> * $SIDE), :height(%meta<rows> * $SIDE);
+
+    my IO() $output = "%s/octans-%s".sprintf(
+        '/tmp', ('a'...'z', 'A'...'Z', 0...9).roll(8).join
+    );
+    if $visualize {
+        mkdir $output;
+        put "Output: $output";
+        die "Output directory doesn't exist" unless $output.d;
+    }
+
+    my Int $iter = 0;
     # start-pos block loops over each starting position.
     start-pos: for $puzzle.gray-squares -> $pos {
         # gather all the words that word-search finds starting from
         # $pos.
         word: for gather word-search(
-            @dict, $puzzle.grids, $pos[0], $pos[1],
+            @dict, $puzzle.grids, $pos[0], $pos[1], :visualize
         ) -> (
             # word-search returns the word along with @visited which
             # holds the list of all grids that were visited when the
             # word was found.
             $word, @visited
         ) {
+            if $visualize {
+                generate-frame(
+                    :%canvas, :side($SIDE), :puzzle($puzzle.grids), :@visited, :%meta,
+                    :out("%s/%08d.png".sprintf: $output, $iter++), :found($word ne "")
+                );
+                next word;
+            }
+
             printf "%s$word\n", $verbose ?? "\n" !! "";
             next word unless so $verbose;
 
@@ -61,6 +85,14 @@ multi sub MAIN(
             }
         }
     }
+
+    if $visualize {
+        put "Creating a slideshow.";
+        my Str $log-level = $verbose ?? "info" !! "error";
+        run «ffmpeg -loglevel "$log-level" -r 1.5 -i "$output/\%08d.png"
+                    -vf 'tpad=stop_mode=clone:stop_duration=1'
+                    -vcodec libx264 -crf 24 -pix_fmt yuv420p "$output/solution.mp4"»;
+    }
 }
 
 multi sub MAIN(