Skip to content

Instantly share code, notes, and snippets.

@milang
Last active December 22, 2017 06:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milang/724b197d9d2e46e5077c83f3fd7eff87 to your computer and use it in GitHub Desktop.
Save milang/724b197d9d2e46e5077c83f3fd7eff87 to your computer and use it in GitHub Desktop.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Input data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let rotateLeft (value: string) =
match value.Length with
| 5 -> String.Join("", [| value.[1]; value.[4]; '/'; value.[0]; value.[3] |])
| 11 -> String.Join("", [| value.[2]; value.[6]; value.[10]; '/'; value.[1]; value.[5]; value.[9]; '/'; value.[0]; value.[4]; value.[8] |])
| _ -> raise (InvalidOperationException "Unrecognized value")
let mirrorY (value: string) =
match value.Length with
| 5 -> String.Join("", [| value.[1]; value.[0]; '/'; value.[4]; value.[3] |])
| 11 -> String.Join("", [| value.[2]; value.[1]; value.[0]; '/'; value.[6]; value.[5]; value.[4]; '/'; value.[10]; value.[9]; value.[8] |])
| _ -> raise (InvalidOperationException "Unrecognized value")
let mirrorX (value: string) =
match value.Length with
| 5 -> String.Join("", [| value.[3]; value.[4]; '/'; value.[0]; value.[1] |])
| 11 -> String.Join("", [| value.[8]; value.[9]; value.[10]; '/'; value.[4]; value.[5]; value.[6]; '/'; value.[0]; value.[1]; value.[2] |])
| _ -> raise (InvalidOperationException "Unrecognized value")
let allVariations (value: string) =
{1..3}
|> Seq.scan (fun current _ -> rotateLeft current) value
|> Seq.map (fun rotatedValue -> rotatedValue :: mirrorX rotatedValue :: mirrorY rotatedValue :: [])
|> List.concat
let parse filename =
File.ReadAllLines filename
|> Seq.map
(fun line ->
let parts = line.Split([| " => " |], StringSplitOptions.None)
let targets = parts.[1].Split('/')
let sources = allVariations parts.[0]
sources |> Seq.ofList |> Seq.map (fun source -> (source, targets)))
|> Seq.concat
|> Map.ofSeq
let data = parse "queries/Advent/Advent2017-day21.txt"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Problem A
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let split (bitmap: string array) =
let subdivideBy = if bitmap.Length % 2 = 0 then 2 else 3
let subdivisions = bitmap.Length / subdivideBy
let newBitmap =
{ 0 .. subdivisions - 1 }
|> Seq.map
(fun row ->
{ 0 .. subdivisions - 1 }
|> Seq.map
(fun column ->
let r =
{ 0 .. (subdivideBy-1) }
|> Seq.map
(fun offset ->
bitmap.[(row * subdivideBy) + offset].Substring(column * subdivideBy, subdivideBy))
String.Join("/", r)))
|> Seq.concat
(subdivideBy, subdivisions, newBitmap)
let join subdivideBy subdivisions (bitmap: (string array) seq) =
bitmap
|> Seq.mapi (fun i row -> ((i / subdivisions), row))
|> Seq.groupBy fst
|> Seq.map
(fun (_, row) ->
{ 0 .. subdivideBy }
|> Seq.map
(fun offset ->
let p = row |> Seq.map (fun (_, r) -> r.[offset])
String.Join("", p)))
|> Seq.concat
|> Array.ofSeq
let enhance iterations data =
let rec enhance' iterations (bitmap: string array) =
if iterations = 0 then bitmap
else
let (subdivideBy, subdivisions, splitBitmap) = split bitmap
let mappedBitmap = splitBitmap |> Seq.map (fun bitmapCell -> data |> Map.find bitmapCell)
enhance' (iterations - 1) (join subdivideBy subdivisions mappedBitmap) // tail recursive
enhance' iterations [| ".#."; "..#"; "###" |]
let countBits (bitmap: string array) =
bitmap
|> Seq.ofArray
|> Seq.map (fun bitmapCell -> bitmapCell |> Seq.map (fun bit -> if bit = '#' then 1 else 0) |> Seq.sum)
|> Seq.sum
let result = enhance 5 data
(countBits result, result).Dump("Final pixel count and bitmap")
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Problem B
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let result2 = enhance 18 data
(countBits result2).Dump("Final pixel count after 18 iterations")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment