-
Notifications
You must be signed in to change notification settings - Fork 1
/
repl.py
135 lines (101 loc) · 3.92 KB
/
repl.py
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
"""REPL Module
Used for visualising a single game.
For testing and debugging.
"""
import curses
import datetime
import time
import numpy
from game import last_royal, is_winner
from game_runner import GameRunner
from format import format_game
class Repl:
PAD_HEIGHT = 30
PAD_WIDTH = 100
IDEAL_FPS = 30
stdscr = None
contents_pad = None
fps = 0
game_runner = None
key_bindings = {
'n': lambda self: (self.game_runner.step(), self.latest_history()),
'r': lambda self: self.reset(),
'p': lambda self: (self.game_runner.play(), self.latest_history()),
'.': lambda self: self.next_in_history(),
',': lambda self: self.prev_in_history(),
}
monitors = {
'Last Royal': lambda self: last_royal(self.game_runner.history[self.history_pos]),
'Counter': lambda self: str(self.game_runner.count),
'Position in History': lambda self: str(self.history_pos),
'Frames per second': lambda self: str(self.fps),
'Winner': lambda self: self.game_runner.history[self.history_pos].winner,
# 'Time': lambda _: str(datetime.datetime.time(datetime.datetime.now()))
}
def __init__(self, stdscr):
self.contents_pad = curses.newpad(self.PAD_HEIGHT, self.PAD_WIDTH)
self.refresh_pad()
self.game_runner = GameRunner()
self.history_pos = 0
self.stdscr = stdscr
self.stdscr.nodelay(True)
self.run()
def reset(self):
self.game_runner = GameRunner()
self.history_pos = self.game_runner.count
def next_in_history(self):
self.history_pos = min(self.history_pos + 1, self.game_runner.count)
def prev_in_history(self):
self.history_pos = max(self.history_pos - 1, 0)
def latest_history(self):
self.history_pos = self.game_runner.count
def get_monitor_lines(self):
return [(str(desc) + ": " + str(val(self))) for (desc, val) in self.monitors.items()]
def refresh_pad(self):
self.contents_pad.noutrefresh(0, 0, 1, 1, self.PAD_HEIGHT, self.PAD_WIDTH)
def render(self, help_lines, game_lines, monitor_lines):
"""Takes lines of different sections and puts them onto pads on the screen."""
lines = []
lines = lines + ["Egyptian Rafter Simulator"]
lines = lines + ["-------------------------"]
lines = lines + [""]
lines = lines + game_lines
lines = lines + [""]
lines = lines + [""]
lines = lines + monitor_lines
lines = lines + [""]
lines = lines + help_lines
self.contents_pad.erase()
self.contents_pad.addstr(0, 0, '\n'.join(lines))
self.refresh_pad()
curses.doupdate()
def run(self):
last_frame = datetime.datetime.now()
self.last5_fps = [0 for i in range(0, 200)]
# (More like prel)
while True:
# Make sure my loops aren't running too fast
# This works but not accurately
self.fps = numpy.mean(self.last5_fps)
delta = max(1/self.IDEAL_FPS - 1/self.fps, 0.0)
# Sleep is not sleeping enough?
time.sleep(delta)
help_lines = ['Press a key: Reset (r), Next (n), Quit (q), Play(p)']
game_lines = format_game(self.game_runner.history[self.history_pos])
monitor_lines = self.get_monitor_lines()
self.render(help_lines, game_lines, monitor_lines)
try:
k = self.stdscr.getkey()
if (k == 'q'):
break
try:
self.key_bindings[k](self)
except KeyError:
pass
except curses.error:
pass
self.last5_fps.append(1 / (datetime.datetime.now() - last_frame).total_seconds())
self.last5_fps.pop(0)
last_frame = datetime.datetime.now()
if __name__ == "__main__":
repl = curses.wrapper(Repl)