-
Notifications
You must be signed in to change notification settings - Fork 0
/
5.wsf
111 lines (98 loc) · 3.07 KB
/
5.wsf
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
# Advent of Code 2021
# Day 5: Hydrothermal Venture
# https://adventofcode.com/2021/day/5
"@array" import
"@bool" import
"@char" import
"@int" import
"@math" import
"@string" import
0 ^ readi retrieve
0
.read_loop:
^ 4* call read_line_segment jz .read_error
1+
^ ^2 j< .read_loop
drop
4* 0 ^1
.horiz_vert_loop:
^1 call push_points_horiz_vert
swap 4+ swap
^1 ^3 j< .horiz_vert_loop
1slide
2dup ^1 -
2dup call array.quicksort # Recursion out of memory
call array.print
2drop end
# read_line_segment reads the points of a line segment in the form:
# x1,y1 -> x2,y2. Stores at addr..addr+4.
# (addr -- ok?)
read_line_segment:
^ ^ 10 ',' call int.read_base_until jz .read_line_segment_err3 store
1+ ^ ^ 10 ' ' call int.read_base_until jz .read_line_segment_err3 store
1+ ^ '-' call char.read_expect jz .read_line_segment_err1
^ '>' call char.read_expect jz .read_line_segment_err1
^ ' ' call char.read_expect jz .read_line_segment_err1
^ ^ 10 ',' call int.read_base_until jz .read_line_segment_err3 store
1+ ^ ^ 10 '\n' call int.read_base_until jz .read_line_segment_err3 store
drop 1 ret
.read_line_segment_err3:
2drop
.read_line_segment_err1:
drop 0 ret
# retrieve_line retrieves the two points at lineaddr.
# (lineaddr -- lineaddr x1 y1 x2 y2)
retrieve_line:
^ retrieve ^1 1+ retrieve ^2 2+ retrieve ^3 3+ retrieve ret
# is_horiz_vert returns whether the line segment is horizontal or
# vertical.
# (x1 y1 x2 y2 -- x1 y1 x2 y2 ?)
is_horiz_vert:
^1 ^4 - ^1 ^4 - call bool.nand ret
# is_diag returns whether the line segment is not horizontal or
# vertical. Includes line segments with slopes other than ±1.
# (x1 y1 x2 y2 -- x1 y1 x2 y2 ?)
is_diag:
^1 ^4 - ^1 ^4 - call bool.and ret
# get_slope returns the hashed slope of the line segment.
# (x1 y1 x2 y2 -- x1 y1 x2 y2 slope)
get_slope:
# Slope only works for horizontal, vertical, and diagonal lines.
^1 ^4 - call math.sign 1000* ^1 ^4 - call math.sign + ret
# push_points pushes hashed points to addr for all points on the line
# segment. Returns the updated address.
# (addr lineaddr -- addr')
push_points:
call retrieve_line
.push_points:
call get_slope
^2 1000* ^2 + # p2
^5 1000* ^5 + # p1
^8 # addr
.push_points_loop:
# addr lineaddr x1 y1 x2 y2 slope p2 p1 addr
^ ^2 store
1+ # addr++
^1 ^3 j= .push_points_break
swap ^3 + swap # p1 += slope
jmp .push_points_loop
.push_points_break:
9slide ret
# push_points_horiz_vert pushes points only for horizontal or vertical
# line segments.
# (addr lineaddr -- addr')
push_points_horiz_vert:
call retrieve_line
call is_diag jz .push_points
5drop ret
# push_points_diag pushes points only for line segments that are not
# horizontal or vertical.
# (addr lineaddr -- addr')
push_points_diag:
call retrieve_line
call is_horiz_vert jz .push_points
5drop ret
# (lines i -- )
.read_error:
-1 "Error: invalid line format"
call string.println_neg_stack 2drop end