Jactl now offers a `switch`

expression similar to Java but with more powerful pattern matching with destructuring.
Unlike Java, there is no `case`

keyword used so a simple `switch`

expression would look like this:

```
switch (x) {
1,3,5,7,9 -> println 'odd'
2,4,6,8,10 -> println 'even'
default -> println 'unknown'
}
```

Since `switch`

is actually an expression and returns a value, you could also write it like this:

```
println switch (x) {
1,3,5,7,9 -> 'odd'
2,4,6,8,10 -> 'even'
default -> 'unknown'
}
```

As well as matching simple literal values such as numbers and Strings you can match on a type pattern:

```
switch (x) {
String -> 'string'
int,long -> 'whole number'
double,Decimal -> 'decimal number'
}
```

Any type of pattern can be followed by an `if`

clause to specify additional conditions that must be met for the
match.
The `it`

variable is bound to the value being switched on and can be referred to within the `if`

and within the
result:

```
switch (str.substring(3)) {
/content=/r if it.size() < 20 -> 'short content'
/name="(.*)".*type="(.*)"/r -> "name is $1,type is $2" // Regex match with capture variables
}
```

List and Map patterns can also be matched against and `_`

can be used to match any value and `*`

can be used to
match any number of values:

```
switch (x) {
[1,2,3] -> 'matched'
[int,String,long] -> 'matched' // List with an int, a String, and a long
[_,_] -> 'matched' // List of size 2
[1,*,4] -> 'matched' // List where 1st element is 1 and last is 4 (size is at least 2)
[name:_,*] -> 'matched' // Map that has an entry of 'name' of any value
}
```

Destructuring is supported where a binding variable can be supplied that will bind to that part of the structure if the overall pattern matches:

```
switch (x) {
[a,b,c] -> a+b+c // Match 3 element list and return sum of the elements
}
```

Binding variables can occur multiple times and for the pattern to match the values of the binding variable must be the same at all locations. They can also be specified with a type to match on a specific type at that location:

```
switch (x) {
[a,_,a] -> 'matched' // First and last elements must be the same
[_,[int a,a]] -> 'matched' // Second element is a pair of ints of same value
}
```

See blog post on Pattern Matching and Destructuring for more details and examples.

A new keyword `const`

allows you to create named constants:

```
const Decimal PI = 3.1415926536
def area = PI * radius.sqr()
```

The type is optional and will be inferred from the type of constant expression of the initialiser:

```
const PI = 3.1415926536
const RADIUS = 100
const AREA = PI * RADIUS * RADIUS
```

`import`

statements can now selectively import static methods and constants from other classes into the current
script/class:

```
import static utils.Math.PI
import static utils.Math.circleArea
def area = circleArea(100)
def circumference = 2 * PI * 100
```

`as`

can be used to give another name to the item being imported:

```
import static utils.Math.circleArea as area
def x = area(100)
```

The use of `*`

to import all static functions and constants from a class is also supported:

```
import static utils.Math.*
```

`do/until`

Loops (#54)Jactl does not support `do/while`

loops (see FAQ) but now has
support for `do/until`

loops that loop *until* a condition is met:

```
int countTokens = 0;
do {
countTokens++
} until (nextToken().isEof())
```

`groupBy()`

Method for Lists (#55)Jactl has added a `groupBy()`

method for lists that, given a closure that returns the key
for a given list element, will group elements with the same key and return a Map of lists
where the lists contain all elements with the same key.
For example, to group words of the same length together:

```
['list', 'of', 'words', 'with', 'different', 'sizes'].groupBy{ it.size().toString() }
```

Result will be:

```
['4':['list', 'with'], '2':['of'], '5':['words', 'sizes'], '9':['different']]
```

`transpose()`

Method for Lists (#56)`transpose()`

works as a matrix transpose where rows are transposed into columns (and columns
into rows).
It operates on a list of lists:

```
[ ['a',1], ['b',2], ['c',3] ].transpose()
```

Result is:

```
[['a', 'b', 'c'], [1, 2, 3]]
```

If the input lists are not all the same size, `null`

will be used to fill any missing values.

Jactl has introduced these new keywords in version 2.0.0:

`const`

`until`

`switch`

`default`

`do`

Blocks Return Value of Last Expression/Statement (#53)To make the language more consistent, `do`

blocks now work like functions/closures and return the
value of the last expression/statement rather than always returning `true`

.

Previously there were inconsitencies with how byte values were treated. Sometimes negative byte values were allowed, and sometimes they were automatically converted to the equivalent postive value.

To make the language more consistent, byte values are always treated as positive values between
`0`

and `255`

.

If a negative value is supplied it will be automatically converted into the appropriate postive
value.
For example, `(byte)-1`

will be converted to `255`

.

`++`

and `--`

on Constant Values is Now InvalidPreviously, expressions such as `++1`

was allowed (and would return `2`

in this case).
Now, this will cause a compile-time error.

This change was needed as part of the support for named constants to make sure that code does not try to modify a constant.

]]>The `switch`

expression in its simplest form works like a `switch`

expression in Java (first introduced in Java 17)
where you pass an expression to `switch()`

and then have a list of values to match against with a result for each match.

In Jactl there is no equivalent to a `switch`

statement like there is in Java.
The Jactl `switch`

expression can be used as either a statement (if you ignore the result) or an expression.

Note that there is no fall through between different cases and so `break`

will not break out of the switch, but will
break out of whatever enclosing `for`

/`while`

loop the `switch`

is contained within.

The main difference, syntactically, between Jactl `switch`

and Java `switch`

is that Jactl does not require the `case`

keyword (and use of `;`

is optional if new lines are used).

Here is a simple example:

```
switch(x) {
1 -> println 'one'
2 -> println 'two'
default -> println 'unknown'
}
```

Note that, as in Java, an optional `default`

case can be used to specify the behaviour when none of the
cases match.

If you want to put more than one case on the same line then `;`

can be used as a separator:

```
switch(x) { 1 -> println 'one'; 2 -> println 'two' }
```

If the result of the match involves multiple statements then they need to be wrapped in `{`

and `}`

:

```
switch(x) {
'Fred' -> {
fred++
println "Fred: $fred"
}
'Barney' -> {
barney++
println "Barney: $barney"
}
}
```

In Jactl, `switch`

is actually an expression so the code after each `->`

is evaluated and the resulting
value is returned if that case succeeded:

```
def result = switch(x) {
1 -> 'one'
2 -> 'two'
default -> 'unknown'
}
```

If the code for the matching case does not result in an actual value (for example the last statement is a `while`

loop)
then `null`

is returned.
Note that invoking `return`

from within a `switch`

case will return from the enclosing function rather than cause
the `switch`

expression to return that value.

If multiple values should map to the same result you can separate the values with commas:

```
switch(x) {
1,3,5,7,9 -> 'odd'
2,4,6,8,10 -> 'even'
}
```

As we have seen in the examples so far, we can use `switch`

expressions to match on literals which are standard
primitive types such as `int`

, `long`

, `double`

, `String`

and so on.

We can also use literals which are `List`

or `Map`

literals, and we can support different literal types in the same
`switch`

(if the type of the value which is the subject of the `switch`

permits the comparison):

```
switch(x) {
1,2,3,4,'abc' -> 'primitive'
[1,2,3],[4,5] -> 'list'
[a:1,b:[4,5]] -> 'map'
}
```

If you try to match against a literal whose type is incompatible with the type of the subject of the `switch`

then
you will get a compile error.
For example:

```
int x = 2
switch(x) {
1,2 -> x
'abc' -> "x=$x"
}
```

```
io.jactl.CompileError: Type int can never match type String @ line 4, column 3
'abc' -> "x=$x"
^
```

In addition to matching against literal values, Jactl also supports testing if an expression is of a given type:

```
switch(x) {
String -> 'string'
int,long -> 'integer'
double,Decimal -> 'floating point'
}
```

Types and literal values can be mixed in the same `switch`

expression:

```
switch(x) {
1,2,String -> '1, 2, or string'
int,long -> 'other integral value'
}
```

Note that if the order of the matches was the other way around you will get a compile error since `int`

already covers
the case of all int values:

```
switch(x) {
int,long -> 'other integral value'
1,2,String -> '1, 2, or string'
}
```

```
Switch pattern will never be evaluated (covered by previous pattern) @ line 3, column 3
1,2,String -> '1, 2, or string'
^
```

User classes can also be matched against:

```
class X {}
class Y extends X {}
def x = new Y()
switch(x) {
Y -> 'type is Y'
X -> 'type is X'
}
```

Again, if the match on type `X`

in the example was before the match on type `Y`

you will get a compile error since
the match on `Y`

can never succeed if it appears after the match on its parent class.

Switch expressions can also be used to do regular expression matches and support the use of capture variables like
`$1`

in the result for that match case:

```
switch(x) {
/(.*)\+(.*)/n -> $1 + $2
/(.*)-(.*)/n -> $1 - $2
default -> 0
}
```

Note that if the regex pattern has no modifiers after it then it will be treated as a standard expression string
and a literal match will occur instead.
To force it to be a regular expression match you must use a modifier (such as `n`

in the example, which forces the
capture variables to be treated as numbers where possible).
The `r`

modifier can be used to force the string to be treated as a regular expression if no other modifier is
appropriate.

There were previous examples showing matches on literals of type `List`

and `Map`

.
When matching against a list or map we can use `_`

as a wildcard to match against arbitrary values within the list
or map:

```
switch(x) {
[_,_,_] -> 'a list of size 3'
[_,3] -> 'list of size 2 where last element is 3'
[k1:_,k2:_] -> 'a map of size 2 with keys k1 and k2'
}
```

We can use `*`

to match any number of elements:

```
switch(x) {
[_,_,*] -> 'a list with at least two elements'
[k:_,*] -> 'a map with at least one element with key k'
}
```

If you want to be able to specify the type of the wildcard you can use a type name instead of `_`

:

```
switch(x) {
[int,int,String] -> '2 ints and a string'
[int,String,*] -> 'list starting with int and string'
[k1:int,k2:String] -> 'map with k1 value being an int and k2 value being a String'
}
```

By specifying an identifier you can create a binding variable that binds to that part of the structure in the expression
being switched on (hence the term *destructuring*):

For example, we can match a list or map and extract different elements of the list or map:

```
switch(x) {
[a,2] -> a + a // a will be bound to first element of list if second element is 2
[a,*,b] -> a + b // a bound to 1st element and b bound to last element
[k1:a,k2:b,*] -> a + b // a bound to value at k1 and b to value at k2
}
```

Note that for map literals, only the value can be bound to a binding variable. The keys themselves are literal values, not binding variables.

Binding variables can occur multiple times but will only match if the value for the variable is the same in all places where it is used:

```
switch(x) {
[a,a] -> "a=$a" // match all 2 element lists where both elements are the same
[a,_,a] -> "a=$a" // 3 element list where first and last are the same
}
```

Binding variables can also be typed if you want to match on the type:

```
switch(x) {
[int a,int b], [a] -> "a=$a" // match 1 or 2 element list if first element is an int
[int a, b, *] -> "a=$a, b=$b" // match if first element is int
}
```

Note that binding variables are shared across all patterns in the same comma separated list (see first pattern list in the example above). This means that their type can only be specified the first time they occur in the pattern list and that if the variable is used in a subsequent pattern (in the same comma separated list), it inherits the same type and will only match if the type matches.

Binding variables can occur anywhere within the structure being matched against, no matter how deep the nesting:

```
switch(x) {
[[a,b],*,[[a,*],[b,*]]] -> a + b
}
```

Binding variables can appear at the top level of a pattern as well and can also have a type:

```
switch(x) {
String s -> "string with value $s"
int i -> "int with value $i"
a -> "other type with value $a"
}
```

The wildcard variable `_`

can also appear at the top level and can be used as way to provide a `default`

case instead
of using `default`

:

```
switch(x) {
1,2,3 -> 'number'
_ -> 'other'
}
```

Note that if you use `_`

like this where it will match everything, it must occur last since otherwise the other cases
would never be evaluated.
This is different to the `default`

which can occur anywhere in the list of match cases.

As well as destructured matching based on type, you can also use a regular expression to match a string at a particular location within a nested structure:

```
switch (x) {
[/^abc/r, /xyz$/r] -> 'list of size 2 where first starts with abc and second ends in xyz'
[name:_, age:/^\d+$/r] -> "map has key called name and key called age whose value is a string of digits"
}
```

Note that if you use a capture group within the regular expressions then the capture variables will refer to the last
regular expression in the pattern.
For example, in the following code `$1`

will never correspond to the capture group in the first regular expression.
It will only have a value for the match on the second regex:

```
switch (x) {
[/^(a|b)+/r, /^(x|y|z)/r] -> "$1 will be x or y or z"
}
```

`it`

If you don’t specify a subject expression for the `switch`

to switch on then it will switch on the implicit `it`

variable.
For example, we can read lines from stdin and parse them using `switch`

like this since the closure passed to `map`

has an implicit `it`

parameter:

```
stream(nextLine).map{
switch {
/(.*)\+(.*)/n -> $1 + $2
/(.*)-(.*)/n -> $1 - $2
default -> die "Bad input: $it"
}
}
```

If you are in a context where there is no `it`

then you will get an error about a reference to an unknown `it`

variable.

Within the `switch`

expression itself, the `it`

variable is bound to the value of the expression passed to `switch`

.
For example:

```
switch(x.substring(3,6)) {
'ABC','XYZ' -> "${it.toLowerCase()}:123" // it has value of x.substring(3,6)
'XXY' -> 'xxy789'
}
```

In addition to specifying a pattern or literal value to match against, each pattern/literal can also have an
optional `if`

expression that is evaluated if the pattern/literal matches which must then also evaluate to true
for that case to match:

```
switch(x.substring(3,6)) {
'ABC' if x.size() < 10, 'XYZ' if x.size() > 5 -> "${it}${it}"
'XXY' if x[0] == 'a' -> 'xxy'
}
```

Within the `if`

expression references to any binding variables and to `it`

are allowed:

```
switch(x) {
[int a,*] if a < 3 -> "list starts with $a < 3"
[String a,*] if x.size() < 5 -> "list with < 5 elems starts with string $a"
[a,*,b] if a.size() == b.size() -> "first and last elem of same size"
_ if x.size() == 0 -> 'empty list/string/map'
_ if x.size() == 1 -> 'single element list/map or single char string'
_ -> 'everything else'
}
```

To match on multiple values at the same time just pass a list of the values to the `switch`

:

```
switch([x,y]) {
[a,a] -> 'x equals y'
[[a,*],[*,a]] -> 'first elem of x is same as last elem of y'
}
```

As mentioned, you can match on a type that is a user defined class. To match based on the field values use the constructor form of the class as the pattern.

For example:

```
class X { int i; int j; List list = [] }
X x = new X(i:2, j:3, list:[1,2,[3]])
switch(x) {
X(i:1) -> 'type is X: field i is 1'
X(list:[3,4]) -> 'X with list field being [3,4]'
}
```

If you use the constructor form with named fields (as in the example above) then you only need specify which field values you are interested in. All other fields can have any value to match that pattern.

The constructor form that does not use named field values requires you to supply values for all mandatory fields:

```
class X { int i; int j; List list = [] }
X x = new X(i:2, j:3, list:[1,2,[3]])
switch(x) {
X(1,3) -> 'type is X: i=1, j=3'
X(_,4) -> 'any X as long as j=4'
}
```

As for Maps and Lists you can “destructure” the fields to bind variables to field values or values within field values:

```
switch (x) {
X(i:i,j:j) -> "X with i=$i, j=$j"
X(list:[_,_,a]) -> "type is X: last elem of X.list is $a"
}
```

If you want to have a pattern that depends on the value of an existing variable then you can use `$`

to expand the
value of that variable inside the pattern.
For example, to match any list whose first element has the same value as the variable `v`

or to
match a two element list whose first element is twice the value of `v`

and whose last element is `v`

:

```
switch (x) {
[$v,*] -> 'matched'
[a,$v] if a == 2*v -> 'matched'
}
```

Just like in expression strings, if the value to be expanded is more than just a simple variable name you can wrap
the expression in `{ }`

:

```
switch (x) {
[${2*v}, $v] -> 'matched'
}
```

You can refer to the value of binding variables (that are already bound) inside the expressions so these two `switch`

expressions are equivalent:

```
switch (x) {
[a,b,c] if b == 2*a && c == 3*a -> 'matched'
}
switch (x) {
[a, ${2*a}, ${3*a}] -> 'matched'
}
```

Note that `switch`

expressions will compare numeric values slightly differently than a standard `==`

comparison.
In a `switch`

expression, numeric value comparisons will only match if the types are the same.
A `long`

value will not match an `int`

value.
This is to allow you to be able to match on exact types, especially in pattern matches.

For example, consider this:

```
switch (x) {
1 -> 'int 1'
1L -> 'long 1'
1D -> 'double 1'
(Decimal)1 -> 'Decimal 1'
1.0 -> 'Decimal 1.0'
}
```

When `x`

is `1`

it will match the pattern that exactly matches its type and value so a `long`

will
only match `1L`

, for example.

Note that `(Decimal)1`

is different to `1.0`

.
Even though both are of type `Decimal`

, `1`

is treated differently to `1.0`

because the number of decimal
places is significant.

This means that this will return `false`

since the `long`

value will not match against an `int`

value
of `1`

:

```
def x = 1L
switch (x) {
1 -> true
default -> false
}
```

This is different to standard comparisons using `==`

:

```
def x = 1L
x == 1 // evaluates to true
```

If the compiler knows the type of the value being switched on and can tell that it can never
match one of the literls in the `switch`

expression you will get a compile error.

See Day 9 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent09.jactl`

) and run it like this (where advent09.txt
is your input file from the Advent of Code site for Day 9):

```
$ cat advent09.txt | java -jar jactl-2.0.0.jar advent09.jactl
```

For today’s challenge we are given a list of number series, one per line, and we need to work out the next number in each series. The challenge is pretty prescriptive and even describes the algorithm to use which consists of generating a new series from the old one based on the differences between consecutive pairs of numbers in the original series until the new series consists only of 0s. Then add up the last element of all the sub-series created and add this to the last element of the original series to get the next number in the original series.

For example:

```
3 10 19 30 43 58
7 9 11 13 15
2 2 2 2
0 0 0
```

The next number in the first series ends up being `0 + 2 + 15 + 58`

which is `75`

.

The goal is to find these next numbers for each series and sum them all.

The code is pretty simple:

```
01 def seqs = stream(nextLine).map{ it.split(/ +/).map{ it as long } }
02 def next(s) { s[-1] + (s.allMatch{it == 0} ? 0 : next(s.windowSliding(2).map{it[1]-it[0]})) }
03 seqs.map{ next(it) }.sum()
```

Each series is on a single line so at line 1 we read each line and split on spaces and convert the values into numbers.

Line 2 is our recursive function that takes the last element of the current series `s[-1]`

and adds it to either `0`

,
if every element is already `0`

, or a recursive call to itself passing in a new series which is the differences
between each pair of numbers in the current series.
We use `windowSliding(2)`

which turns a list of values into a list of consecutive pairs.

Finally, line 3 invokes our recursive `next()`

function on each series and sums the results.

For part 2, the goal is to do the same as in part 1 but instead of finding the next number in the series, we need to find the previous number in the series.

This can be done by taking the first element of each series and subtracting the first element of the series generated from the differences of the pairs.

This means a simple change of our code in part 1 at line 2 to change `s[-1] + ...`

in our recursive function to `s[0] - ...`

:

```
01 def seqs = stream(nextLine).map{ it.split(/ +/).map{ it as long } }
02 def next(s) { s[0] - (s.allMatch{ it == 0 } ? 0 : next(s.windowSliding(2).map{it[1] - it[0]})) }
03 seqs.map{ next(it) }.sum()
```

As was pointed out to me, though, another approach is to just reverse the series and use the original function from part 1:

```
01 def seqs = stream(nextLine).map{ it.split(/ +/).map{ it as long } }
02 def next(s) { s[-1] + (s.allMatch{it == 0} ? 0 : next(s.windowSliding(2).map{it[1]-it[0]})) }
03 seqs.map{ next(it.reverse()) }.sum()
```

At line 3 we just pass in the reverse of the series using the built-in `reverse()`

method.

See Day 8 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent08.jactl`

) and run it like this (where advent08.txt
is your input file from the Advent of Code site for Day 8):

```
$ cat advent08.txt | java -jar jactl-2.0.0.jar advent08.jactl
```

For day 8 we are given input that has the first line as a list of right/left moves (a series of `R`

and `L`

)
followed by a list of nodes where each node describes which of the neighbours is their left neighbour and which is
their right one.

For example:

```
RLLRRRLRL
AAA = (BBB,CCC)
BBB = (DDD,EEE)
CCC = (EEE,FFF)
...
```

The idea is to use the moves to move through the nodes from the staring node `AAA`

until we get to node `ZZZ`

and
then output how many steps it took.
If we run out of moves before we have reached `ZZZ`

we cycle back to the start of the moves list.

The code looks like this:

```
01 def m = nextLine(); nextLine();
02 def nodes = stream(nextLine).map{ /(...) = .(...), (...)./r; [$1, [L:$2,R:$3]] } as Map
03 def cnt = 0
04 for (def n = 'AAA'; n != 'ZZZ'; n = nodes[n][m[cnt++ % m.size()]]) {}
05 cnt
```

At line 1 we read in the moves as a string and advance past the blank line.

Line 2 reads all the nodes and uses a regex to split out the neighbours.
We generate a map of maps where each submap has two members keyed on `'L'`

and `'R'`

.

Line 4 then iterates from `AAA`

until we get to `ZZZ`

by looking up the neighbour of the current node based on the
current move, incrementing `cnt`

each time.
We look up which move using the current `cnt`

as an index after using `%`

to make sure it wraps around if we get past
the end of the moves string.
Since `node[n]`

is a map keyed on `L`

and `R`

we use the move as the key to look up which neighbour to move to and
assign that to `n`

.

Line 5 returns the `cnt`

value.

In part 2 there are multiple “ghosts” moving through the nodes.
There is on ghost per starting node (which is now any node ending in `A`

) and each ghosts moves until it reaches a node
ending in `Z`

.

We need to work out how many moves it will take for all ghosts to simultaneously be at a terminating node.

Since the number of moves it takes is different for each ghost we need to work out what the cycle length is for each ghost and then determine the least common multiple for these cycle lengths since at that point they will all be at a terminating node.

Note we assume that the cycle length for a ghost is not how many steps it takes to reach the first terminating node. In general, this does not have to be the case since the next node after the first terminating node could lead to another sequence finishing at yet another terminating node, and so forth. This would make the challenge much harder. Luckily the input we are given matches this assumption so we don’t have to deal with the more complex general problem.

Here is the code:

```
01 def m = nextLine(); nextLine();
02 def nodes = stream(nextLine).map{ /(...) = .(...), (...)./r; [$1, [L:$2,R:$3]] } as Map
03
04 def count(n) {
05 def cnt = 0
06 while (n !~ /Z$/) { n = nodes[n][m[cnt++ % m.size()]] }
07 cnt
08 }
09
10 def pfactors(n, long start=2, factors=[]) {
11 def p = (n.sqrt()-start+1).map{it+start}.filter{ n % it == 0 }.limit(1)[0]
12 p ? pfactors(n/p,p,factors << p) : factors << n
13 }
14
15 def lcm(nums) {
16 nums.map{ pfactors(it).reduce([:]){ m,it -> m[it as String]++; m } }
17 .reduce([:]){ m,facts -> facts.each{ f,c -> m[f] = [m[f]?:0,c].max() }; m }
18 .flatMap{ f,c -> c.map{ f as long } }
19 .reduce(1L){ p,it -> p * it }
20 }
21
22 lcm(nodes.map{ it[0] }.filter{ /A$/r }.map{ count(it) })
```

We read in the input as per part 1 at lines 1 and 2.

At line 4 we have a function that counts the steps from a given starting node to any terminating node.

Line 10 declares a recursive function that determines the prime factors for a given number `n`

, excluding `1`

, and
excluding `n`

unless `n`

is itself prime.
It iterates from the given starting number up until the square root of `n`

looking for the first number `p`

by which
`n`

is divisible.
If we find such a number we add it to a list of factors and then add all factors of `n/p`

by recursively calling
ourselves.
If there were no number `p`

then we must be prime, so we add ourselves to the list and return that.

Line 15 declares the `lcm(nums)`

function for finding the lowest common multiple of a list of numbers.
It finds the prime factors of each number at line 16 and turns the list into a map of counts for each factor.

Then, at line 17 we combine the maps by finding, for each factor, the maximum count needed for each of the input numbers.

At line 18 we turn the map of these counts back into a list of factors where each factor appears the number of times corresponding to the maximum count calculated at line 17.

Then line 19 multiplies them altogether to get the least common multiple.

Line 22 finds all nodes ending in `A`

and finds the cycle length for that node by invokeing `count(it)`

.
Then this list of counts is passed to our `lcm()`

function to calculate the least common multiple.

See Day 5 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent05.jactl`

) and run it like this (where advent05.txt
is your input file from the Advent of Code site for Day 5):

```
$ cat advent05.txt | java -jar jactl-2.0.0.jar advent05.jactl
```

For day 5 we are given a list of numbers (called “seeds” in the puzzle) and then 7 different mappings to apply in sequence to each of the initial numbers.

Each mapping is a list of rules about how to transform a given input range into an output range. If none of the rules in a mapping apply to the input number then the input number is left as is.

See Day 5 for a proper explanation of what the input looks like and how the rules should be applied.

Here is the code for part 1:

```
01 def seeds = nextLine().split(/: */)[1].split(/ +/).map{ it as long }; nextLine()
02 def maps = stream(nextLine).filter{ ':' !in it }.join('\n').split('\n\n').map{ it.lines().map{ it.split(/ +/).map{ it as long } } }
03 def mapping(m,s) { (m.map{ s >= it[1] && s < it[1]+it[2] ? it[0]+s-it[1] : null }.filter()+[s])[0] }
04 seeds.map{ maps.reduce(it){ p,it -> mapping(it,p) } }.min()
```

Line 1 reads the seed numbers which are just a space seperated list of numbers appearing after `seeds: `

on the first
line.

Line 2 reads each mapping.
We join all the remaining lines together (ignoring lines with `:`

which indicate a mapping label that is not
relevant to how the rules work) and then split on blank lines (which separate each mapping).
We then capture each mapping rule into a list of numbers.

Each rule in a mapping is of the form `dst src count`

which means to transform the input value `n`

, if it is in the range
`src <= n < src + count`

by turning it into `dst + (n - src)`

.

Line 3 creates a function that given a mapping (a list of these rules), and a seed number `s`

returns the transformed
value (if any of the rules apply) or `s`

if none of the source ranges apply.
We iterate over the rules and return the mapped values for each rule, finally adding `[s]`

at the end.
Then, we end up with either `[x, s]`

if a rule applied or `[s]`

if no rules applied and so `[0]`

returns the first
value of our list.
Note that only one rule will apply but even if there were multiple rules that worked for a given mapping, only the
first rule that applies will win.

Finally, line 4 runs all the mappings in sequence for every seed number and returns the minimum result (as required by the puzzle).

Part 2 changes the rules so that the seed numbers are not actual numbers but pairs of numbers giving a range of
values.
So `4 5 6 7`

now means inclusive intervals of `4-8`

and `6-12`

.

The goal is still to find the minimum value after mapping all the numbers in the input ranges but since the numbers in the input are so large iterating over the numbers in the ranges would take an inordinately long time so we need to find a better solution.

The approach, now, is to track the intervals (ranges) of numbers as they flow through the mappings.

The problem is that since a rule in a mapping might apply to only part of the input interval we need to split the input interval into sub-intervals each time we apply a rule that matches.

For example, a rule like `10 20 5`

given an input interval of `20-30`

results in two intervals: `10-14`

and `25-30`

.
Then these two intervals need to be applied to each subsequent rule in a mapping potentially resulting in even more
intervals.

The next mapping has to take the intervals output from the previous mapping and do the same thing.

Here is the code:

```
01 def seeds = nextLine().split(/: */)[1].split(/ +/).map{ it as long }; nextLine()
02 def maps = stream(nextLine).filter{ ':' !in it }.join('\n').split('\n\n')
03 .map{ it.lines().map{ it.split(/ +/).map{ it as long } } }
04 .map{ m -> m.map{ [it[0],[it[1],it[1]+it[2]-1]] } }
05
06 def intersections(s, ivls) { ivls.filter{ intersects(s, it) }.map{ [[s[0],it[0]].max(), [s[1],it[1]].min()] } }
07 def intersects(a, b) { !(a[1] < b[0] || a[0] > b[1]) }
08 def subtract(a, b) { [[[a[0], b[0]].min(), [a[0], b[0]].max()- 1], [[a[1], b[1]].min()+ 1, [a[1], b[1]].max()] ].filter{it[1] >= it[0] } }
09 def subtractAll(a, ivls) { ivls = ivls.filter{ intersects(a, it) }; !ivls ? [a] : ivls.flatMap{ subtract(a, it) } }
10
11 def mapping(m,ranges) {
12 def result = m.reduce([src:ranges,dst:[]]){ p,mi ->
13 def mappable = intersections(mi[1], p.src)
14 def notMapped = p.src.flatMap{ subtractAll(it, mappable) }
15 [src:notMapped, dst:p.dst + mappable.map{ [mi[0] + it[0]-mi[1][0], mi[0] + it[1]-mi[1][0]] }]
16 }
17 result.src + result.dst
18 }
19
20 seeds.grouped(2)
21 .map{ [it[0], it.sum() - 1] }
22 .flatMap{ maps.reduce([it]){ p,m -> mapping(m,p) } }
23 .min{ it[0] }[0]
```

Line 1 reads in the seeds the same way as in part 1.

Lines 2-4 read in the mappings as in part 1 but this time we convert the input rules from `dst srcStart count`

to
`dst srcStart srcEnd`

by adding the count to `src`

and substracting `1`

to make it an inclusive range, so we can
treat is an interval of numbers.

Line 6 creates a function that takes an interval `s`

and a list of intervals `ivls`

and returns a list of intervals
which are the intersections between `s`

and each interval in `ivls`

(when such an intersection exists).

Line 7 is a function that returns true if the two intervals intersect.

Line 8 returns the list of intervals resulting in substracting interval `b`

from interval `a`

.
Note that this can return 0, 1, or 2 values depending on how the intervals overlap (or don’t).

Line 9 returns a list of intervals resulting from substracting each interval in `ivls`

from the interval `a`

.

Line 11 declares a function that applies the rules in a mapping `m`

to the list of intervals `ranges`

.
The result will be another list of intervals.
This function works by iterating over the rules for the mapping (line 12) and calculating the intersections between
the source range of the rule and the current list of input intervals (line 13).
These intersections are the ones that we can map using the current rule.

Line 14 then removes these intervals from the current set of input intervals leaving behind a new set of intervals
for the inputs that are not mappable by this rule.
These non-mapped intervals will then be used as the input (`src`

) for the next rule in the mapping in line 15 where we
also pass in the results of mapping the mappable intervals into their destination values (`dst`

).

At line 17 we return the result which is any intervals from the input that were not mapped by any rule appended with the results of the mappings for sub-intervals that could be mapped.

Line 20 groups the seeds into pairs and at line 21 we turn the pair into an interval.

Then at line 21 we apply the mappings to this interval to get a list of resulting mapped intervals.
By using `flatMap()`

we turn the results for all seeds into one list of results.

Finally, at line 23, we find the interval with the lowest lower bound and return that lower bound as the result.

]]>See Day 6 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent06.jactl`

) and run it like this (where advent06.txt
is your input file from the Advent of Code site for Day 6):

```
$ cat advent06.txt | java -jar jactl-2.0.0.jar advent06.jactl
```

For day 6 we have to solve a puzzle about boat races.

We are given a list of races with the total time available (in ms) and the best distance (in mm) so far obtained by the other competitors.

The input looks like this:

```
Time: 8 13 40
Distance: 9 25 300
```

The rule is that the boats can be charged such that after `n`

ms the boat will have a speed of `n mm/ms`

.
We can decide at what point to let our boat go in order to optimise the total distance it can travel in the given
time.

The goal is to find, for each race, the number of ways in which we can beat the current best distance achieved (i.e.
how many values of `n`

will give a better result).

Then we need to multiply these values together for the final result.

The code looks like this:

```
01 def (times,distances) = 2.map{ nextLine().split(/: +/)[1].split(/ +/).map{ it as int } }
02 times.mapWithIndex{ t,i -> t.map{ it * (t - it) }.filter{ it > distances[i] }.size() }
03 .reduce(1){ p,it -> it * p }
```

For part 1 I just took a brute force approach and iterate from `0`

to `t`

where `t`

is the total time for that race,
calculating the distance travelled `it * (t - it)`

where `it`

is the time at which we let the boat go.

Line 1 reads in the list of times and distances for each race.

Line 2 calculates the number of time values which where will exceed the current best distance for that race, and line 3 then multiplies these numbers together.

For part 2 the twist is that there is only one race and the spaces between the numbers for the times and the distances should be ignored. This means that the size of the numbers is too large to use our naive brute force approach.

Since we have a quadratic equation for the distance travelled after time `n`

(`d = n * (T - n)`

) we could use
the quadratic formula to find the two roots of `n * (T - n) = D`

and calculate the difference between the two roots
to determine the number of values for `n`

where our distance is greater than `D`

.
I decided, however, to implement a binary search instead as it seemd more fitting for a programming challenge.

Here is the code:

```
01 def (T,D) = 2.map{ (nextLine().split(/: +/)[1] =~ s/ //gr) as long }
02 def bin(a,b,fn) { def m = (a+b)/2.0; b-a < 1 ? (long)m : fn(m) < 0 ? bin(a,m,fn) : bin(m,b,fn) }
03 bin(T/2,T,{ it*(T-it) <=> D }) - bin(0,T/2,{ D <=> it*(T-it) })
```

Line 1 reads in the data and removes the spaces before converting the time and distance to a long value.

Line 2 declares a binary search function that takes a lower bound, an upper bound, and a function that should return
`-1`

if we are lower than our goal or `1`

if we are higher.
The function continues until the gap between the lower and upper bounds is less thnan 1.
In general, a binary search function would continue until the function returned `0`

to indicate we have found the
result but in our case we are only interested in integral values and since the root might be irrational we don’t
want to terminate early.

Line 3 calculates the difference between the two roots that we found using our binary search.
This is the number of integral values we can choose where our distance will be greater than `D`

.

See Day 7 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent07.jactl`

) and run it like this (where advent07.txt
is your input file from the Advent of Code site for Day 7):

```
$ cat advent07.txt | java -jar jactl-2.0.0.jar advent07.jactl
```

For day 7 we are given a list consisting of hands of cards along with a bid (an integer amount). Each hand consists of five cards and each card can be one of A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, 2 with this order also being the rank order of the cards. Cards have no suit in this game and there can be five cards of the same type in a hand.

The puzzle requires us to sort the hands into a ranking order based on rules that are similar to poker:

- Five-of-a-kind beats four-of-a-kind
- Foud-of-a-kind beats a full house
- A full house beats three-of-a-kind
- etc

One slight twist that if two hands are classified the same way (e.g. both three-of-a-kind) then the cards are compared (in order) using their ranking to determine which hand has a higher ranking.

Once the cards have been ranked, from the lowest ranking to highest, we need to calculate the sum of the each cards bid multiplied by their rank (where ran starts with 1).

The code looks like this:

```
01 def cards = stream(nextLine).map{ it.split(/ /) }
02 def rnk = '23456789TJQKA'.mapWithIndex() as Map
03 def stronger(a,b) {
04 def counts = { it.reduce([:]){ m,it -> m[it]++; m } }
05 def (ca, cb) = [counts(a), counts(b)]
06 def hcntCmp = ca.max{it[1]}[1] <=> cb.max{it[1]}[1]
07 ca.size() != cb.size() ? cb.size() <=> ca.size() :
08 hcntCmp ? hcntCmp : a.map{rnk[it]} <=> b.map{rnk[it]}
09 }
10 cards.sort{a,b -> stronger(a[0],b[0]) }.mapWithIndex{ c,i -> (i+1) * (c[1] as long) }.sum()
```

At line 1 we read the cards and split them into two parts: the hand (just a 5 character string) and the bid amount.

Line 2 creates a `rnk`

map which returns the rank for an individual card.

Line 3 declares a function `stronger()`

which is a comparator function for two hands `a`

and `b`

.
If `a`

is stronger, then it returns 1, if `a`

is weaker, it returns -1, and if they are the same it returns 0.

At line 4 we create a function that creates a map from a hand of card to count which we then use in line 5 to create
the two map of counts `ca`

and `cb`

.

Line 6 assigns the comparison between the highest count for any card in card `a`

and the highest count for any
card in hand `b`

to `hcntCmp`

.
So if hand `a`

is `AJQA3`

then its highest count is `2`

since we have a single pair and if hand `b`

were `AT9TT`

then
its highest count would be `3`

since we have a three-of-a-kind and `hcntCmp`

would be `-1`

because `2`

is less than `3`

.
This will help us to compare the two hands.

Line 7 and 8 return the comparator result for the two hands.
If the number of distinct cards differs then we return `cb.size() <=> ca.size()`

which means that that hand with fewer
distinct cards will win.Note that we use `cb.size() <=> ca.size()`

and *not* `ca.size() <=> cb.size()`

since here
the lowest number wins.

Otherwise if `hcntCmp`

is non-zero it means that the highest card counts differ and so we want the hand with the
highest card count to win and we return `hcntCmp`

.

If the highest card counts are the same and the number of distinct cards are the same then we need to compare the hands based on the ordered ranking of the cards, so we map the cards to their ranking and return the comparator for the two lists of card rankings as our result.

Line 10 sorts the cards based on this `stronger(a,b)`

comparator function and then for each card multiplies the
card bid by their index in the sorted ranking and sums the results.

In part 2 the rules change so that J is now a joker and can match any other card in the hand. This means that we want use the joker to maximise the rank of the hand by making it match the most frequent other non-joker card in the hand. However, when comparing hands based on the card rankings (when they are otherwise of equal strength), the ranking of a joker is now lower than any other card.

One additional twist to watch out for is that a hand can have 5 jokers.

Here is the code:

```
01 def cards = stream(nextLine).map{ it.split(/ /) }
02 def rnk = 'J23456789TQKA'.mapWithIndex() as Map
03 def ranked(a,b) { rnk[a] <=> rnk[b] }
04 def stronger(a,b) {
05 def counts = { it.reduce([:]){ m,it -> m[it]++; m } }
06 def (ca, cb) = [counts(a =~ s/J//gr), counts(b =~ s/J//gr)]
07 def (aBest, bBest) = [ca,cb].map{ cs -> (['J'] + cs.filter{ it[1]==cs.max{it[1]}[1] }.sort(ranked))[-1][0] }
08 (ca, cb) = [counts(a =~ s/J/$aBest/gr), counts(b =~ s/J/$bBest/gr)]
09 def hcntCmp = ca.max{it[1]}[1] <=> cb.max{it[1]}[1]
10 ca.size() != cb.size() ? cb.size() <=> ca.size() :
11 hcntCmp ? hcntCmp : a.map{rnk[it]} <=> b.map{rnk[it]}
12 }
13
14 cards.sort{ a,b -> stronger(a[0],b[0]) }.mapWithIndex{ c,i -> (i+1) * (c[1] as long) }.sum()
```

Line 2 now ranks the cards using the new ranking for part 2.

Line 3 declares a function that returns a comparator for comparing the rankings of two cards that we can use in a sort later on.

Line 4 is where we have the `stronger()`

function for determining which hand of `a`

or `b`

is stronger.
We still have a function for returning a map of card counts at line 5.
We use this function to calculate the counts for `a`

and `b`

in the maps `ca`

and `cb`

(after stripping out all
the jokers) at line 6.

Note that `a =~ s/J//gr`

is a regex expression that substitutes all occurrences of `'J'`

with `''`

.
The `r`

after the expressions means that it returns the value after substitutions and doesn’t modify the value `a`

as it would normally.

Line 7 is where we find the best card to use in case we have any jokers.
We use the card counts in `ca`

and `cb`

to find the card with the highest count and return it
as `aBest`

for hand `a`

and `bBest`

for hand `b`

.
We generate a list of cards that have the highest count.
There may be multiple if we have two pairs, for example, or 5 different cards with no multiples.
We then sort the list based on ranking and return the last card in the list as it has the highest ranking.
We add ‘J’ to front of the list to cater for the case when the list is empty (because all cards are jokers).

At line 8 we recalculate the counts after substituting jokers for our best card.

The rest of the code works exactly as in part 1.

]]>See Day 4 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent04.jactl`

) and run it like this (where advent04.txt
is your input file from the Advent of Code site for Day 4):

```
$ cat advent04.txt | java -jar jactl-2.0.0.jar advent04.jactl
```

For today’s puzzle we are given a list of scratch cards with each card having a set of winning numbers, and, for each
card we have a set of numbers that we have to match against that cards winning numbers.
For the first winning number we get one point, and then each winning number after that doubles the number of points
we have.
In other words the number of points for each card is `2^(n-1)`

where `n`

is the number of winning cards we have.

The lines of input look like this:

```
Card 1: 1 10 23 6 | 2 23 45 66 1
Card 2: 22 3 47 65 | 10 3 65 22 44
```

The first set of numbers are the winning numbers and the second set is our set of numbers that we have to verify against the winning numbers.

We just need to sum the points across all of our cards.

Here is the code:

```
01 stream(nextLine).map{ it.split(/:/)[1].split(/ *\| */).map{ it.split(/ +/) } }
02 .map{ c -> c[1].filter{ it in c[0] }.size() }
03 .filter().map{ 1 << (it - 1) }.sum()
```

We first read each line and split on `:`

.
The second part of the split (the part after the `:`

) is what we are interested in.
We then split this part on `/ *| */`

which splits on the ‘|’ and also ignores the spaces around it.
Then each of the two parts is split into the numbers by splitting on `/ +/`

.

Line 2 counts the number of numbers in the second set of numbers that appear in the first set (using `in`

to
search the list of numbers).

Line 3 then takes the count and calculates `2^n`

by shifting `1`

left by one less than the count.

For part 2 the rules change so that the number of winning numbers actually give you additional cards to match
against.
If, on card `i`

you have `n`

winning numbers, then you add cards `i+1,i+2,...,i+n`

to the list of cards and continue
the processing of the cards.
Since these cards are already in the list of cards they will be processed multiple times.

Here is the code:

```
01 def C=stream(nextLine).map{it.split(/:/)[1].split(/ *\| */).map{it.split(/ +/)}}
02 .mapWithIndex{ x,i -> [i:i,c:x[1].filter{it in x[0]}.size()] }
03 for(int i=0;i<C.size();i++){ C+=C.subList(C[i].i+1,C[i].i+C[i].c+1) if C[i].c }
04 C.size()
```

Since there were bonus points for *golfing* the solution (making it as short as possible), I stripped out some
whitespace.

Here is a more legible version:

```
01 def C = stream(nextLine).map{ it.split(/:/)[1].split(/ *\| */).map{ it.split(/ +/) } }
02 .mapWithIndex{ x,i -> [idx:i, cnt:x[1].filter{ it in x[0] }.size()] }
03 for (int i = 0; i < C.size(); i++) {
04 C += C.subList(C[i].idx + 1, C[i].idx + C[i].cnt + 1) if C[i].cnt
05 }
06 C.size()
```

Line 1 reads in the card data the same way as in part 1.

Line 2 then creates a list of cards where each card is of the form `[idx:i, cnt:c]`

where `i`

is the card index
and `c`

is the winning count for that card.

Line 3 iterates over the list of cards and for each card adds the winning cards to end of the list based on the number of cards and where we are up to in the list.

Once there are no more cards to process we return the number of cards in the list.

]]>See Day 3 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent03.jactl`

) and run it like this (where advent03.txt
is your input file from the Advent of Code site for Day 3):

```
$ cat advent03.txt | java -jar jactl-2.0.0.jar advent03.jactl
```

In part 1 we are given a grid consisting of digits, dots, and symbols (such as ‘+’, ‘#’, ‘*’). The idea is to find in the grid sequences of digits and treat these sequences as a number and sum all numbers in the grid that match the criteria that one of the digits in the number must be adjacent to a symbol. Adjacent, for this puzzle, means any neighbour in the 8 surrounding squares of the grid.

For example:

```
..123..44.
..+3..*...
.32..677..
..111.....
.......$9.
```

As usual, for puzzles involving grids, I added a border of dots around the grid to avoid having to check for out-of-bounds conditions when looking for neighbours at the edge of the grid.

Here is the code:

```
def (rows, D) = [stream(nextLine), [-1,0,1]]
def g = ['.' * (rows[0].size()+2)] + rows.map{ '.'+it+'.' } + ['.' * (rows[0].size()+2)]
def numNearSym(x,y) { g[y][x] =~ /\d/ && D.flatMap{ dx -> D.map{ dy -> [x+dx,y+dy] } }.anyMatch{ x1,y1 -> g[y1][x1] !~ /[.\d]/ } }
g.mapWithIndex{ r,y -> r.size().map{ x -> g[y][x] + (numNearSym(x, y) ? 'S' : '') }.join() }
.flatMap{ it.split(/[^\dS]+/).filter{ 'S' in it }.map{ s/[^\d]+//g }
.map{ it as int } }.sum()
```

The first line assigns all input lines to `rows`

and assigns `[-1,0,1]`

to `D`

for use when calculating deltas
to `x,y`

coordinates later.

Then we create our grid of lines in the variable `g`

, adding a row at the beginning and end and adding a dot to the
beginning and end of each row.

The function `numNearSym()`

checks if at `x,y`

we have a digit and then looks for a neighbour that is not a digit and
is not a `.`

and returns true if we are a digit with such a neighbour.

Then we iterate over the rows using `mapWithIndex()`

and append `S`

to each digit in the row that has a neighbouring
symbol.

We take the resulting lines with these `S`

characters and use the regex split to split the line into a list of substrings
that were separated by anything that was not a digit or `S`

.
This gives us our candidate numbers.
We filter for only numbers with an embeded `S`

(since these are the ones with symbol neighbours), remove the `S`

characters and convert into numbers before summing them.

For part 2 we are only interested in numbers that have a neighbour that is a `*`

and only if that `*`

has exactly
two numbers for which it is a neighbour.
Then we multiply the two numbers together and sum the resulting products.

```
01 def lines = stream(nextLine)
02 def g = ['.' * (lines[0].size()+2)] + lines.map{ '.' + it + '.' } + ['.' * (lines[0].size()+2)]
03
04 def nearest2Nums(x,y) {
05 def nums = [[-1,0,1].flatMap{ dx -> [-1,0,1].map{dy -> [x+dx, y+dy] } }
06 .filter{ x1, y1 -> g[y1][x1] =~ /\d/ }
07 .map{ x1,y1 -> [x1 - (x1+1).filter{ g[y1][x1-it] !~ /\d/ }.limit(1)[0] + 1, y1] }
08 .sort().unique()].filter{ it.size() == 2 }[0]
09 nums ? nums.map{ x1,y1 -> g[y1].substring(x1,(g[y1].size()-x1).map{x1+it+1}.filter{ g[y1][it] !~ /\d/ }.limit(1)[0]) as int }
10 .grouped(2).map{ it[0] * it[1] }[0]
11 : null
12 }
13
14 g.size().flatMap{ y -> g[y].size().filter{ g[y][it] == '*' }.flatMap{ nearest2Nums(it, y) } }.sum()
```

As in part 1, we read the lines and add a border of dots on all sides.

We define a function `nearest2Nums(x,y)`

that for a given location check if any neighbours are digits (line 6).
Then at line 7 we find the start location in the current row for the number that contains that digit and return the
`[x,y]`

location for that number.

At line 8 we sort these coordinates and eliminate duplicates (since one number might have multiple digits neighbouring
that ‘*’) and then filter solutions where there are exactly 2 numbers.
Since we have wrapped the result in `[`

and `]`

we actually have a list of a list of coordinate pairs and so the filter
will return either this list (if it has 2 elements) or null if the list is filtered out.
The `[0]`

unwraps the resulting list back into a simple list of coordinate pairs.

At line 9, if the `nums`

result was non-null, we map the coordinates into the numbers at those locations by finding
the ending digit, grabbing the substring and converting to an `int`

.

Line 10 turns the 2 element list into a list of a list of 2 elements so we can multiply the two numbers together.

Line 11 returns `null`

if the location did not have exactly two neighbouring numbers.

Line 14 searches all grid locations for ‘*’ and uses the `nearest2Nums()`

function to return null or the product of
the 2 numbers (if they exist).
By using `flatMap()`

we ignore `null`

values and can then invoke `sum()`

to sum everything together.

See Day 2 for a detailed description of the problem.

To run the Jactl shown here save the code into a file (e.g. `advent02.jactl`

) and run it like this (where advent02.txt
is your input file from the Advent of Code site for Day 2):

```
$ cat advent02.txt | java -jar jactl-2.0.0.jar advent02.jactl
```

In Part 1 we are given a list of “games” with each game having a multiple lists and each list being a list of colours and a count. The idea is that these lists represent a random selection of coloured cubes from a bag. Multiple lists for each game show multiple random picks from the same bag. Each game gets a new bag with different colour cubes.

For example:

```
Game 1: 3 blue, 2 red, 4 green; 1 blue, 3 red, 3 green; 2 blue, 3 red, 4 green
Game 2: 2 blue, 6 red, 4 green; 3 blue, 4 red, 5 green; 1 blue, 7 red, 8 green
...
```

If we are told that the bag actually has 12 red cubes, 13 green cubes, and 14 blue cubes, we need to determine which games could actually have been played with that bag. That is we need to weed out the games where the selections had counts too high for this given bag.

For the games that could have occurred we sum their ids and that is the solution for the puzzle.

```
def bag = [red:12, green:13, blue:14]
stream(nextLine).map{
/Game (\d+): (.*)$/n
[$1, $2.split(/;/)
.flatMap{ it.split(/,/)
.map{ /(\d+) (.*)/n; [$2,$1] }}.allMatch{ colour,count -> count <= bag[colour] }]
}.filter{ it[1] }.map{ it[0] }.sum()
```

The solution was pretty straightforward.
We take each line, extract the game id, and then split the rest of the line on `;`

to get the list of picks.
Then we split on `,`

to find the individual colours and the counts.
We then filter the games for games where the colour counts for all picks were less than or equal to the counts
in the bag we have been given.

Finally we sum the game ids.

For Part 2 we take the cube counts for each game and we need to work out what the smallest count per colour in our bag could be for that game to have been valid. Each game, therefore, gets its own minimum bag with a count per colour. Then we multiply these counts together for each game and sum these products for the final solution:

```
stream(nextLine).map{ it.split(/: /)[1].split(/;/)
.flatMap{ it.split(/,/).map{ /(\d+) (.*)/n; [$2,$1] } }
.sort() as Map }
.map{ it.reduce(1){ prod,entry -> prod * entry[1] } }.sum()
```

The only trick here is to generate a simple list of [colour, count] for each game and then sort these so that we get a list sorted by colour and then count so that the highest counts come later in the list. Then we convert this list into a Map which means that the last value for each colour will be the value in the Map. Since we have sorted the list this means we end up with a Map of colours with the maximum count values.

Then we used `reduce()`

to generate the product of these counts and sum them together.