-
Notifications
You must be signed in to change notification settings - Fork 319
/
ch-1.raku
120 lines (112 loc) · 3.54 KB
/
ch-1.raku
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# Three solutions.
# My "official" answer to the task.
# For any two adjacent rows, all elements (except the last ) of the first row
# must match all elements (except the first) of the next row.
# With a small refactor to use an iterator and @last&@this rows,
# this would work efficiently with an enormous number of rows.
sub task1 ( @m --> Bool ) {
for @m.rotor( 2 => -1 ) -> ( $top, $bottom ) {
return False unless $top.head(*-1) eqv $bottom.skip(1);
}
return True;
}
# All credit for this idea goes to Mark Anderson:
# @m[ ^@m.end; ^@m[0].end ] eqv @m[ 1..@m.end; 1..@m[1].end ]
# https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-211/mark-anderson/raku/ch-1.raku#L24
# A Toeplitz matrix minus its right and bottom edges will be identical
# to that matrix minus its left and top edges.
# Mark's range-and-semicolon wording is a perfect expression of that idea, if you already know that idea.
# I wrote my version differently, attempting to better convey the idea to those who *don't* already know it.
# Then, I ended up writing all this text anyway, so my success is doubtful.
sub task1_concise ( @m ) {
return @m.head(*-1).map({ .head(*-1) }) # Omitting bottom and right edges.
eqv @m.tail(*-1).map({ .tail(*-1) }); # Omitting top and left edges.
}
# This is the first thing I wrote when I read the task.
# Walking each element of the first row,
# it checks that every value matches along the diagonal,
# returning False on a mis-match.all the diagonal values checks each diagonal.
# Since that process misses all the diagonal starting points (besides [0,0])
# on the left edge of the matrix, the second loop handles those.
sub task1_first_attempt ( @m --> Bool ) {
for @m[0].keys -> $col {
my $first_of_top_edge = @m[0][$col];
for 1 .. min(@m.end, @m[0].end - $col) -> $row {
return False unless @m[$row][$col+$row] eqv $first_of_top_edge;
}
}
for @m.keys.skip -> $row {
my $first_of_left_edge = @m[$row][0];
for 1 .. min(@m[0].end, @m.end-$row) -> $col {
return False unless @m[$row+$col][$col] eqv $first_of_left_edge;
}
}
return True;
}
my @tests =
(
(
< 4 3 2 1 >,
< 5 4 3 2 >,
< 6 5 4 3 >,
),
True,
),
(
(
< 1 2 3 >,
< 3 2 1 >,
),
False,
),
# Example 1, but final element differs
(
(
< 4 3 2 1 >,
< 5 4 3 2 >,
< 6 5 4 9 >,
),
False,
),
(
(
< A B C D E F G H I J K >,
< Z A B C D E F G H I J >,
< Y Z A B C D E F G H I >,
< X Y Z A B C D E F G H >,
< W X Y Z A B C D E F G >,
< V W X Y Z A B C D E F >,
< U V W X Y Z A B C D E >,
),
True,
),
(
( # Just like last test, but `V` on last line now `_`
< A B C D E F G H I J K >,
< Z A B C D E F G H I J >,
< Y Z A B C D E F G H I >,
< X Y Z A B C D E F G H >,
< W X Y Z A B C D E F G >,
< V W X Y Z A B C D E F >,
< U _ W X Y Z A B C D E >,
),
False,
),
(
(
< A B C >,
< Z A B >,
< Y Z A >,
< X Y Z >,
< W X Y >,
< V W X >,
< U V W >,
),
True,
),
;
use Test;
plan +@tests;
for @tests -> ( $in, $expected ) {
is task1($in), $expected;
}