@@ -5,58 +5,94 @@ use std::{
5
5
thread:: { spawn, JoinHandle } ,
6
6
} ;
7
7
8
+ #[ derive( Clone , Copy , Eq , PartialEq , Hash , Debug ) ]
9
+ enum Mode {
10
+ Position ,
11
+ Immediate ,
12
+ Relative ,
13
+ }
14
+
8
15
pub struct Program {
9
- original_memory : Vec < i32 > ,
16
+ original_memory : Vec < i64 > ,
10
17
pointer : usize ,
11
- input : Receiver < i32 > ,
18
+ relative_base : usize ,
19
+ input : Receiver < i64 > ,
12
20
halted : bool ,
13
- output : Sender < i32 > ,
14
- output_value : i32 ,
15
- pub memory : Vec < i32 > ,
21
+ output : Sender < i64 > ,
22
+ output_value : i64 ,
23
+ pub memory : Vec < i64 > ,
16
24
}
17
25
18
26
impl Program {
19
- pub fn new ( memory : & Vec < i32 > ) -> Program {
27
+ pub fn new ( memory : & Vec < i64 > ) -> Program {
20
28
let ( output, input) = channel ( ) ;
21
29
22
30
Program {
23
31
original_memory : memory. clone ( ) ,
24
32
pointer : 0 ,
25
33
output_value : 0 ,
34
+ relative_base : 0 ,
26
35
input,
27
36
halted : false ,
28
37
memory : memory. clone ( ) ,
29
38
output,
30
39
}
31
40
}
32
41
33
- pub fn new_input ( & mut self , input : Receiver < i32 > ) {
34
- self . input = input ;
42
+ pub fn new_input ( & mut self , receiver : Receiver < i64 > ) {
43
+ self . input = receiver ;
35
44
}
36
45
37
- pub fn new_output ( & mut self , output : Sender < i32 > ) {
38
- self . output = output ;
46
+ pub fn new_output ( & mut self , sender : Sender < i64 > ) {
47
+ self . output = sender ;
39
48
}
40
49
41
50
pub fn is_halted ( & self ) -> bool {
42
51
self . halted
43
52
}
44
53
45
- fn get_index ( & mut self , step : usize , positional : bool ) -> usize {
46
- if positional {
47
- self . memory [ self . pointer + step] as usize
48
- } else {
49
- self . pointer + step
54
+ fn get_index ( & mut self , step : usize , mode : Mode ) -> usize {
55
+ match mode {
56
+ Mode :: Position => self . memory [ self . pointer + step] as usize ,
57
+ Mode :: Immediate => self . pointer + step,
58
+ Mode :: Relative => self . memory [ self . pointer + step] as usize ,
59
+ }
60
+ }
61
+
62
+ fn ensure_memory_available ( & mut self , position : & usize ) {
63
+ if * position >= self . memory . len ( ) {
64
+ self . memory . resize ( position + 1 , 0 ) ;
50
65
}
51
66
}
52
67
53
- fn mode_1_2 ( & mut self , opcode : i32 , positional_first : bool , positional_second : bool ) -> usize {
54
- let noun_index = self . get_index ( 1 , positional_first) ;
55
- let verb_index = self . get_index ( 2 , positional_second) ;
56
- let out_index = self . get_index ( 3 , true ) ;
57
- let noun = self . memory [ noun_index] ;
58
- let verb = self . memory [ verb_index] ;
59
- self . memory [ out_index] = if opcode == 1 {
68
+ fn get_memory < ' a > ( & ' a mut self , step : usize , mode : Mode ) -> i64 {
69
+ let next = match mode {
70
+ Mode :: Relative => {
71
+ let index = & ( self . pointer + step) ;
72
+ self . ensure_memory_available ( & index) ;
73
+ self . memory [ * index] . to_owned ( ) + ( self . relative_base as i64 )
74
+ }
75
+ _ => {
76
+ let index = & self . get_index ( step, mode) ;
77
+ self . ensure_memory_available ( & index) ;
78
+ self . memory [ * index]
79
+ }
80
+ } ;
81
+
82
+ next
83
+ }
84
+
85
+ fn get_mut_memory_ref < ' a > ( & ' a mut self , index : & ' a usize ) -> & ' a mut i64 {
86
+ self . ensure_memory_available ( & index) ;
87
+ & mut self . memory [ * index]
88
+ }
89
+
90
+ fn mode_1_2 ( & mut self , opcode : i64 , mode_first : Mode , mode_second : Mode ) -> i64 {
91
+ let noun = self . get_memory ( 1 , mode_first) ;
92
+ let verb = self . get_memory ( 2 , mode_second) ;
93
+ let index = & self . get_index ( 3 , Mode :: Position ) ;
94
+
95
+ * self . get_mut_memory_ref ( index) = if opcode == 1 {
60
96
noun + verb
61
97
} else {
62
98
noun * verb
@@ -65,72 +101,71 @@ impl Program {
65
101
4
66
102
}
67
103
68
- fn mode_3_4 ( & mut self , opcode : i32 ) -> usize {
69
- let index = self . get_index ( 1 , true ) ;
104
+ fn mode_3_4 ( & mut self , opcode : i64 , mode : Mode ) -> i64 {
70
105
if opcode == 3 {
71
106
let input = self . input . recv ( ) . unwrap_or ( 0 ) ;
72
- self . memory [ index] = input. to_owned ( ) ;
107
+ let index = & self . get_index ( 1 , Mode :: Position ) ;
108
+ * self . get_mut_memory_ref ( index) = input. to_owned ( ) ;
73
109
} else {
74
- let output = self . memory [ index ] . clone ( ) ;
110
+ let output = self . get_memory ( 1 , mode ) ;
75
111
self . output . send ( output. to_owned ( ) ) . unwrap_or ( ( ) ) ;
76
112
self . output_value = output. to_owned ( ) ;
77
113
} ;
78
114
79
115
2
80
116
}
81
117
82
- fn mode_5_6 (
83
- & mut self ,
84
- opcode : i32 ,
85
- position_mode_first : bool ,
86
- position_mode_second : bool ,
87
- ) -> usize {
88
- let first_index = self . get_index ( 1 , position_mode_first) ;
89
- let second_index = self . get_index ( 2 , position_mode_second) ;
90
- let param_1 = self . memory [ first_index] ;
91
- let param_2 = self . memory [ second_index] ;
118
+ fn mode_5_6 ( & mut self , opcode : i64 , mode_first : Mode , mode_second : Mode ) -> i64 {
119
+ let param_1 = self . get_memory ( 1 , mode_first) ;
120
+ let param_2 = self . get_memory ( 2 , mode_second) ;
92
121
93
122
if ( opcode == 5 && param_1 != 0 ) || ( opcode == 6 && param_1 == 0 ) {
94
- param_2 as usize - self . pointer
123
+ param_2 - self . pointer as i64
95
124
} else {
96
125
3
97
126
}
98
127
}
99
128
100
- fn mode_7_8 (
101
- & mut self ,
102
- opcode : i32 ,
103
- position_mode_first : bool ,
104
- position_mode_second : bool ,
105
- ) -> usize {
106
- let first_index = self . get_index ( 1 , position_mode_first) ;
107
- let second_index = self . get_index ( 2 , position_mode_second) ;
108
- let third_index = self . get_index ( 3 , true ) ;
129
+ fn mode_7_8 ( & mut self , opcode : i64 , mode_first : Mode , mode_second : Mode ) -> i64 {
130
+ let a = self . get_memory ( 1 , mode_first) ;
131
+ let b = self . get_memory ( 2 , mode_second) ;
132
+ let index = & self . get_index ( 3 , Mode :: Position ) ;
109
133
110
- let a = self . memory [ first_index] ;
111
- let b = self . memory [ second_index] ;
112
-
113
- self . memory [ third_index] = if ( opcode == 7 && a < b) || ( opcode == 8 && a == b) {
134
+ * self . get_mut_memory_ref ( index) = if ( opcode == 7 && a < b) || ( opcode == 8 && a == b) {
114
135
1
115
136
} else {
116
137
0
117
138
} ;
118
139
4
119
140
}
120
141
121
- fn to_int ( & mut self , input : & char ) -> i32 {
122
- ( & input. to_string ( ) ) . parse :: < i32 > ( ) . unwrap ( )
142
+ fn mode_9 ( & mut self , mode : Mode ) -> i64 {
143
+ let memory = self . get_memory ( 1 , mode) as usize ;
144
+ let relative_base = self . relative_base + memory as usize ;
145
+
146
+ self . relative_base = relative_base;
147
+ 2
148
+ }
149
+
150
+ fn to_int ( & mut self , input : & char ) -> i64 {
151
+ ( & input. to_string ( ) ) . parse :: < i64 > ( ) . unwrap ( )
123
152
}
124
153
125
- fn position_mode ( & mut self , input : & Option < char > ) -> bool {
126
- input. unwrap_or ( '0' ) == '0'
154
+ fn mode ( & mut self , input : & Option < char > ) -> Mode {
155
+ match input. unwrap_or ( '0' ) {
156
+ '0' => Mode :: Position ,
157
+ '1' => Mode :: Immediate ,
158
+ '2' => Mode :: Relative ,
159
+ _ => Mode :: Position ,
160
+ }
127
161
}
128
162
129
- pub fn run ( & mut self ) -> i32 {
163
+ pub fn run ( & mut self ) -> i64 {
130
164
self . pointer = 0 ;
131
165
self . output_value = 0 ;
132
166
self . halted = false ;
133
167
self . memory = self . original_memory . clone ( ) ;
168
+ self . relative_base = 0 ;
134
169
135
170
while !self . halted {
136
171
self . eval ( )
@@ -151,48 +186,48 @@ impl Program {
151
186
let mut instuction = string. chars ( ) . rev ( ) ;
152
187
let opcode = self . to_int ( & instuction. next ( ) . unwrap ( ) ) ;
153
188
instuction. next ( ) ;
154
- let positional_first = self . position_mode ( & instuction. next ( ) ) ;
155
- let positional_second = self . position_mode ( & instuction. next ( ) ) ;
156
-
157
- self . pointer += match opcode {
158
- 1 | 2 => self . mode_1_2 ( opcode, positional_first, positional_second) ,
159
- 3 | 4 => self . mode_3_4 ( opcode) ,
160
- 5 | 6 => self . mode_5_6 ( opcode, positional_first, positional_second) ,
161
- 7 | 8 => self . mode_7_8 ( opcode, positional_first, positional_second) ,
162
- 9 => {
163
- self . halted = true ;
164
- 0
165
- }
189
+ let mode_first = self . mode ( & instuction. next ( ) ) ;
190
+ let mode_second = self . mode ( & instuction. next ( ) ) ;
191
+
192
+ let next = match opcode {
193
+ 1 | 2 => self . mode_1_2 ( opcode, mode_first, mode_second) ,
194
+ 3 | 4 => self . mode_3_4 ( opcode, mode_first) ,
195
+ 5 | 6 => self . mode_5_6 ( opcode, mode_first, mode_second) ,
196
+ 7 | 8 => self . mode_7_8 ( opcode, mode_first, mode_second) ,
197
+ 9 => self . mode_9 ( mode_first) ,
166
198
_ => panic ! ( "[{}], opcode: {}" , self . pointer, opcode) ,
167
199
} ;
200
+
201
+ self . pointer = ( ( self . pointer as i64 ) + next) as usize ;
168
202
}
169
203
}
170
204
171
- pub fn exec ( memory : Vec < i32 > , input : Receiver < i32 > , output : Sender < i32 > ) -> JoinHandle < i32 > {
205
+ pub fn exec ( memory : Vec < i64 > , receiver : Receiver < i64 > , sender : Sender < i64 > ) -> JoinHandle < i64 > {
172
206
spawn ( move || {
173
207
let mut program = Program :: new ( & memory) ;
174
- program. new_input ( input ) ;
175
- program. new_output ( output ) ;
208
+ program. new_input ( receiver ) ;
209
+ program. new_output ( sender ) ;
176
210
program. run ( )
177
211
} )
178
212
}
179
213
180
- pub fn exec_without_channels ( memory : Vec < i32 > , input : Option < Vec < i32 > > ) -> i32 {
181
- let ( c_out , c_in ) = channel ( ) ;
214
+ pub fn exec_without_channels ( memory : Vec < i64 > , input : Option < Vec < i64 > > ) -> i64 {
215
+ let ( sender , receiver ) = channel ( ) ;
182
216
match input {
183
217
Some ( input) => {
184
218
for seq in input. clone ( ) {
185
- c_out . send ( seq) . unwrap ( ) ;
219
+ sender . send ( seq) . unwrap ( ) ;
186
220
}
187
221
}
188
222
None => {
189
- c_out . send ( 0 ) . unwrap ( ) ;
223
+ sender . send ( 0 ) . unwrap ( ) ;
190
224
}
191
225
} ;
226
+
192
227
spawn ( move || {
193
228
let mut program = Program :: new ( & memory) ;
194
- program. new_input ( c_in ) ;
195
- program. new_output ( c_out ) ;
229
+ program. new_input ( receiver ) ;
230
+ program. new_output ( sender ) ;
196
231
program. run ( )
197
232
} )
198
233
. join ( )
0 commit comments