-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path02.rkt
161 lines (134 loc) · 5.23 KB
/
02.rkt
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#|
Day 2
https://adventofcode.com/2024/day/02
Still getting the hang of using racket so this day took a bit
longer than it should have due to a lot of small mistakes.
The basic plan was parse the input then check
every adjancent pair for each line and see if the
absolute diff was < 4 and > 0. I also recorded the
sign of the diff (positive or negative) and passed that
along to the next pair to check if following diffs are also
in the same direction (increase or decrease).
For part 2, I used the same function but added a 'damepener'
which added an 'or' condition when true that also checked the list
if the current element was skipped. It then recusred with dampener
disabled.
|#
#lang racket/base
(require racket/string)
(require racket/list)
(require "../solution.rkt")
(provide run)
;; parse-levels :: string -> [[integer]]
;; parse day 2 into levels
(define (parse-levels input)
(let ([lines (string-split input "\n")])
(map
(λ (l) (map string->number (string-split l)))
lines)
))
;; a Trend is one of:
;; - 'increase
;; - 'decrease
;; - 'zero
;; same-sign? :: Trend Trend -> boolean
;; checks if two Trendss are the same
;; assues the 'zero trend matches both as it is used
;; as the initial trend
(define (same-sign? new-sign last-sign)
(or (equal? last-sign 'zero)
(equal? last-sign new-sign)))
;; get-trend :: integer -> Trend
;; get trends returns the trend for the levels
(define (get-trend diff)
(cond
[(equal? diff 0) 'zero]
[(> diff 0) 'increase]
[else 'decrease]))
;; report-safe :: [[integer]] boolean? -> boolean
;; determines if a report is safe.
;; optionally can enable the problem-dampener which
;; additionally returns safe reports if removing one
;; level results in a safe report
(define (report-safe? levels #:enable-dampener [problem-dampener #f])
(letrec ([get-sign (λ (diff) (if (> diff 0) 'increase 'decrease))]
;; test is the adjancent is stafe
[adjacent-safe?
(λ (diff last-sign next dampener)
(let ([sign (get-sign diff)]
[abs-diff (abs diff)])
(and (> abs-diff 0) (< abs-diff 4)
(same-sign? sign last-sign)
(report-safe-helper next sign dampener))))]
;; helper, using last-sign and dampener as accumulators
[report-safe-helper
(λ (l last-sign dampener)
(or
(<= (length l) (if dampener 2 1))
;; test without using dampener
(adjacent-safe?
;; diff is l[1] - l[0]
(- (cadr l) (car l))
last-sign
;; next is l[1:]
(cdr l)
dampener)
;; if failed, test using dampener if unusued
(and dampener
;; if we get here, dampener is #t
(adjacent-safe?
;; diff is l[2] - l[0]
(- (caddr l) (car l))
last-sign
;; next is l[2:]
(cddr l)
;; dampener is now used
#f))))])
(or
(report-safe-helper levels 'zero problem-dampener)
;; have to also check if using the dampener on the first item
(and problem-dampener (report-safe-helper (cdr levels) 'zero #f)))))
(define (run input)
(let* ([levels (parse-levels input)]
[part1 (length (filter report-safe? levels))]
[part2 (length (filter (λ (l) (report-safe? l #:enable-dampener #t)) levels))])
(full-solution part1 part2)))
(module+ test
(require rackunit)
(define example-input #<<EOF
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
EOF
)
(define example-levels (parse-levels example-input))
(check-equal? example-levels '((7 6 4 2 1)
(1 2 7 8 9)
(9 7 6 2 1)
(1 3 2 4 5)
(8 6 4 4 1)
(1 3 6 7 9)))
(check-equal? (report-safe? '(7 6 4 2 1)) #t)
(check-equal? (report-safe? '(1 2 7 8 9)) #f)
(check-equal? (report-safe? '(9 7 6 2 1)) #f)
(check-equal? (report-safe? '(1 3 2 4 5)) #f)
(check-equal? (report-safe? '(8 6 4 4 1)) #f)
(check-equal? (report-safe? '(1 3 6 7 9)) #t)
(check-equal? (report-safe? '(7 6 4 2 1) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(1 2 7 8 9) #:enable-dampener #t) #f)
(check-equal? (report-safe? '(9 7 6 2 1) #:enable-dampener #t) #f)
(check-equal? (report-safe? '(1 3 2 4 5) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(8 6 4 4 1) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(1 3 6 7 9) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(10 8 10 6 4 2 1)) #f)
(check-equal? (report-safe? '(10 8 10 6 4 2 1) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(1 2 3 4 5 11) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(1 2 3 4 5 11)) #f)
(check-equal? (report-safe? '(99 1 2 3 4 5) #:enable-dampener #t) #t)
(check-equal? (report-safe? '(99 1 2 3 4 5)) #f)
(check-equal? (length (filter report-safe? example-levels)) 2)
(check-equal? (length (filter (λ (l) (report-safe? l #:enable-dampener #t)) example-levels)) 4)
)