From 102086e040577a4f6b3e7d97e442ee32e12f3e27 Mon Sep 17 00:00:00 2001 From: Brian Chu Date: Tue, 4 Jan 2022 22:14:05 -0800 Subject: solutions to day 8 --- .gitignore | 2 ++ day1.fsx | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ day2.fsx | 51 ++++++++++++++++++++++++++++++++++++++++++++++ day3.fsx | 20 ++++++++++++++++++ day4.fsx | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ day5.fsx | 43 +++++++++++++++++++++++++++++++++++++++ day6.fsx | 18 ++++++++++++++++ day7.fsx | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ day8.py | 46 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 363 insertions(+) create mode 100644 .gitignore create mode 100644 day1.fsx create mode 100644 day2.fsx create mode 100644 day3.fsx create mode 100644 day4.fsx create mode 100644 day5.fsx create mode 100644 day6.fsx create mode 100644 day7.fsx create mode 100644 day8.py 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 = + 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) (posfunc: int*int -> string -> int*int) (keyfunc: int*int -> string) (start: int*int): list = + 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): 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) : list = + let windows (group: bool * list) = + 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 -> 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 -- cgit 1.4.1-2-gfad0