summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2021-01-22 13:24:29 +0530
committerAndinus <andinus@nand.sh>2021-01-22 13:24:29 +0530
commit337356b3adb1fe10874fb1ea42a5da24963d9881 (patch)
treebdd0b1d47b26e01e7321ac6d4ca9781b4255686b
downloadtucana-337356b3adb1fe10874fb1ea42a5da24963d9881.tar.gz
Initial commit
-rw-r--r--.gitignore1
-rw-r--r--LICENSE13
-rw-r--r--README.org13
-rwxr-xr-xbin/tucana3
-rw-r--r--lib/Tucana/CLI.rakumod66
5 files changed, 96 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4a5e4c7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+lib/.precomp
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e51df07
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2021, Andinus <andinus@nand.sh>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..2a9194b
--- /dev/null
+++ b/README.org
@@ -0,0 +1,13 @@
+#+SETUPFILE: ~/.emacs.d/org-templates/projects.org
+#+EXPORT_FILE_NAME: index
+#+OPTIONS: toc:2
+#+TITLE: Tucana
+
+Tucana is a program to generate puzzles like Algot's Wordsearch.
+
+- Website: https://andinus.nand.sh/tucana
+- Source: https://git.tilde.institute/andinus/tucana
+- GitHub: https://github.com/andinus/tucana
+
+It's a work in progress. Currently it uses a very naive approach of just
+walking around the grid & chosing a random neighbor.
diff --git a/bin/tucana b/bin/tucana
new file mode 100755
index 0000000..c515c81
--- /dev/null
+++ b/bin/tucana
@@ -0,0 +1,3 @@
+#!/usr/bin/env raku
+
+use Tucana::CLI;
diff --git a/lib/Tucana/CLI.rakumod b/lib/Tucana/CLI.rakumod
new file mode 100644
index 0000000..b791d50
--- /dev/null
+++ b/lib/Tucana/CLI.rakumod
@@ -0,0 +1,66 @@
+unit module Tucana::CLI;
+
+use Octans::Neighbors;
+
+# If no arguments are passed then run USAGE & exit.
+proto MAIN (|) is export {unless so @*ARGS {say $*USAGE; exit;}; {*}}
+
+multi sub MAIN (Bool :$version) {
+    say "Tucana v" ~ $?DISTRIBUTION.meta<version>;
+}
+
+multi sub MAIN (
+    Str $word, #= word for the puzzle
+    Bool :v($verbose), #= increase verbosity
+) {
+    my @puzzle := generate-puzzle($word);
+    "  $_".say for @puzzle;
+}
+
+# generate-puzzle generates a 3x3 puzzle with $word in there.
+sub generate-puzzle (
+    Str $word,
+) {
+    my @puzzle := [
+        [<_ _ _ _>],
+        [<_ _ _ _>],
+        [<_ _ _ _>],
+        [<_ _ _ _>],
+    ];
+
+    my Int ($y, $x) = edges(@puzzle).pick;
+    @puzzle[$y][$x] = $word.comb[0];
+
+    my @visited;
+    @visited[$y][$x] = True;
+
+    my Int $count = 1;
+    while $count < $word.chars {
+        neighbor: for neighbors(@puzzle, $y, $x).pick(*) -> ($pos-y, $pos-x) {
+            next neighbor if @visited[$pos-y][$pos-x];
+            @visited[$pos-y][$pos-x] = True;
+
+            @puzzle[$pos-y][$pos-x] = $word.comb[$count];
+            ($y, $x) = ($pos-y, $pos-x);
+            last neighbor;
+        }
+
+        $count++;
+    }
+
+    return @puzzle;
+}
+
+# edges takes a 2d grid & returns the list of edges, i.e. squares with
+# < 4 neighbors.
+sub edges (
+    @puzzle --> List
+) {
+    my List @edges;
+    for 0 .. @puzzle.end -> $y {
+        for 0 .. @puzzle[$y].end -> $x {
+            push @edges, ($y, $x) if neighbors(@puzzle, $y, $x).elems < 4;
+        }
+    }
+    return @edges;
+}