summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBrian Chu <brianmchu42@gmail.com>2022-01-04 22:14:05 -0800
committerBrian Chu <brianmchu42@gmail.com>2022-01-04 22:14:05 -0800
commit102086e040577a4f6b3e7d97e442ee32e12f3e27 (patch)
treec88f097b0a798bc9e1cd4ed09684216ac0f0946d
downloadAdventOfCode2016-102086e040577a4f6b3e7d97e442ee32e12f3e27.tar.gz
solutions to day 8
-rw-r--r--.gitignore2
-rw-r--r--day1.fsx58
-rw-r--r--day2.fsx51
-rw-r--r--day3.fsx20
-rw-r--r--day4.fsx56
-rw-r--r--day5.fsx43
-rw-r--r--day6.fsx18
-rw-r--r--day7.fsx69
-rw-r--r--day8.py46
9 files changed, 363 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b88559f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.ionide
+*.txt
\ No newline at end of file
diff --git a/day1.fsx b/day1.fsx
new file mode 100644
index 0000000..cec57b5
--- /dev/null
+++ b/day1.fsx
@@ -0,0 +1,58 @@
+open System.IO
+
+let lines = (File.ReadAllText "day1.txt").Split ", "
+
+let rec move (steps: string[]) (dir: int) (x: int) (y: int): int =
+    if (Array.length steps) = 0 then abs x + abs y
+    else
+        let instDir = steps[0][0]
+        let instLen = steps[0][1..] |> int
+        let newDir =
+            match instDir with
+            | 'R' -> (dir + 1) % 4
+            | 'L' -> (((dir - 1) % 4) + 4) % 4
+            | _ -> -500 // will never get to this point but the compiler yells at me otherwise
+        
+        let (newX, newY) =
+            match newDir with
+            | 0 -> (x, y + instLen)
+            | 1 -> (x + instLen, y)
+            | 2 -> (x, y - instLen)
+            | 3 -> (x - instLen, y)
+            | _ -> (-500, -500) // again will never reach here
+        move steps[1..] newDir newX newY
+
+let rec move2 (steps: string[]) (dir: int) (x: int) (y: int) (visited: Set<int * int>): int =
+    let instDir = steps[0][0]
+    let instLen = steps[0][1..] |> int
+    let newDir = 
+        match instDir with 
+        | 'R' -> (dir + 1) % 4
+        | 'L' -> (((dir - 1) % 4) + 4) % 4
+        | _ -> -500
+    
+    let newVisited =
+        match newDir with
+        | 0 -> set [for newY in seq {y+1 .. y+instLen} do yield (x, newY)]
+        | 1 -> set [for newX in seq {x+1 .. x+instLen} do yield (newX, y)]
+        | 2 -> set [for newY in seq {y-1 .. -1 .. y-instLen} do yield (x, newY)]
+        | 3 -> set [for newX in seq {x-1 .. -1 .. x-instLen} do yield (newX, y)]
+        | _ -> Set.empty
+    
+    let diff = Set.intersect visited newVisited
+    if (Set.count diff) > 0 then
+        let pointList = [for point in diff do yield point]
+        let (pointX, pointY) = pointList[0] // assume there is only one intersection at a time
+        abs pointX + abs pointY
+    else
+        let (newX, newY) =
+            match newDir with
+            | 0 -> (x, y + instLen)
+            | 1 -> (x + instLen, y)
+            | 2 -> (x, y - instLen)
+            | 3 -> (x - instLen, y)
+            | _ -> (-500, -500)
+        move2 steps[1..] newDir newX newY (Set.union visited newVisited)
+
+move lines 0 0 0 |> printfn "%A" 
+move2 lines 0 0 0 Set.empty |> printfn "%A"
diff --git a/day2.fsx b/day2.fsx
new file mode 100644
index 0000000..26fc704
--- /dev/null
+++ b/day2.fsx
@@ -0,0 +1,51 @@
+open System.IO
+
+let keypad1 (pos: int * int): string = 
+    let (x, y) = pos
+    string (x + 3 * y + 1)
+
+let keypad2 (pos: int * int): string =
+    let pad = [
+        "--1--"
+        "-234-"
+        "56789"
+        "-ABC-"
+        "--D--"
+    ]
+    let (row, col) = pos
+    string (pad[col][row])
+
+let final_pos1 (start: int * int) (line: string) =
+    let move (pos: int*int) (dPos: char) = 
+        let (x, y) = pos
+        match dPos with
+            | 'U' -> (x, y-1 |> max 0 |> min 2)
+            | 'D' -> (x, y+1 |> max 0 |> min 2)
+            | 'L' -> (x-1 |> max 0 |> min 2, y)
+            | 'R' -> (x+1 |> max 0 |> min 2, y)
+            | _ -> (-500, -500)
+    List.fold move start (Seq.toList line)
+
+let final_pos2 (start: int*int) (line: string) =
+    let move (pos: int*int) (dPos: char) =
+        let (x, y) = pos
+        let newPos =
+            match dPos with
+                | 'U' -> (x, y-1 |> max 0 |> min 4)
+                | 'D' -> (x, y+1 |> max 0 |> min 4)
+                | 'L' -> (x-1 |> max 0 |> min 4, y)
+                | 'R' -> (x+1 |> max 0 |> min 4, y)
+                | _ -> (-500, -500)
+        if keypad2 newPos = "-" then pos else newPos
+    List.fold move start (Seq.toList line)
+
+let lines = "day2.txt" |> File.ReadLines |> Seq.toList
+
+let generate_code (instructions: list<string>) (posfunc: int*int -> string -> int*int) (keyfunc: int*int -> string) (start: int*int): list<string> =
+    let positions = List.scan posfunc start instructions
+    List.map keyfunc positions[1..]
+
+// part 1
+generate_code lines final_pos1 keypad1 (1, 1) |> String.concat "" |> printfn "%s"
+// part 2
+generate_code lines final_pos2 keypad2 (0, 2) |> String.concat "" |> printfn "%s"
\ No newline at end of file
diff --git a/day3.fsx b/day3.fsx
new file mode 100644
index 0000000..ef1a0d9
--- /dev/null
+++ b/day3.fsx
@@ -0,0 +1,20 @@
+open System.IO
+
+let lengths = [for line in File.ReadLines "day3.txt" do yield line.Split " " |> Seq.filter ((<>) "") |> Seq.map int |> Seq.toList]
+let isTriangle (sides: list<int>): bool =
+    let sorted = Seq.sort sides |> Seq.toArray
+    sorted[0] + sorted[1] > sorted[2]
+
+// part 1
+let triangles = Seq.filter isTriangle lengths
+Seq.length triangles |> printfn "%d"
+
+// part 2
+let colLengths = seq {
+    for row in 0..3..(Seq.length lengths - 1) do
+        for col in 0..2 do
+            yield [lengths[row][col];lengths[row+1][col]; lengths[row+2][col]]
+}
+
+let colTriangles = Seq.filter isTriangle colLengths
+Seq.length colTriangles |> printfn "%d"
\ No newline at end of file
diff --git a/day4.fsx b/day4.fsx
new file mode 100644
index 0000000..dd9916a
--- /dev/null
+++ b/day4.fsx
@@ -0,0 +1,56 @@
+open System.IO
+open System.Text.RegularExpressions
+open System
+
+let lines = File.ReadLines "day4.txt" |> Seq.toList
+
+let (|Regex|_|) pattern input = 
+    let m = Regex.Match(input, pattern)
+    if m.Success then Some(List.tail [for g in m.Groups -> g.Value])
+    else None
+
+let validChecksum (info: string * int * string) =
+    let (name, idNum, checksum) = info
+    let counts = 
+        name 
+        |> String.filter ((<>) '-') 
+        |> Seq.toList 
+        |> List.countBy id
+        |> List.sortBy fst
+        |> List.sortBy (snd >> fun x -> -x)
+    let topFive = (List.map fst counts)[0..4] |> Seq.map string|> String.concat "" 
+    if topFive = checksum then idNum else 0
+
+let getInfo string = 
+        match string with
+        | Regex "([a-z\-]*)-(\d+)\[([a-z]{5})\]" [name; id; checksum] -> 
+            (name, int id, checksum)
+        | _ -> ("", 0, "")
+
+let totalChecksum =
+    List.map (getInfo >> validChecksum) >> List.sum
+
+// part 1
+totalChecksum lines |> printfn "%A"
+
+// part 2
+let decrypt (offset: int) (letter: char) : string =
+        match letter with
+        | '-' -> " "
+        | _ ->
+            int letter 
+            |> fun x -> x - (int 'a') + offset 
+            |> fun x -> x % 26 
+            |> ((+) (int 'a')) 
+            |> Convert.ToChar
+            |> string
+
+let decryptValid (info: string * int * string) = 
+    let (name, idNum, checksum) = info
+    Seq.toList name |> List.map (decrypt idNum) |> String.concat "", idNum
+
+
+let decrypted =
+    List.map (getInfo >> decryptValid) >> List.filter (fst >> fun x -> x.Contains "north")
+
+decrypted lines |> printfn "%A"
diff --git a/day5.fsx b/day5.fsx
new file mode 100644
index 0000000..2f7b4ba
--- /dev/null
+++ b/day5.fsx
@@ -0,0 +1,43 @@
+open System.Security.Cryptography
+open System.Text
+
+let input = "reyedfim"
+
+let md5 (data: string): string = 
+    use md5 = MD5.Create()
+    (StringBuilder (), md5.ComputeHash(Encoding.ASCII.GetBytes data))
+    ||> Array.fold (fun sb b -> sb.Append(b.ToString("x2")))
+    |> string
+
+let rec getPassword (count: int) (chars: string): string =
+    if String.length chars = 8 then chars
+    else
+        let hashed = md5 (input + string count)
+        if hashed[0..4] = "00000" then 
+            getPassword (count + 1) (chars + string hashed[5])
+        else
+            getPassword (count + 1) chars
+
+// part 1
+getPassword 0 "" |> printfn "%s"
+
+// part 2
+let updateElement index newValue =
+    String.mapi (fun i v -> if i = index then newValue else v)
+
+let rec getPassword2 (count: int) (chars: string): string =
+    if Seq.fold (fun x y -> x && (y <> ' ')) true chars then chars
+    else
+        let hashed = md5 (input + string count)
+        if hashed[0..4] = "00000" then 
+            let index = int hashed[5] - int '0'
+            if index < 0 || index > 7 || chars[index] <> ' ' then
+                getPassword2 (count + 1) chars
+            else
+                let newChar = hashed[6]
+                let newChars = chars |> updateElement index newChar
+                getPassword2 (count + 1) newChars
+        else
+            getPassword2 (count + 1) chars
+
+getPassword2 0 "        " |> printfn "%s"
\ No newline at end of file
diff --git a/day6.fsx b/day6.fsx
new file mode 100644
index 0000000..251dba1
--- /dev/null
+++ b/day6.fsx
@@ -0,0 +1,18 @@
+open System.IO
+
+let lines = File.ReadLines "day6.txt" |> Seq.toArray |> Array.map (fun x -> x.ToCharArray()) |> array2D
+let rows, cols = Array2D.length1 lines, Array2D.length2 lines
+
+let chars (reversed:bool) = seq { for i = 0 to cols - 1 do
+                                    let col = lines[*, i]
+                                    yield col  
+                                    |> Seq.countBy id 
+                                    |> Seq.sortBy (snd) 
+                                    |> if reversed then Seq.last else Seq.head 
+                                    |> fst
+                                    |> string }
+
+// part 1
+chars true |> String.concat "" |> printfn "%s"
+// part 2
+chars false |> String.concat "" |> printfn "%s"
\ No newline at end of file
diff --git a/day7.fsx b/day7.fsx
new file mode 100644
index 0000000..950d98d
--- /dev/null
+++ b/day7.fsx
@@ -0,0 +1,69 @@
+open System.IO
+open System.Text.RegularExpressions
+
+let (|Regex|_|) pattern input =
+    let m = Regex.Matches(input, pattern)
+    if m.Count > 0 then Some(m)
+    else None
+
+let lines = File.ReadLines "day7.txt"
+
+let getSegments inputStr = 
+    match inputStr with
+    | Regex "(?:[a-z]+)|(?:\[[a-z]+\])" matches -> matches |> Seq.map (fun x -> x.Value) |> Seq.toList
+    | _ -> []
+// part 1
+let containsABBA (segment: string): bool =
+    let isABBA (chars: char[]): bool = 
+        let a1, b1, b2, a2 = chars[0], chars[1], chars[2], chars[3]
+        a1 = a2 && b1 = b2 && a1 <> b1
+    segment 
+    |> Seq.windowed 4
+    |> Seq.map isABBA
+    |> Seq.fold (||) false
+
+let ABBASegment (segment: string): bool =
+    not ((containsABBA segment) && (segment[0] = '['))
+
+let TLSLine (line: string):bool=
+    let allValid = line
+                   |> getSegments
+                   |> Seq.map ABBASegment
+                   |> Seq.fold (&&) true
+    allValid && containsABBA line
+
+lines |> Seq.filter TLSLine |> Seq.length |> printfn "%d"
+
+// part 2
+let matchABA (pair: char[] * char[]): bool =
+    let aba, bab = pair
+    let a, b, c = aba[0], aba[1], aba[2]
+    let d, e, f = bab[0], bab[1], bab[2]
+    a = c && d = f && a = e && b = d
+
+let ABAPairs (segments: list<string>) : list<char[] * char[]> =
+    let windows (group: bool * list<string>) =
+        let _, segments = group
+        seq {
+            for segment in segments do
+                yield! seq {
+                    for window in Seq.windowed 3 (String.filter (fun x -> x <> '[' && x <> ']') segment) do 
+                        yield window
+                }
+        }
+    let cartesian xs ys =
+        xs |> List.collect (fun x -> ys |> List.map (fun y -> x, y))
+    
+    let separated = segments |> List.groupBy (fun x -> x[0] = '[') |> List.map windows |> List.map Seq.toList
+    cartesian separated[0] separated[1]
+
+let validABA =
+    getSegments
+    >> ABAPairs
+    >> Seq.map matchABA
+    >> Seq.fold (||) false
+
+let ABACount : seq<string> -> int=
+    Seq.filter validABA >> Seq.length
+
+ABACount lines |> printfn "%d"
\ No newline at end of file
diff --git a/day8.py b/day8.py
new file mode 100644
index 0000000..868aeb1
--- /dev/null
+++ b/day8.py
@@ -0,0 +1,46 @@
+import numpy as np
+import re
+
+def parse_line(line: str):
+    '''
+    rect/rotate = 0/1
+    row/col = 0/1
+    dims = int/int
+    '''
+    splitline = line.strip().split()
+    if splitline[0] == 'rect':
+        col, row = map(int, splitline[-1].split('x'))
+        return (0, -1, col, row)
+    else:
+        dim, offset = map(int, re.findall(r'\d+', line))
+        if splitline[1] == 'row':
+            return (1, 0, dim, offset)
+        else:
+            return (1, 1, dim, offset)
+
+with open('day8.txt') as data:
+    insts = [parse_line(line) for line in data]
+
+def part1(instructions):
+    grid = np.zeros((6, 50), dtype=bool)
+    for inst in instructions:
+        match inst:
+            case 0, _, col, row:
+                grid[0:row, 0:col] = True
+            case 1, axis, dim, offset:
+                if axis == 0:
+                    grid[dim] = np.roll(grid[dim], offset)
+                else:
+                    grid[:, dim] = np.roll(grid[:, dim], offset)
+    return grid
+
+def part2(instructions):
+    grid = part1(instructions)
+    printable = np.zeros_like(grid, dtype=str)
+    printable[grid] = "*"
+    printable[~grid] = " "
+    for line in printable:
+        print("".join(char for char in line))
+
+print(np.count_nonzero(part1(insts)))
+part2(insts)
\ No newline at end of file