-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay8.R
144 lines (120 loc) · 3.77 KB
/
Day8.R
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
### IMPORT + FORMAT DATA ###
setwd("~/Other/Programming/Advent of code/2020/Data")
boot <- read.table(text = gsub("-", "- ",
gsub("\\+", "\\+ ",
readLines("Day8data.txt"))),
sep = " ",
stringsAsFactors = FALSE)
### FUNCTIONS ###
updateACC <- function(acc, op, num) {
# DESCRIPTION #
# Originally designed to update the accumulator according to given instructions
# However, it also serves to update the instruction line when a jump command is used
# PARAMETERS #
# acc: current value in accumulator OR current instruction line
# op: operation ("+" or "-")
# num: value by which accumulator OR current instruction line is to be updated by, in direction
# specified by op
return(
eval(
parse(
text = paste(
toString(acc),
op,
toString(num)
)
)
)
)
}
read <- function(bootcode, acc, inst) {
# DESCRIPTION #
# takes current accumulator value and instruction line number and returns their updated values after
# reading and parsing the current line of code
# PARAMETERS #
# bootcode: table of boot instructions
# acc: current acumulator value
# inst: current instruction line
# RETURNS
# c(updated accumulator value, updated boot code line)
fn <- bootcode[inst, 1]
sgn <- bootcode[inst, 2]
num <- bootcode[inst, 3]
if (fn == "nop") {
return(c(acc,
inst + 1))
} else if (fn == "acc") {
return(c(updateACC(acc,
sgn,
num),
inst + 1))
} else {
return(c(acc,
updateACC(inst,
sgn,
num)))
}
### PART 1 ###
ACC <- 0
instr <- 1
n <- nrow(boot)
visited <- numeric(n)
while (visited[instr] == 0) {
visited[instr] <- 1
# we can update accumulator and instruction line separately ONLY IF WE UPDATE THE ACCUMULATOR FIRST
# (because instr affects the next update of ACC, but ACC does not affect the next update of instr)
ACC <- read(boot, ACC, instr)[1]
instr <- read(boot, ACC, instr)[2]
}
}
print(ACC)
### PART 2 ###
runboot <- function(bootcode) {
# DESCRIPTION #
# Runs entire boot sequence and checks for errors (e.g. index oob or a loop)
# PARAMETERS
# bootcode: table of boot instructions
# RETURNS
# either "ERROR" if there is a loop or the index goes oob,
# or the value of the accumulator if the code works
# reset boot sequence
ACC <- 0
instr <- 1
visited <- numeric(n)
repeat {
# check if we've left the range of instructions (or reached a loop) and act accordingly
# order matters: the third check needs to be done after the first two
if (instr > n+1) {
return("ERROR")
}
if (instr == n+1) {
return(ACC)
}
if (visited[instr] == 1) {
return("ERROR")
}
# and if we haven't, carry on as normal
visited[instr] <- 1
ACC <- read(bootcode, ACC, instr)[1]
instr <- read(bootcode, ACC, instr)[2]
}
}
# Now we can loop through, changing each instruction and running the new versions of the code
for (i in 1:n) {
newboot <- boot
if (boot[i, 1] == "jmp") {
newboot[i, 1] <- "nop" # make attempt to fix instruction
result <- runboot(newboot) # run new boot code
if (result != "ERROR") { # print result if code works
print(result)
break
}
} else if (boot[i, 1] == "nop") {
newboot[i, 1] <- "jmp" # make attempt to fix instruction
result <- runboot(newboot) # run new boot code
if (result != "ERROR") { # print result if code works
print(result)
break
}
}
}