-
Notifications
You must be signed in to change notification settings - Fork 0
/
Solution_2020_14.swift
147 lines (131 loc) · 3.88 KB
/
Solution_2020_14.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//
// Solution_2020_14.swift
//
//
// Created by Ivan Chalov on 14.12.20.
//
import Foundation
import Algorithms
import Prelude
private enum Instruction {
case mask(String)
case mem(address: Int, value: Int)
}
extension Instruction {
init(string: String) {
if string.hasPrefix("mask") {
self = .mask(string |> flip(String.dropFirst)(7) >>> String.init)
}
else if string.hasPrefix("mem") {
let scanner = Scanner(string: string)
scanner.currentIndex = string.index(scanner.currentIndex, offsetBy: "mem[".count)
let address = scanner.scanInt()!
scanner.currentIndex = string.index(scanner.currentIndex, offsetBy: "] = ".count)
let value = scanner.scanInt()!
self = .mem(address: address, value: value)
} else {
fatalError("Incorrect Input")
}
}
}
private protocol Chip {
var mem: [Int: Int] { get set }
var sum: Int { get }
mutating func apply(instructions: [Instruction])
mutating func apply(_ instruction: Instruction)
}
extension Chip {
var sum: Int {
mem.map(\.value).sum()
}
mutating func apply(instructions: [Instruction]) {
instructions.forEach { apply($0) }
}
}
private struct Chip1: Chip {
var mask = ""
var mem = [Int: Int]()
mutating func apply(_ instruction: Instruction) {
switch instruction {
case let .mask(mask):
self.mask = mask
case let .mem(address: address, value: value):
set(value, at: address)
}
}
private mutating func set(
_ value: Int,
at address: Int
) {
let (newValue: newValue, power: _, current: _) = mask.reversed().reduce(
into: (newValue: 0, power: 1, current: value)
) { acc, x in
let digit: Int
if let maskDigit = Int(String(x)) {
digit = maskDigit
} else {
digit = acc.current % 2
}
acc.newValue += digit * acc.power
acc.current /= 2
acc.power *= 2
}
mem[address] = newValue
}
}
private struct Chip2: Chip {
var mask = [Character]()
var mem = [Int: Int]()
mutating func apply(_ instruction: Instruction) {
switch instruction {
case let .mask(mask):
self.mask = mask.map(id)
case let .mem(address: address, value: value):
set(value, at: address)
}
}
private mutating func set(
_ value: Int,
at address: Int,
_ index: Int = 0,
_ power: Int = 1,
_ newAddress: Int = 0
) {
if index == mask.count {
mem[newAddress] = value
return
}
switch mask.reversed()[index] {
case "1":
set(value, at: address / 2, index + 1, power * 2, newAddress + power)
case "0":
set(value, at: address / 2, index + 1, power * 2, newAddress + (address % 2) * power)
case "X":
set(value, at: address / 2, index + 1, power * 2, newAddress + power)
set(value, at: address / 2, index + 1, power * 2, newAddress)
default:
fatalError("Incorrect Mask")
}
}
}
struct Solution_2020_14: Solution {
var input: Input
func run() throws {
let input = try self.input.get()
.split(whereSeparator: \.isNewline)
.map(String.init >>> Instruction.init(string:))
// ------- Part 1 -------
var chip1 = Chip1()
chip1.apply(instructions: input)
let part1 = chip1.sum
print(part1)
// ------- Part 2 -------
var chip2 = Chip2()
chip2.apply(instructions: input)
let part2 = chip2.sum
print(part2)
// ------- Test -------
assert(part1 == 17481577045893, "WA")
assert(part2 == 4160009892257, "WA")
}
}