Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
Futhark can read only number and array types from stdin, the input data is often a non-starter. Therefore, I often massage it into the right format using sed.
entry part1 (colors: [][4]i32) =
let isGreenDominant c = c.g > c.r && c.g > c.b
in colors
|> map (\array -> (array[0], {r = array[1], g = array[2], b = array[3]}))
|> filter ((.1) >-> isGreenDominant)
|> map (.0)
|> i32.sum
type Optional 'a = #absent | #present a
def map_optional 'a 'b (f: a -> b) (this: Optional a) : Optional b =
match this
case #absent -> #absent
case #present a -> #present (f a)
def optional_is_present 'a (this: Optional a) : bool =
match this
case #absent -> false
case _ -> true
def unwrap_optional 'a (this: Optional a) : a =
match this
case #absent -> assert (("unwrap_optional: #absent", false).1) ([][1])
case #present a -> a
def bind_optional 'a 'b (f: a -> Optional b) (this: Optional a) : Optional b =
match this
case #absent -> #absent
case #present a -> f a
def maximum_by 'a (gte: a -> a -> bool) (as: []a) : Optional a =
let choose (this: Optional a) (other: Optional a) =
match (this, other)
case (#absent, o) -> o
case (t, #absent) -> t
case (#present t, #present o) -> #present (if o `gte` t then o else t)
in reduce choose #absent (map (\a -> #present a) as)
type ShineColor = {r: i32, g: i32, b: i32, s: i32}
def array2ShineColor (array: [5]i32) : (i32, ShineColor) = (array[0], {r = array[1], g = array[2], b = array[3], s = array[4]})
def on f g a b = f (g a) (g b)
entry part2 (colors: [][5]i32) =
let gte (this: ShineColor) (other: ShineColor): bool =
let colorSum c = c.r + c.g + c.b
in this.s > other.s || (this.s == other.s && colorSum this <= colorSum other)
in colors
|> map array2ShineColor
|> maximum_by (gte `on` (.1))
|> unwrap_optional
|> (.0)
type Shininess = #matte | #shiny
type DominantColor = #red | #green | #blue
def filterMap 'a 'b [n] (f: a -> Optional b) (as: [n]a) : []b =
as
|> map f
|> filter optional_is_present
|> map unwrap_optional
def categorize_shininess (s: i32) : Optional Shininess =
if s <= 30 then #present #matte else if s >= 33 then #present #shiny else #absent
def categorize_color (color: ShineColor) : Optional DominantColor =
if color.r > color.g && color.r > color.b
then #present #red
else if color.g > color.r && color.g > color.b
then #present #green
else if color.b > color.r && color.b > color.g
then #present #blue
else #absent
def categorize ((value, color): (i32, ShineColor)) : Optional (i32, (DominantColor, Shininess)) =
categorize_shininess color.s
|> bind_optional (\s -> map_optional (\c -> (c, s)) (categorize_color color))
|> map_optional (\g -> (value, g))
-- >>> category_index (#red, #shiny)
-- 3
def category_index ((c, s): (DominantColor, Shininess)) : i64 =
(+) (match c
case #red -> 0
case #green -> 1
case #blue ->
2)
(match s
case #matte -> 0
case #shiny -> 3)
def (&&&) f g x = (f x, g x)
def sum2d (a, b) (c, d) : (i32, i32) = (a + c, b + d)
entry part3 (colors: [][5]i32) =
colors
|> map array2ShineColor
|> filterMap categorize
|> map ((.1) >-> category_index &&& ((.0) &&& const 1))
|> unzip
|> uncurry (hist sum2d (0, 0) 6)
|> maximum_by ((>=) `on` (.1))
|> unwrap_optional
|> (.0)
I had hoped that the input might get big enough for optimization purposes, but the calculations are likely too simple.