class Tree: def __init__( self, tree_type="pro", delay=0.4, left_lane="computer", right_lane="human", debug=False, perfect=0.0, left_rollout=0.220, right_rollout=0.220, stats=False, amin=1.0, amax=3.0, cmin=-0.009, cmax=0.115, auto_reset=False, res="480x700", fullscreen=False, hw=False, doublebuf=False, ): self.perfect = perfect self.left_rollout = left_rollout self.right_rollout = right_rollout self.amin = amin self.amax = amax self.auto_reset = auto_reset self.two_player = left_lane == "human" and right_lane == "human" self.debug = debug self.stats = stats self.delay = delay self.start = threading.Event() self.staged = threading.Event() self.quitting = threading.Event() self.tree_type = tree_type self.tie = [] self.start_time = None self.clock = pygame.time.Clock() flags = 0 if hw: flags = flags | pygame.HWSURFACE if doublebuf: flags = flags | pygame.DOUBLEBUF if fullscreen: resolution = (0, 0) flags = flags | pygame.FULLSCREEN pygame.mouse.set_visible(False) else: width, height = res.split("x") resolution = (int(width), int(height)) self.screen = pygame.display.set_mode(resolution, flags) self.scale() self.left_lane = Lane( tree_type=tree_type, delay=delay, start=self.start, lane="left", computer=(left_lane == "computer"), perfect=perfect, rollout=left_rollout, cmin=cmin, cmax=cmax, surface=self.screen.subsurface( pygame.Rect(self.rect.left, self.tree_rect.top, self.rect.centerx, self.tree_rect.height) ), background=self.background, ) self.right_lane = Lane( tree_type=tree_type, delay=delay, start=self.start, lane="right", computer=(right_lane == "computer"), perfect=perfect, rollout=right_rollout, cmin=cmin, cmax=cmax, surface=self.screen.subsurface( pygame.Rect(self.rect.centerx, self.tree_rect.top, self.rect.centerx, self.tree_rect.height) ), background=self.background, ) self.lanes = {"left": self.left_lane, "right": self.right_lane} if self.two_player: self.human = None elif right_lane == "human": self.human = self.right_lane elif left_lane == "human": self.human = self.left_lane else: self.human = self.left_lane if self.debug: self.font = pygame.font.Font("assets/font.ttf", 50) self.fps = self.font.render("", 1, (255, 255, 255)) clock = threading.Thread(None, self._clock, name="clock()") # monitor = threading.Thread(None, self.thread_monitor, # name="thread_monitor()") clock.start() # monitor.start() self.reset() self.event_loop() clock.join() # monitor.join() def scale(self): self.rect = self.screen.get_rect() background = pygame.image.load("assets/background.png") background.convert() # background = utils.load_background() background_rect = background.get_rect() if float(self.rect.width) / float(self.rect.height) <= 1.6: background = pygame.transform.smoothscale( background, (int(round(self.rect.height * 1.6, 0)), self.rect.height) ) else: background = pygame.transform.smoothscale( background, (self.rect.width, int(round(self.rect.width / 1.6, 0))) ) background_rect = background.get_rect() temp_rect = self.rect.move(0, 0) temp_rect.centerx = background_rect.centerx temp_rect.centery = background_rect.centery self.background = background.subsurface(temp_rect) # self.vignette = utils.load_vignette() self.vignette = pygame.image.load("assets/vignette.png") self.vignette.convert_alpha() self.vignette = pygame.transform.smoothscale(self.vignette, (self.rect.width, self.rect.height)) self.tree = pygame.image.load("assets/tree.png") self.tree.convert_alpha() self.tree_rect = self.tree.get_rect() self.tree_rect = self.tree_rect.fit(self.rect) self.tree = pygame.transform.smoothscale(self.tree, (self.tree_rect.width, self.tree_rect.height)) self.tree_rect.midbottom = self.rect.midbottom self.background.blit(self.vignette, (0, 0)) self.background.blit(self.tree, (self.tree_rect.left, 0)) self.screen.blit(self.background, (0, 0)) pygame.display.flip() def reset(self): self.tie = [] self.start_time = None self.start.clear() self.staged.clear() for lane in self.lanes.values(): lane.reset() if self.quitting.is_set(): return threading.Thread(None, self.staging, name="staging()").start() def staging(self): while not self.quitting.is_set() and not (self.left_lane.staged.is_set() and self.right_lane.staged.is_set()): time.sleep(0.001) if self.quitting.is_set(): return # The following line sets the window for the randomized delay between # both lanes having fully staged and the race starting. if self.amin == self.amax: autostart = self.amin else: autostart = random.randrange(self.amin * 1000.0, self.amax * 1000.0, 1) / 1000.0 self.start_time = time.time() + autostart if self.left_lane.staged.is_set() and self.right_lane.staged.is_set(): self.staged.set() else: self.reset() return while ( time.time() < self.start_time - 0.1 and self.left_lane.staged.is_set() and self.right_lane.staged.is_set() ): time.sleep(0.001) if self.left_lane.staged.is_set() and self.right_lane.staged.is_set(): threading.Thread(None, self.race, name="race()").start() else: self.reset() return def timer(self): left = threading.Thread(None, self.left_lane.timer, name="Left Lane timer()") right = threading.Thread(None, self.right_lane.timer, name="Right Lane timer()") if self.tree_type == "sportsman": green_time = self.start_time + (3 * self.delay) else: green_time = self.start_time + self.delay y2time = self.start_time + self.delay y3time = self.start_time + (self.delay * 2) left.start() right.start() self.start.set() while time.time() < self.start_time: continue self.left_lane.y1.set() self.right_lane.y1.set() if self.tree_type == "sportsman": while time.time() < y2time: continue self.left_lane.y2.set() self.right_lane.y2.set() while time.time() < y3time: continue self.left_lane.y3.set() self.right_lane.y3.set() while time.time() < green_time: continue self.left_lane.g.set() self.right_lane.g.set() self.left_lane.launched.wait() self.right_lane.launched.wait() left.join() right.join() def race(self): self.left_lane.start_time = self.right_lane.start_time = self.start_time self.timer() time.sleep(0.1) self.start_time = None # print "Left start time: %0.7f" % self.left_lane.start_time # print "Right start time: %0.7f" % self.right_lane.start_time if self.two_player: if self.tie[0].foul.is_set(): self.tie[1].win() else: self.tie[0].win() elif self.left_lane.reaction < self.right_lane.reaction: if self.left_lane.foul.is_set(): if self.right_lane.foul.is_set(): self.right_lane.win() # print "Winner: Right Lane RT %0.3f (foul)" % self.right_lane.reaction # print "Loser: Left Lane RT %0.3f (foul)" % self.left_lane.reaction self.right_lane.win() # print "Winner: Right Lane RT %0.3f" % self.right_lane.reaction # print "Loser: Left Lane RT %0.3f (foul)" % self.left_lane.reaction else: self.left_lane.win() # print "Winner: Left Lane RT %0.3f" % self.left_lane.reaction # print "Loser: Right Lane RT %0.3f" % self.right_lane.reaction elif self.right_lane.reaction < self.left_lane.reaction: if self.right_lane.foul.is_set(): if self.left_lane.foul.is_set(): self.left_lane.win() # print "Winner: Left Lane RT %0.3f (foul)" % self.left_lane.reaction # print "Loser: Right Lane RT %0.3f (foul)" % self.right_lane.reaction self.left_lane.win() # print "Winner: Left Lane RT %0.3f" % self.left_lane.reaction # print "Loser: Right Lane RT %0.3f (foul)" % self.right_lane.reaction else: self.right_lane.win() # print "Winner: Right Lane RT %0.3f" % self.right_lane.reaction # print "Loser: Left Lane RT %0.3f" % self.left_lane.reaction elif self.left_lane.reaction == self.right_lane.reaction: for lane in self.lanes.values(): lane.win() if self.stats: print "Round %d: Left Lane: %0.3f\tRight Lane: %0.3f" % ( len(self.left_lane.log), self.left_lane.reaction, self.right_lane.reaction, ) if self.auto_reset: reset = time.time() + self.auto_reset while time.time() < reset: if self.quitting.is_set(): return self.reset() def win(self, lane): print "win lane %s" % lane self.lanes[lane].win() def event_loop(self): pygame.event.set_allowed(None) pygame.event.set_allowed([KEYDOWN, KEYUP, QUIT]) while not self.quitting.is_set(): event = pygame.event.wait() if event.type == KEYDOWN and event.key in [K_m, K_z, K_SPACE]: if self.two_player: if not (self.right_lane.pre_staged.is_set() or self.left_lane.pre_staged.is_set()): if not self.auto_reset: self.reset() elif event.key == K_m and self.right_lane.pre_staged.is_set(): self.right_lane.stage() elif event.key == K_z and self.left_lane.pre_staged.is_set(): self.left_lane.stage() elif event.key == K_SPACE: if self.human.pre_staged.is_set(): self.human.stage() # while pygame.key.get_pressed()[K_SPACE]: # pygame.event.pump() # if self.human.staged.is_set() and self.start.is_set(): # self.human.launched_time = time.time() # self.human.launched.set() # else: # self.human.staged.clear() # self.human.lights[1].off() elif not self.auto_reset: self.reset() elif event.type == KEYUP and event.key in [K_m, K_z, K_SPACE]: if self.two_player: if event.key == K_m: if self.right_lane.staged.is_set() and self.start.is_set(): self.right_lane.launched_time = time.time() self.right_lane.launched.set() self.tie.append(self.right_lane) else: self.right_lane.staged.clear() self.right_lane.lights[1].off() elif event.key == K_z: if self.left_lane.staged.is_set() and self.start.is_set(): self.left_lane.launched_time = time.time() self.left_lane.launched.set() self.tie.append(self.left_lane) else: self.left_lane.staged.clear() self.left_lane.lights[1].off() elif event.key == K_SPACE: if self.human.staged.is_set() and self.start.is_set(): self.human.launched_time = time.time() self.human.launched.set() else: self.human.staged.clear() self.human.lights[1].off() elif event.type == pygame.QUIT or (event.type == KEYDOWN and event.key in [K_ESCAPE, K_q]): self.quit() # print event def draw(self): self.left_lane.draw() self.right_lane.draw() dirty = [] if self.left_lane.dirty: dirty += self.left_lane.dirty_rects self.left_lane.dirty = False self.left_lane.dirty_rects = [] if self.right_lane.dirty: dirty += self.right_lane.dirty_rects self.right_lane.dirty = False self.right_lane.dirty_rects = [] if self.debug: self.fps = self.font.render("%0.1f" % self.clock.get_fps(), 1, (255, 255, 255)) fps_rect = self.fps.get_rect() fps_rect.top = 10 fps_rect.left = 10 self.screen.blit(self.background, (fps_rect.left, fps_rect.top), fps_rect) self.screen.blit(self.fps, (fps_rect.left, fps_rect.top)) dirty.append(fps_rect) if dirty: pygame.display.update(dirty) def _clock(self): while not self.quitting.is_set(): self.clock.tick() self.draw() def thread_monitor(self): if not self.debug: return last_count = 0 while not self.quitting.is_set(): if threading.active_count() == last_count: continue else: last_count = threading.active_count() print "\nActive threads:" for thread in sorted(threading.enumerate(), key=threading.Thread.getName): print " " + thread.name def print_stats(self): for lane in self.lanes.values(): if lane.log: print lane.lane, "stats:" best = None worst = None for react in lane.log: if not best and not worst: worst = best = react if react < best and react >= self.delay: best = react if react > best and best < self.delay: best = react if react > worst: worst = react print "\tBest: %0.3f" % best print "\tWorst: %0.3f" % worst print "\tAverage: %0.3f" % round(sum(lane.log) / len(lane.log), 3) def quit(self): self.quitting.set() self.reset() if self.stats: self.print_stats() pygame.quit()