about summary refs log tree commit diff stats
path: root/potato.scm
blob: 00f23fa1f3719f7b95e72898ec4a59adc9222a9e (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
#!/bin/sh
#| -*- scheme -*-
exec csi -s $0 "$@"
; POTATO: a one-file single-player RPG  ;
; based on https://twitter.com/deathbybadger/status/1567425842526945280 ;
; (a one-page single-player RPG by Oliver Darkshire) ;
; NOTE: the game play will not work in Geiser! ;
; ... something to do with (read-char) and Geiser injecting input.
|#

(import (chicken io)
        (chicken random)
        (chicken string))

;;; Global variables

(define destiny 0)
(define potatoes 0)
(define orcs 0)
(define orc-cost 1)

;;; Utilities

(define (roll)
  (+ 1 (pseudo-random-integer 6)))

(define-syntax inc!
  (syntax-rules ()
    ((_ x) (begin (set! x (+ x 1)) x))
    ((_ x n) (begin (set! x (+ x n)) x))))

(define-syntax dec!
  (syntax-rules ()
    ((_ x) (begin (set! x (if (< (- x 1) 0) 0 (- x 1))) x))
    ((_ x n) (begin (set! x (if (< (- x n) 0) 0 (- x n))) x))))

;;; UI

(define (clear-screen)
  (display #\escape)
  (display "[2J")
  (newline))

(define (prln . strs)
  (apply string-append
         (append (intersperse
                  (map (lambda (s)
                         (if (list? s)
                             (apply string-append (map ->string s))
                             (->string s)))
                       strs)
                  "\n")
                 '("\n"))))

(define (char-line c n)
  (string-append (make-string n c)
                   (make-string (- 10 n) #\-)))

(define (scores)
  (prln `("DESTINY  " ,(char-line #\* destiny))
        `("POTATOES " ,(char-line #\o potatoes))
        `("ORCS     " ,(char-line #\x orcs))))

(define (display-columns a b)
  (let loop ((a (string-split a "\n"))
             (a-max 0)
             (b (string-split b "\n")))
    (cond
     ((and (null? a) (null? b)) 'done)
     ((null? a)
      (display (make-string a-max #\space))
      (display #\tab)
      (display (car b))
      (newline)
      (loop '() a-max (cdr b)))
     ((null? b)
      (display (car a))
      (newline)
      (loop (cdr a)
            (if (> (string-length (car a)) a-max)
                (string-length (car a))
                a-max)
            '()))
     (else
      (display (car a))
      (display #\tab)
      (display (car b))
      (newline)
      (loop (cdr a)
            (if (> (string-length (car a)) a-max)
                (string-length (car a))
                a-max)
            (cdr b))))))

;;; Gameplay

(define (event)
  (case (roll)
    ((1 2)
     (display (prln "You head out to the garden."))
     (garden))
    ((3 4)
     (display (prln "You hear a knock at the door."))
     (door))
    ((5 6) (dangerous))))

(define (garden)
  (case (roll)
    ((1)
     (inc! potatoes)
     (prln "You happily root about all day in your garden."))
    ((2)
     (inc! potatoes)
     (inc! destiny)
     (prln "You narrowly avoid a visitor by hiding in a potato sack."))
    ((3)
     (inc! destiny)
     (inc! orcs)
     (prln "A hooded stranger lingers outside your farm."))
    ((4)
     (inc! orcs)
     (dec! potatoes)
     (prln "Your field is ravaged in the night by unseen enemies."))
    ((5)
     (dec! potatoes)
     (prln "You trade potatoes for other delicious foodstuffs."))
    ((6)
     (inc! potatoes 2)
     (prln "You burrow into a bumper crop of potatoes."
           "Do you cry with joy?  Possibly."))))

(define (door)
  (case (roll)
    ((1)
     (inc! orcs)
     (prln "It's a distant cousin.  They are after your potatoes."
           "They may snitch on you."))
    ((2)
     (inc! destiny)
     (prln "It's a dwarven stranger.  You refuse them entry."
           "Ghastly creatures."))
    ((3)
     (dec! orcs)
     (inc! destiny)
     (prln "A wizard strolls by."
           "You pointedly draw the curtains."))
    ((4)
     (dec! potatoes)
     (inc! orcs 2)
     (prln "There are rumors of war in the reaches."
           "You eat some potatoes."))
    ((5)
     (inc! destiny)
     (prln "It's an elf."
           "They are not serious people."))
    ((6)
     (inc! potatoes 2)
     (prln "It's a sack of potatoes from a generous neighbor."
           "You really must remember to to pay them a visit.."
           "one of these years."))))

(define (dangerous)
  (inc! orc-cost)
  (prln "The world has become a darker, more dangerous place."
        `("[ Removing an ORC now takes " ,orc-cost " POTATOES. ]")))

(define (game)
  (set! destiny 0)
  (set! potatoes 0)
  (set! orcs 0)
  (set! orc-cost 1)

  (clear-screen)
  (display (prln "  P O T A T O "
                 "  ~ story by @deathbybadger"
                 "  ~ game by @caseofducks"))
  (newline)

  (display (prln "You are a halfling, just trying to exist."
                 "Meanwhile, the dark lord rampages across the world."
                 "You do not care about this.  You are trying to farm potatoes."
                 "What could a halfling possibly do about it, anyway?"
                 ""
                 "Press ENTER to begin."))
  (read-char)
  (case (turns)
    ('potatoes
     (display
      (prln "You have enough potatoes to go underground until the danger is past."
            "You nestle down into your burrow and enjoy your well-earned rest.")))
    ('destiny
     (let ((interloper (if (< (pseudo-random-real) 0.5)
                           "wizard"
                           "bard")))
       (display
        (prln `("An interfering " interloper " turns up at your doorstep with a quest.")
              "You are whisked away against your will on an adventure.."
              "where you will probably be eaten by orcs."))))
    ('orcs
     (display
      (prln "Orcs have found your potato farm."
            "Alas, orcs are not so interested in potatoes as they are in halfling flesh."
            "You end up in a cookpot.")))))

(define (turns)
  (cond
   ((>= potatoes 10) 'potatoes)
   ((>= destiny 10) 'destiny)
   ((>= orcs 10) 'orcs)
   (else (clear-screen)
         (let ((desc (event)))
              (display-columns (scores) desc))
         (newline)

         (when (and (> orcs 0)
                    (>= potatoes orc-cost))
           (let ((es (if (> orc-cost 1) "ES" "")))
             (display (prln `("You can hurl " ,orc-cost " POTATO" ,es
                              " at an ORC to make them go away.")
                            `("Press H to hurl POTATO" ,es ".")))))
         (display "Press ENTER to advance.\n")

         (case (char-downcase (read-char))
          ((#\h)
           (if (and (> orcs 0)
                    (> potatoes orc-cost))
               (begin (display "The ORC runs away.")
                      (dec! potatoes orc-cost)
                      (dec! orcs))
               (display "You don't have enough POTATOES to hurl!")))
          ;; (else => (lambda (c) (display c) (newline)))
          )

         (newline)
         (read-buffered)
         (turns))))

(game)