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
|
(def HOME "/home/")
(def PORCH "/porch/")
(def BOWL "/porch/bowl/")
(def USER (first ($ "whoami")))
(def NAME "simon")
(def PRONOUN "he")
(def CAT "
|\ _,,,---,,_
/,`.-'`' -. ;-;;,_
|,4- ) )-,_..;\ ( `'-'
'---''(_/--' `-'\_)
")
; get a user from their /home/*/* path
(func user-from-path (inp)
(first (rest (rest (split inp "/")))))
; get all users who have a "porch"
(func get-porches ()
(map user-from-path (glob (concat HOME "*" PORCH))))
; add " * " to the beginning of the string
(func concat-star (inp)
(concat " * " inp))
; pretty-print all porches
(func print-porches ()
(print "Neighborhood porches")
(map print (map concat-star (get-porches))))
; get all eats available on a given porch
(func get-eats (porch)
(glob (concat HOME porch BOWL "*")))
; get all eats on all porches
(func get-porches-with-eats ()
(map get-eats (get-porches)))
; find the cat
(func locate-cat ()
(glob (concat HOME "*" PORCH NAME)))
(func locate ()
(def porch (locate-cat))
(if (empty? porch)
(print (concat "hmm, " PRONOUN "must have wandered off. maybe you should leave some food?"))
(print (concat "last I saw " NAME ", " PRONOUN " was on " (user-from-path (first porch)) "'s porch"))))
(func get-random-eats ()
; expected format ((porch1/eat1 porch1/eat2) (porch2/eat1)...)
(safe-first
(shuf
(safe-first
(shuf (get-porches-with-eats))))))
; prevent a panic on (first ())
(func safe-first (inp)
(if (empty? inp)
(list)
(first inp)))
(func wander ()
(print (concat "off " PRONOUN " goes!"))
(def current-location (locate-cat))
(if (not (empty? current-location))
(unlink (first current-location)))
; if there's no eats, exit
(def target-eats (get-random-eats))
(if (and (list? target-eats) (empty? target-eats)) (exit))
; eat the food
(unlink target-eats)
; go to the porch
(def target-eats-stem (last (split target-eats "/")))
(def target-porch (user-from-path target-eats))
(def cat-file (open-write (concat HOME target-porch PORCH NAME)))
(write CAT cat-file)
(write (concat "thank you for the " target-eats-stem "!\n") cat-file)
(close cat-file))
(func init ()
; create the new porch and bowl
(def new_porch (concat HOME USER PORCH))
(if (not (exists? new_porch))
($ (concat "mkdir -m 777 " new_porch)))
(def new_bowl (concat HOME USER BOWL))
(if (not (exists? new_bowl))
($ (concat "mkdir -m 777 " new_bowl)))
; get rid of the old stuff, if applicable
; TODO
;(def old_bowl (concat HOME USER "/.bowl"))
;(if (exists? old_bowl)
; ($ (concat "mv " old_bowl "/* " new_bowl)))
(print "You're all set up!"))
(func feed (food)
(if (not (eq? (list-length food) 1))
(block
(print "usage: feed <food>")
(exit 1)))
(if (not (exists? (concat HOME USER BOWL)))
(block
(print "you've got no bowl to put food in! try 'init' first")
(exit)))
(def foodfile (concat HOME USER BOWL "/" (first food)))
(if (exists? foodfile)
(block
(print (concat "you already have " (first food) " in your bowl!"))
(exit)))
(close (open-write (concat HOME USER BOWL "/" (first food))))
(print (concat "you left some " (first food) " for " NAME "!")))
(func help ()
(print "neighborcat -- a neighborhood cat")
(print " -> 'init' : initialize your porch")
(print " -> 'locate' : locate the neighborcat")
(print " -> 'feed <food>' : locate the neighborcat")
(print " -> 'wander' : send the cat a-wandering"))
(func main (args)
(branch
((empty? args) (print-porches))
((eq? "init" (first args)) (init))
((eq? "help" (first args)) (help))
((eq? "wander" (first args)) (wander))
((eq? "locate" (first args)) (locate))
((eq? "feed" (first args)) (feed (rest args)))
(#true
(print (concat "unknown argument: " (first args))))))
(main (rest (argv)))
|