diff options
author | Brian Chu <brianmchu42@gmail.com> | 2022-01-04 22:14:05 -0800 |
---|---|---|
committer | Brian Chu <brianmchu42@gmail.com> | 2022-01-04 22:14:05 -0800 |
commit | 102086e040577a4f6b3e7d97e442ee32e12f3e27 (patch) | |
tree | c88f097b0a798bc9e1cd4ed09684216ac0f0946d | |
download | AdventOfCode2016-102086e040577a4f6b3e7d97e442ee32e12f3e27.tar.gz |
solutions to day 8
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | day1.fsx | 58 | ||||
-rw-r--r-- | day2.fsx | 51 | ||||
-rw-r--r-- | day3.fsx | 20 | ||||
-rw-r--r-- | day4.fsx | 56 | ||||
-rw-r--r-- | day5.fsx | 43 | ||||
-rw-r--r-- | day6.fsx | 18 | ||||
-rw-r--r-- | day7.fsx | 69 | ||||
-rw-r--r-- | day8.py | 46 |
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 |