summaryrefslogtreecommitdiff
path: root/wake-up.scm
blob: 3f64dce29b44d720f74d4d3aef4f4d555eb4111a (plain)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
; https://xn--rpa.cc/irl/term.html
(define-module (depre main)
  #:use-module (ice-9 textual-ports))

;; Clean indentation from strings
(eval-when (expand load eval)
  (read-enable 'hungry-eol-escapes))

;; Random seed
(set! *random-state* (random-state-from-platform))

;; Code makes heavy use of functional code and parameters for state.
(define max-100 (lambda (x) (if (> x 100) 100 x)))
(define *depression* (make-parameter 40 max-100))
(define *tiredness*  (make-parameter 40 max-100))
(define *day*        (make-parameter 1))

;; Control SIGINT
(sigaction SIGINT
           (lambda (sig)
             (exit-with-message)))

;; Exit message
(define (exit-with-message)
  (newline)
  (display "---------------------------")
  (newline)
  (display "Exiting game.")
  (newline)
  (display (string-append "Days played: " (number->string (*day*))))
  (newline)
  (newline)
  (display "This game tries to show the internal dialog of a depressed person \
           that is alone at home, working as a freelance, on a phd or any job \
           that allows to work on an independent way.\n\
           Somehow, it tries to express the life of those who suffer in \
           silence, alone in their caves. Hopefully, this game made you \
           empathize with them. \n\
           If you feel identified by what it is shown here, it might be time \
           to review your internal dialog and treat yourself better. You \
           deserve to be loved.\n")
  (newline)
  (display "Thanks for playing.")
  (newline)
  (exit))

(define (nth n lst)
  (if (> n (length lst))
    (error "Chosen element longer than provided list")
    (let loop ((lst lst)
               (n n))
    (if (= 1 n)
      (car lst)
      (loop (cdr lst) (- n 1))))))


;; Function combinations: they define the state transitions
(define (combine . functions)
  "Calls given functions in given order."
  (lambda ()
    (let loop ((fs functions))
      (when (not (null? fs))
        ((car fs))
        (loop (cdr fs))))))

;; Transition by chance, according to the state
;; Example:
;; - You are too tired for that, so you do this instead
;; - Or you actually do it
;; NOTE: The functions try with 120 to leave some chance to randomness even if
;; you are tired or depressed to the limit
(define (f-or-tired f tired)
  (lambda ()
    (if (< (random 120) (*tiredness*)) (f) (tired))))

(define (f-or-depressed f depressed)
  (lambda ()
    (if (< (random 120) (*depression*)) (f) (depressed))))


;; State alteration functions for easy access
(define (tire)
  (lambda () (*tiredness*  (+ (*tiredness*) 5))))

(define (rest)
  (lambda () (*tiredness*  (- (*tiredness*) 5))))

(define (depress)
  (lambda () (*depression* (+ (*depression*) 5))))

(define (cheer-up)
  (lambda () (*depression* (- (*depression*) 5))))

(define (tire+)
  (lambda () (*tiredness*  (+ (*tiredness*) 8))))

(define (rest+)
  (lambda () (*tiredness*  (- (*tiredness*) 8))))

(define (depress+)
  (lambda () (*depression* (+ (*depression*) 8))))

(define (cheer-up+)
  (lambda () (*depression* (- (*depression*) 8))))

(define (next-day)
  (lambda () (*day* (+ 1 (*day*)))))

;; Simple I/O
(define (answer message)
  (lambda ()
    (newline)
    (display message)
    (when (eof-object? (get-line (current-input-port)))
      (exit-with-message))))

(define (bar percent)
  "A simple 12 character bar for life-like variable representation"
  (define len 22)
  (string-tabulate
    (lambda (x)
      (cond
        ((= x 0)                          #\[)
        ((= x (- len 1))                  #\])
        ((>= (/ percent (/ 100 len)) x)   #\=)
        (else                             #\space)))
    len))

(define (day-banner)
  (lambda ()
    (newline)
    (display "---------------------------")
    (newline)
    (display (string-append "Day  " (number->string (*day*))))
    (newline)))

(define (read-number)
  (let ((line (get-line (current-input-port))))
    (if (eof-object? line)
        (exit-with-message)
        (string->number line))))

;; Basic state representation and creation: A state is a function that knows
;; how to jump to other states through a menu.
(define* (state heading menu #:optional (hide-status #f))
  (lambda ()
    (when (not hide-status)
      (newline)
      (display "Depression:\t")
      (display (bar (*depression*)))
      (newline)
      (display "Tiredness:\t")
      (display (bar (*tiredness*))))
    (newline)
    (display heading)
    (newline)
    (map (lambda (opt num)
           (display (string-append "  " (number->string num) "- " (car opt)))
           (newline))
         menu (iota (length menu) 1))
    (display "You choose >  ")
    (let loop ((chosen (read-number)))
      (if (and (number? chosen) (<= chosen (length menu)))
        ((cdr (nth chosen menu)))
        (begin
          (display "Wrong answer. Try again >  ")
          (loop (read-number)))))))

;; States:

;; Some macro magic for indirection that enables recursion.
;; I don't really know how it works (yet!)
(define %states (make-hash-table))
(define-macro (register-state name f)
  `(hash-set! %states ,name ,f))
(define-macro (to-state name)
  `(lambda () ((hash-ref %states ,name))))


(register-state
  'start
  (state "Hi, game starts"
         (list
           (cons "Start game"
                 (combine
                   (answer "Let's start, then. Press [ENTER] to continue. \
                           Exit with [Ctrl-D].")
                   (to-state 'wake-up)))
           (cons "Quit game"
                 (answer "Good bye!")))
         #:hide-status))

(register-state
  'wake-up
  (state "Good morning. It's time to wake up, what do you want to do?"
         (list
           (cons "Wake up and start your day."
                 (f-or-tired
                   (combine
                     (answer "You just woke up, had your shower, had some \
                             breakfast and now you are ready for \
                             anything.")
                             (cheer-up+)
                             (tire)
                             (to-state 'morning-1))
                     (combine
                       (answer "You are too tired for waking up now. You \
                               stay at bed instead and your day starts in \
                               mid morning.")
                               (depress)
                               (rest)
                               (to-state 'morning-2))))

           (cons "Stay in bed."
                 (combine
                   (answer "You rest for a little bit more, but you feel \
                           bad because you have a hard time waking up \
                           like a normal person.")
                           (depress)
                           (rest)
                           (to-state 'morning-2))))))

(register-state
  'morning-1
  (state "It's early in the morning. You have time to do whatever you want \
         right now. What do you want to do?"
    (list
      (cons "Work."
            (f-or-tired
              (combine
                (answer "You worked for a couple of hours.")
                (tire)
                (to-state 'morning-2))
              (combine
                (answer "You are too tired to work. You do nothing for a \
                        couple of hours and you feel bad for wasting your \
                        time.")
                (depress+)
                (to-state 'morning-2))))

      (cons "Relax."
            (combine
              (answer "You do nothing for a couple of hours and feel guilty \
                      because you didn't work.")
              (depress)
              (rest)
              (to-state 'morning-2))))))

(register-state
  'morning-2
  (state "It's late in the morning. You still have some time before having \
         lunch. What do you want to do?"
    (list
      (cons "Work."
            (f-or-depressed
              (f-or-tired
                (combine
                  (answer "You worked for a couple of hours.")
                  (tire)
                  (cheer-up)
                  (to-state 'lunch))
                (combine
                  (answer "You are too tired to work. Not that long ago you \
                          were able to work for longer time. You are getting \
                          worse.")
                          (depress+)
                          (to-state 'lunch)))
              (combine
                (answer "It's almost time to have lunch... Maybe it's better \
                        just to leave work for later.")
                (depress)
                (to-state 'lunch))))

      (cons "Relax."
            (combine
              (answer "You do nothing for a couple of hours. Is this what you \
                      call \"working hard\"?")
              (depress)
              (rest+)
              (to-state 'lunch))))))


(register-state
  'lunch
  (state "You have something for lunch. What do you want to do now?"
    (list
      (cons "Work."
            (f-or-depressed
              (f-or-tired
                (combine
                  (answer "You worked for a couple of hours.")
                  (tire)
                  (to-state 'evening))
                (combine
                  (answer "You are too tired to work. As always.")
                          (depress+)
                          (to-state 'evening)))
              (combine
                (answer "Work? What for? It's meaningless. Just let your life \
                        pass while asking yourself why you are doing nothing.")
                (depress)
                (to-state 'evening))))

      (cons "Relax."
            (f-or-depressed
              (combine
                (answer "You do nothing. Sometimes it's good for you.")
                        (depress)
                        (rest)
                        (to-state 'evening))
              (combine
                (answer "You can't just relax. You are worthless if you don't \
                        work. \
                        You overwork and spend the whole afternoon working in \
                        bad conditions.")
                (tire+)
                (to-state 'dinner)))))))

(register-state
  'evening
  (state "You still have some time until dinner. What do you want to do?"
  (list
    (cons "Work."
          (f-or-depressed
            (combine
              (answer "You work. It's late so it's really tiring and you have \
                      a hard time concentrating.")
              (tire+)
              (to-state 'dinner))
            (combine
              (answer "You work because what else you could do? There's \
                      nothing else in your life.\
                      You work in bad conditions and you skip dinner because \
                      you are obsessed with your job.")
              (depress)
              (tire+)
              (day-banner)
              (to-state 'wake-up))))
    (cons "Relax at home."
          (f-or-depressed
            (combine
              (answer "You relax at home. You stayed at home the whole day. \
                      Again.")
              (depress+)
              (to-state 'dinner))
            (combine
              (answer "You are bored, you play around with work related stuff \
                      until it's time to have dinner.")
              (tire)
              (to-state 'dinner))))
    (cons "Go outside."
          (f-or-depressed
            (combine
              (answer "You go outside for a walk.")
              (cheer-up+)
              (cheer-up)
              (to-state 'dinner))
            (combine
              (answer "It's already dark outside. You don't feel like going \
                      outside. You wait doing nothing until dinner time.")
              (depress)
              (to-state 'dinner)))))))

(register-state
  'dinner
  (state "Time for dinner. What do you want to do afterwards?"
    (list
      (cons "Work"
            (f-or-tired
              (combine
                (answer "You work for some time and then go to bed.")
                (cheer-up)
                (tire)
                (next-day)
                (day-banner)
                (to-state 'wake-up))

              (combine
                (answer "You are too tired to work. You watch some TV while \
                        you could be doing something productive. The story \
                        of your life.")
                (depress)
                (rest)
                (next-day)
                (day-banner)
                (to-state 'wake-up))))
      (cons "Relax"
            (f-or-depressed
              (combine
                (answer "You manage to relax watching a film. And go to bed \
                        afterwards.")
                (day-banner)
                (to-state 'wake-up))
              (combine
                (answer "You didn't work enough during the day and you want \
                        to relax. You should be working.\n \
                        You work until it's late and then go to bed.")
                (tire+)
                (depress)
                (next-day)
                (day-banner)
                (to-state 'wake-up)))))))

((to-state 'start))