Add entrypoint to setup.py for vendserver
[uccvend-vendserver.git] / VendServer / Idler.py
1 #!/usr/bin/env python
2
3 import string, time, os
4 from subprocess import Popen, PIPE
5 from random import random
6 from MessageKeeper import MessageKeeper
7
8 orderings = None
9
10 IDLER_TEXT_SPEED=1.8
11
12 class Idler:
13         def __init__(self, v, affinity=None):
14                 self.v = v
15                 if affinity:
16                         self._affinity = affinity
17                 else:
18                         self._affinity = 1
19
20         def next(self):
21                 """Displays next stage of the idler. Returns time to the next step"""
22                 return 1
23
24         def reset(self):
25                 """Resets the idler to a known intial state"""
26                 pass
27         
28         def finished(self):
29                 """Returns True if the idler is considered finished"""
30                 return False
31
32         def affinity(self):
33                 """How much we want this idler to be the next one chosen"""
34                 return self._affinity
35
36 class GreetingIdler(Idler):
37         def __init__(self, v, secs_to_greeting = None):
38                 affinity = 0 
39                 Idler.__init__(self, v, affinity = affinity)
40                 self.secs_to_greeting = secs_to_greeting
41                 self.message_displayed = False
42
43         def next(self):
44                 if not self.secs_to_greeting is None:
45                         x = self.secs_to_greeting
46                         self.secs_to_greeting = None
47                         return x
48
49                 self.v.display('UCC SNACKS')
50                 self.message_displayed = True
51                 return 5
52
53         def reset(self):
54                 self.message_displayed = False
55                 self.secs_to_greeting = None
56
57         def finished(self):
58                 return self.message_displayed
59
60 class TrainIdler(Idler):
61         def __init__(self, v):
62                 Idler.__init__(self, v)
63                 self.idle_state = 0
64
65         def put_shark(self, s, l):
66                 if self.s[l] == ' ':
67                         self.s[l] = s
68                 elif self.s[l] == 'X':
69                         self.s[l] = '*'
70                 else:
71                         self.s[l] = 'X'
72
73         def next(self):
74                 # does the next stage of a dance
75                 self.s = [' ']*10
76                 shark1 = self.idle_state % 18
77                 if shark1 < 9:
78                         self.put_shark('^', shark1)
79                 else:
80                         self.put_shark('^', 18-shark1)
81
82                 shark2 = ((self.idle_state+4) % 36)/2
83                 if shark2 < 9:
84                         self.put_shark('<', shark2)
85                 else:
86                         self.put_shark('<', 18-shark2)
87
88                 shark3 = ((self.idle_state+7) % 54)/3
89                 if shark3 < 9:
90                         self.put_shark('>', 9-shark3)
91                 else:
92                         self.put_shark('>', 9-(18-shark3))
93
94                 train1 = ((self.idle_state%(18*36)))
95                 train1_start = 122
96                 if train1 > train1_start and train1 < train1_start+(10*2):
97                         for i in range(5):
98                                 ptr = i+train1-train1_start-5
99                                 if ptr >= 0 and ptr < 10: self.s[ptr] = '#'
100
101                 train2 = ((self.idle_state%(18*36)))
102                 train2_start = 400
103                 if train2 > train2_start and train2 < train2_start+(10*2):
104                         for i in range(5):
105                                 ptr = i+train2-train2_start-5
106                                 if ptr >= 0 and ptr < 10: self.s[9-ptr] = '#'
107
108                 train3 = ((self.idle_state%(18*36)))
109                 train3_start = 230
110                 if train3 > train3_start and train3 < train3_start+(10*2):
111                         for i in range(10):
112                                 ptr = i+train3-train3_start-10
113                                 if ptr >= 0 and ptr < 10: self.s[ptr] = '-'
114
115                 self.v.display(string.join(self.s, ''))
116                 self.idle_state += 1
117                 self.idle_state %= 18*36*54
118
119         def reset(self):
120                 self.idle_state = 0
121
122 class OrderMaker:
123         def __init__(self, n=8):
124                 self.n = n
125                 self.make_factorials(n)
126         
127         def make_factorials(self, n):
128                 self.factorial = []
129                 a = 1
130                 for i in range(1,n+1):
131                         self.factorial.append(a)
132                         a *= i
133
134         def order(self, index):
135                 used = []
136                 for i in range(0,self.n):
137                         used.append(i)
138                 i = self.n-1
139                 j = 0
140                 res = []
141                 while i >= 0:
142                         a = index/self.factorial[i]
143                         index %= self.factorial[i]
144                         res.append(a+1)
145                         i -= 1
146                         j += 1
147                 for i in range(0,self.n):
148                         tmp = used[res[i]-1]
149                         for j in range(res[i],self.n):
150                                 used[j-1] = used[j]
151                         res[i] = tmp
152                 return res
153
154         def __getitem__(self, i):
155                 return self.order(i)
156
157 class GrayIdler(Idler):
158         def __init__(self, v, one=None, zero=None, reorder=0):
159                 Idler.__init__(self, v)
160                 self.bits = 8
161                 self.size = 1 << self.bits
162                 self.i = 0
163                 self.grayCode = 0
164                 self.one = one
165                 self.zero = zero
166                 self.reorder = reorder
167                 global orderings
168                 if not orderings:
169                         orderings = OrderMaker()
170
171         def next(self):
172                 output = self.do_next_state()
173                 # does the next stage of a dance
174                 if self.zero:
175                         output = string.replace(output, "0", self.zero)
176                 if self.one:
177                         output = string.replace(output, "1", self.one)
178                 if self.reorder:
179                         global orderings
180                         newoutput = ""
181                         for i in range(0,8):
182                                 newoutput += output[orderings[self.reorder][i]]
183                         output = newoutput
184                 self.v.display(" %8.8s " % (output))
185                 self.i = (self.i + 1) % self.size
186
187         def do_next_state(self):
188                 self.grayCode = self.i ^ (self.i >> 1)
189                 output = self.dec2bin(self.grayCode)
190
191                 return "0"*(self.bits-len(output))+output
192
193
194         def dec2bin(self,num):
195             """Convert long/integer number to binary string.
196
197             E.g. dec2bin(12) ==> '1100'.
198             
199             from http://starship.python.net/~gherman/playground/decbingray/decbingray.py"""
200
201             assert num >= 0, "Decimal number must be >= 0!"
202
203             # Gracefully handle degenerate case.
204             # (Not really needed, but anyway.)    
205             if num == 0:
206                 return '0'
207
208             # Find highest value bit.
209             val, j = 1L, 1L
210             while val < num:
211                 val, j = val*2L, j+1L
212
213             # Convert.
214             bin = '' 
215             i = j - 1
216             while i + 1L:
217                 k = pow(2L, i)
218                 if num >= k:
219                     bin = bin + '1'
220                     num = num - k
221                 else:
222                     if len(bin) > 0:
223                         bin = bin + '0'
224                 i = i - 1L
225
226             return bin
227
228         def reset(self):
229                 self.i = 0
230                 self.grayCode = 0
231                 if self.reorder:
232                         self.reorder = int(random()*40319)+1
233
234
235 class StringIdler(Idler):
236         def __init__(self, v, text="Hello Cruel World!  ",repeat=True, affinity=None):
237                 Idler.__init__(self, v, affinity=affinity)
238                 self.mk = MessageKeeper(v)
239                 self.text = "         " + self.clean_text(text) + "          "
240                 
241                 msg = [("",False, None),(self.text, repeat, IDLER_TEXT_SPEED)]
242                 self.mk.set_messages(msg)
243
244         def clean_text(self, text):
245                 # nothing like a bit of good clean text :)
246                 valid = string.digits \
247                         + string.letters \
248                         + string.punctuation \
249                         + " "
250                 # uppercase it
251                 text = string.upper(text)
252                 clean = ""
253                 for char in text:
254                         if char in valid:
255                                 clean = clean + char
256                         else:
257                                 clean = clean + " "
258                 return clean
259
260         def next(self):
261                 self.mk.update_display()
262
263         def finished(self):     
264                 return self.mk.done()
265
266 class ClockIdler(Idler):
267         def __init__(self, v):
268                 affinity = 3 
269                 Idler.__init__(self, v, affinity = affinity)
270                 self.last = None
271
272         def next(self):
273                 colonchar = ':'
274                 if int(time.time()*2) & 1: colonchar = ' '
275                 output = time.strftime("%%H%c%%M%c%%S"%(colonchar,colonchar))
276                 if output != self.last:
277                         self.v.display(" %8.8s " % (output))
278                         self.last = output
279
280 class FortuneIdler(StringIdler):
281         def __init__(self, v, affinity = 30):
282                 fortune = "/usr/games/fortune"
283                 text = "I broke my wookie...."
284                 if os.access(fortune,os.F_OK|os.X_OK):
285                         (lines, unused) = Popen((fortune,), close_fds=True, stdout=PIPE).communicate()
286                         text = lines.replace('\n', '  ').replace('\r', '')
287                 StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
288
289         def reset(self):
290                 self.__init__(self.v, affinity=self._affinity)
291
292
293 class PipeIdler(StringIdler):
294         def __init__(self, v, command, args, affinity = 5):
295                 text = "I ate my cookie...."
296                 if os.access(command,os.F_OK|os.X_OK):
297                         (lines, unused) = Popen([command,] + args.split(), close_fds=True, stdout=PIPE).communicate()
298                         text = lines.replace('\n', '  ').replace('\r', '')
299                 StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
300
301 class FileIdler(StringIdler):
302         def __init__(self, v, thefile=None, repeat=False, affinity=8):
303                 text = "I broke my wookie...."
304
305                 if file and os.access(thefile,os.F_OK|os.R_OK):
306                         f = file(thefile,'r')
307                         text = string.join(f.readlines())
308                         f.close()
309                 StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)

UCC git Repository :: git.ucc.asn.au