summary refs log tree commit diff stats
path: root/lib/Tucana/CLI.rakumod
blob: b791d50767aae515013c554d8cf81ead97c9b993 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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;
}