def choose_size(self): """ After interaction with the player, this method will return the selected board size. This method uses its own UI loop. """ pygame.time.wait(300) toplay_orig = [ #memory_text.choose_begin, memory_text.choose_small.format(memory_config.size['small']), #memory_text.choose_medium.format(memory_config.size['medium']), memory_text.choose_large.format(memory_config.size['large']), #memory_text.choose_huge.format(memory_config.size['huge']), ] toplay = toplay_orig[:] while True: self.audio.do_play() # get next pygame event in queue event = pygame.event.poll() if len(toplay) > 0: self.audio.synthesize_and_play(toplay.pop(0)) if event.type == pygame.locals.QUIT: return 'terminate' if event.type == pygame.locals.KEYDOWN: # log key press keyname = pygame.key.name(event.key) liblog.log('key pressed: {}'.format(keyname)) # any key press stops audio self.audio.stop_playback() self.audio.clear_queue() # arrow keys to select size if event.key == pygame.locals.K_LEFT: return 'small' #if event.key == pygame.locals.K_UP: # return 'medium' elif event.key == pygame.locals.K_RIGHT: return 'large' #if event.key == pygame.locals.K_DOWN: # return 'huge' if event.key == pygame.locals.K_F1: self.tell_help() # escape to terminate elif event.key == pygame.locals.K_ESCAPE: return 'terminate' # everything else to repeat #event.key == pygame.locals.K_SPACE: else: toplay = toplay_orig[:]
def do_play(self): if pygame.mixer.get_busy(): return if len(self.queue) > 0: soundfile = self.queue.pop(0) liblog.log('playing sound file "{}"'.format(soundfile)) sound = pygame.mixer.Sound(soundfile) sound.play()
def change_speed(self, how, msg): minspeed = 0.6 maxspeed = 2.0 if how == 'faster': if self.speed < maxspeed: self.speed = min(self.speed + 0.2, maxspeed) else: if self.speed > minspeed: self.speed = max(self.speed - 0.2, minspeed) self.synthesize_and_play(msg) liblog.log('changed speaking rate to {:.1f}'.format(self.speed))
def run(self): self.ui.update_display() self.ui.welcome() self.ui.help() status = 'pre_game' while True: if status == 'pre_game': size = self.ui.choose_size() if size == 'terminate': liblog.log('early termination during choose_size') break self.init_game(size) status = self.logic.handle_event('begin') continue elif status == 'update': self.ui.walk() self.ui.tell_position(self.logic.curpos) self.ui.tell_options(self.logic.get_options()) elif status == 'goal': self.ui.walk() self.ui.tell_position(self.logic.curpos) self.ui.tell_goal(self.logic.numsteps) self.log_seed_vector() again = self.ui.play_again() if again == 'new': status = 'pre_game' continue elif again == 'same': status = self.logic.handle_event('begin') continue elif again == 'terminate': break elif status == 'invalid': self.ui.invalid() eventstring = self.ui.get_next_event() if eventstring == 'terminate': break elif eventstring == 'pre_game': status = eventstring continue else: status = self.logic.handle_event(eventstring) liblog.log('terminating')
def get_next_event(self): pygame.time.wait(10) self.audio.do_play() # get next pygame event in queue event = pygame.event.poll() if event.type == pygame.locals.QUIT: return 'hardterminate' if event.type == pygame.locals.KEYDOWN: # log key press keyname = pygame.key.name(event.key) if keyname == ';': keyname = '\xc3\xb6' liblog.log('key pressed: {}'.format(keyname)) # any key press stops audio self.audio.stop_playback() self.audio.clear_queue() if event.key in self.allowed_field_keys: self.lastkey = keyname return 'field_' + str(self.allowed_field_keys.index(event.key)) # space bar for repeating current position and options if event.key == pygame.locals.K_SPACE: return 'repeat' # escape for terminating if event.key == pygame.locals.K_ESCAPE: return 'terminate' if event.key == pygame.locals.K_F1: self.tell_help() return '' # F2 and F3 to change speaking rate if event.key == pygame.locals.K_F2: self.audio.change_speed('slower', memory_text.speed_slower) return '' if event.key == pygame.locals.K_F3: self.audio.change_speed('faster', memory_text.speed_faster) return '' # invalid key, play short sound self.audio.clear_queue() self.audio.priority_play('data/audio/effects/blop.wav') return ''
def handle_event(self, eventstring): if eventstring == '': return None #~ print 'eventstring: {}'.format(eventstring) if eventstring == 'begin': # put player in start node self.curpos = 0 self.prevpos = None self.numsteps = 0 self.starttime = datetime.datetime.now() return 'update' if eventstring in ('left', 'right', 'forward', 'back'): opts = self.get_options() # selected option might be invalid at current node if eventstring not in opts.keys(): return 'invalid' # otherwise, update current and position self.prevpos = self.curpos self.curpos = opts[eventstring] # increment number of taken steps self.numsteps += 1 # log player move liblog.log('player moved {:7s}: {}->{} ({} -> {})'.format( eventstring, self.prevpos, self.curpos, self.rooms[self.prevpos][0], self.rooms[self.curpos][0], )) # we might have reached the goal if self.curpos == self.goal: elapsedtime = datetime.datetime.now() - self.starttime liblog.log('goal reached after {} steps and {} seconds'.format( self.numsteps, elapsedtime.total_seconds())) return 'goal' else: return 'update'
def __init__(self, gamenum, voice): if gamenum is not None: self.gamenum = gamenum else: # try to load game self.load_game() print "Beginne mit " + str(self.gamenum) # set up logging liblog.init_logging('memory') liblog.log('game starting with game number {}'.format(self.gamenum)) # create audio processing object self.audio = libaudio.Audio(voice, 'memory') # create user interface object self.ui = memory_ui.UI(self.audio)
def log_seed_vector(self): liblog.log('-' * 54) msg = 'seed index vector (small,medium,large,huge) is ' msg += '{},{},{},{}'.format( self.seed_indices['small'], self.seed_indices['medium'], self.seed_indices['large'], self.seed_indices['huge'], ) liblog.log(msg) liblog.log('-' * 54)
def init_game(self, size): """ Initializes a new game of the specified size. """ liblog.log('initializing new game ({}) with number {}'.format(size, self.gamenum)) nextseed = memory_config.seeds[self.gamenum] random.seed(nextseed) # initialize game logic, including creation of a random board self.logic = memory_logic.GameLogic(size) # now select game theme and random objects from theme for each board field self.init_theme(self.logic.board.size) self.ui.set_num_fields(self.logic.board.size) self.logic.things = self.things liblog.log('board = {}'.format(self.logic.board.fields)) liblog.log('things = {}'.format(self.things)) liblog.log('game initialization complete')
def init_game(self, size): """ Initializes a new game of the specified size (number of rooms). """ liblog.log('initializing new game ({})'.format(size)) i = self.seed_indices[size] nextseed = labyrinth_config.seeds[size][i] random.seed(nextseed) liblog.log('seed number {} for {} size is {}'.format( i, size, nextseed)) self.seed_indices[size] += 1 # initialize game logic, including creation of a random labyrinth self.logic = labyrinth_logic.GameLogic(size) # assign random names to rooms for player interaction self.ui.shuffle_rooms() self.logic.rooms = self.ui.rooms liblog.log('game initialization complete')
def create_graph(self): """Creates a random undirected graph, the actual labyrinth The graph is represented by a (symmetrical, because the graph is undirected) incidence matrix (a numpy.ndarray), which this function returns. """ n = self.size # create empty incidence matrix graph = numpy.zeros((n, n), dtype=numpy.int8) # set a number of rooms aside, they will be added as dead ends at the # end m = n - self.dead_ends # create random tree by attaching each node to a randomly selected # earlier node which doesn't have too many neighbors yet for i in range(1, m): # potential neighbors nodes = [x for x in range(i) if sum(graph[x]) < 3] j = random.choice(nodes) graph[i, j] = 1 graph[j, i] = 1 #print graph blacklist = [] # add dead ends # all nodes whose degree is less than 4 nodes = [x for x in range(m) if sum(graph[x]) < 4 and x != 0] random.shuffle(nodes) for i in range(m, n): j = nodes.pop(0) graph[i, j] = 1 graph[j, i] = 1 blacklist.append(i) # randomly add edges, as long as no node's degree gets too large #~ blacklist = [] while True: # all nodes whose degree is less than 3 nodes = [ x for x in range(m) if sum(graph[x]) < 3 and x not in blacklist ] if len(nodes) == 0: #print 'I couldn\'t find a node with degree less than 3' break i = random.choice(nodes) #print 'I\'ll try to add an edge to node {}'.format(i) # all nodes # - except the start node # - and i itself # - whose degree is less than 4 # - and which are not already connected to i nodes = [ x for x in range(1, m) if x != i and sum(graph[x]) < 4 and graph[i, x] == 0 ] if len(nodes) == 0: #print 'I couldn\'t find one, blacklisting node {}'.format(i) blacklist.append(i) continue j = random.choice(nodes) #print 'adding edge ({},{})'.format(i, j) graph[i, j] = 1 graph[j, i] = 1 #print graph #self.draw_graph(graph) #print graph # write labyrinth info to log numedges = graph.sum() / 2 liblog.log( 'labyrinth generated. number of nodes: {} number of edges: {}'. format(n, numedges)) msg = 'labyrinth node adjacency matrix:\n' opts = numpy.get_printoptions() numpy.set_printoptions(threshold='nan') msg += numpy.array_str(graph, max_line_width=500) numpy.set_printoptions(**opts) liblog.log(msg) return graph
def get_next_event(self): pygame.time.wait(50) self.audio.do_play() # get next pygame event in queue event = pygame.event.poll() if event.type == pygame.locals.QUIT: return 'terminate' if event.type == pygame.locals.KEYDOWN: # log key press keyname = pygame.key.name(event.key) liblog.log('key pressed: {}'.format(keyname)) # any key press stops audio self.audio.stop_playback() self.audio.clear_queue() # arrow keys for moving through the labyrinth if event.key == pygame.locals.K_LEFT: return 'left' if event.key == pygame.locals.K_RIGHT: return 'right' if event.key == pygame.locals.K_UP: return 'forward' if event.key == pygame.locals.K_DOWN: return 'back' # space bar for repeating current position and options if event.key == pygame.locals.K_SPACE: self.tell_position(self.last_curpos) self.tell_options(self.last_options) return '' # escape for terminating if event.key == pygame.locals.K_ESCAPE: return 'terminate' # F2 and F3 to change speaking rate if event.key == pygame.locals.K_F2: self.audio.change_speed('faster', labyrinth_text.speed_changed) return '' if event.key == pygame.locals.K_F3: self.audio.change_speed('slower', labyrinth_text.speed_changed) return '' # F4 for aborting current labyrinth if event.key == pygame.locals.K_F4: self.audio.synthesize_and_play(labyrinth_text.abort) liblog.log('labyrinth aborted') return 'pre_game' # F1 for help if event.key == pygame.locals.K_F1: self.help() return '' # invalid key, play short sound self.audio.clear_queue() self.audio.priority_play('data/audio/effects/blop.wav') return ''
def play_again(self): """ After completing one game, asks the player if she wants to play again. If yes, go to choose size. If no, terminate. Like choose_size, this uses its own UI loop """ toplay_orig = [ labyrinth_text.left_play_again, labyrinth_text.right_play_same_again, labyrinth_text.escape_terminate ] toplay = toplay_orig[:] while True: self.audio.do_play() if len(toplay) > 0: self.audio.synthesize_and_play(toplay.pop(0)) # get next pygame event in queue event = pygame.event.poll() if event.type == pygame.locals.QUIT: return 'terminate' if event.type == pygame.locals.KEYDOWN: # log key press keyname = pygame.key.name(event.key) liblog.log('key pressed: {}'.format(keyname)) # any key press stops audio self.audio.stop_playback() self.audio.clear_queue() # arrow keys to select new game, same game or quit if event.key == pygame.locals.K_LEFT: return 'new' if event.key == pygame.locals.K_RIGHT: liblog.log('restarting same labyrinth') return 'same' # space bar to repeat options if event.key == pygame.locals.K_SPACE: toplay = toplay_orig[:] continue # escape to terminate if event.key == pygame.locals.K_ESCAPE: return 'terminate' # F2 and F3 to change speaking rate if event.key == pygame.locals.K_F2: self.audio.change_speed('slower', labyrinth_text.speed_changed) continue if event.key == pygame.locals.K_F3: self.audio.change_speed('faster', labyrinth_text.speed_changed) continue # F1 for help if event.key == pygame.locals.K_F1: self.help() continue # unknown key self.audio.play_sound_file('data/audio/effects/blop.wav')
def choose_size(self): """ After interaction with the player, this method will return the selected labyrinth size. This method uses its own UI loop. """ pygame.time.wait(500) toplay_orig = [ labyrinth_text.choose_size_begin, labyrinth_text.choose_size.format( labyrinth_text.sizes['small'][0], labyrinth_text.sizes['small'][1], labyrinth_config.size['small'] ), labyrinth_text.choose_size.format( labyrinth_text.sizes['medium'][0], labyrinth_text.sizes['medium'][1], labyrinth_config.size['medium'] ), labyrinth_text.choose_size.format( labyrinth_text.sizes['large'][0], labyrinth_text.sizes['large'][1], labyrinth_config.size['large'] ), labyrinth_text.choose_size.format( labyrinth_text.sizes['huge'][0], labyrinth_text.sizes['huge'][1], labyrinth_config.size['huge'] ), ] toplay = toplay_orig[:] while True: self.audio.do_play() # get next pygame event in queue event = pygame.event.poll() if len(toplay) > 0: self.audio.synthesize_and_play(toplay.pop(0)) if event.type == pygame.locals.QUIT: return 'terminate' if event.type == pygame.locals.KEYDOWN: # log key press keyname = pygame.key.name(event.key) liblog.log('key pressed: {}'.format(keyname)) # any key press stops audio self.audio.stop_playback() self.audio.clear_queue() # arrow keys to select size if event.key == pygame.locals.K_LEFT: self.audio.synthesize_and_play( labyrinth_text.selected_size.format( labyrinth_text.sizes['small'][1])) return 'small' if event.key == pygame.locals.K_UP: self.audio.synthesize_and_play( labyrinth_text.selected_size.format( labyrinth_text.sizes['medium'][1])) return 'medium' if event.key == pygame.locals.K_RIGHT: self.audio.synthesize_and_play( labyrinth_text.selected_size.format( labyrinth_text.sizes['large'][1])) return 'large' if event.key == pygame.locals.K_DOWN: self.audio.synthesize_and_play( labyrinth_text.selected_size.format( labyrinth_text.sizes['huge'][1])) return 'huge' # space bar to repeat options if event.key == pygame.locals.K_SPACE: toplay = toplay_orig[:] # escape to terminate if event.key == pygame.locals.K_ESCAPE: return 'terminate' # F2 and F3 to change speaking rate if event.key == pygame.locals.K_F2: self.audio.change_speed('slower', labyrinth_text.speed_changed) continue if event.key == pygame.locals.K_F3: self.audio.change_speed('faster', labyrinth_text.speed_changed) continue # F1 for help if event.key == pygame.locals.K_F1: self.help() continue
def run(self): self.ui.update_display() self.ui.welcome() self.ui.tell_round(self.gamenum+1) size = self.choose_size() if size == 'terminate': liblog.log('early termination during choose_size') return self.init_game(size) self.ui.tell_size(size) self.ui.tell_theme(self.themeidx) laststatus = status = self.logic.handle_event('begin') while not self.logic.terminate: # user has to select field 1 if status == 'select1': # tell user which field she selected as #2 if self.logic.current_thing is not None: self.ui.tell_thing_selected( self.things[ self.logic.current_thing - 1 ] ) # tell user if both fields matched if self.logic.last_correct is not None: self.ui.tell_correct( self.logic.last_correct ) # tell user to selected a #1 field self.ui.tell_select_field( 1 ) # user has to select field 2 elif status == 'select2': # tell user the field #1 she selected if self.logic.current_thing is not None: self.ui.tell_thing_selected( self.things[ self.logic.current_thing - 1 ] ) # sell user to select field #2 self.ui.tell_select_field( 2 ) elif status == 'wrongfield': self.ui.tell_wrongfield() elif status == 'finished': self.ui.tell_thing_selected( self.things[ self.logic.current_thing - 1 ] ) # all games done? #if self.gamenum == 7: self.ui.tell_goal_all8(self.logic.numsteps) self.ui.tell_goal(self.logic.numsteps) self.gamenum += 1 self.save_game() self.ui.tell_round(self.gamenum+1) size = self.choose_size() if size == 'terminate': break else: self.init_game(size) self.ui.tell_size(size) self.ui.tell_theme( self.themeidx ) status = self.logic.handle_event('begin') pygame.event.clear() continue eventstring = self.ui.get_next_event() # repeat last status if eventstring == 'repeat': status = laststatus continue # don't allow quitting too early ;) #if eventstring == 'terminate' and self.gamenum < 8: # eventstring = '' status = self.logic.handle_event(eventstring) # save last status message if status is not None and status is not "wrongfield": laststatus = status liblog.log('terminating')
def handle_event(self, eventstring): if eventstring == '': return None #print 'eventstring: {}'.format(eventstring) if eventstring == 'terminate': self.terminate = True return None if eventstring == 'hardterminate': self.terminate = True return None # get started if eventstring == 'begin': self.current_state = self.States.SELECT_1 self.field1 = None self.field2 = None self.current_thing = None self.last_correct = None self.starttime = datetime.datetime.now() self.numsteps = 0 return 'select1' # user selected a field if eventstring.startswith("field_"): fieldsel = int(eventstring[6:]) if self.board.fields[fieldsel] < 1 or fieldsel == self.field1: liblog.log( 'user selected field {} which is already finished.'.format( fieldsel)) return 'wrongfield' # user selected the first field if self.current_state == self.States.SELECT_1: liblog.log('user selected field1: {} ({}).'.format( fieldsel, self.things[self.board.fields[fieldsel] - 1])) self.field1 = fieldsel self.current_thing = self.board.fields[fieldsel] self.current_state = self.States.SELECT_2 return 'select2' # user selected the second field if self.current_state == self.States.SELECT_2: liblog.log('user selected field2: {} ({}).'.format( fieldsel, self.things[self.board.fields[fieldsel] - 1])) self.field2 = fieldsel self.current_thing = self.board.fields[fieldsel] self.numsteps += 1 # see if fields match if self.board.fields[self.field1] == self.board.fields[ self.field2]: liblog.log( 'user was correct with field1: {} ({}) and field2: {} ({}).' .format( self.field1, self.things[self.board.fields[self.field1] - 1], self.field2, self.things[self.board.fields[self.field2] - 1])) self.board.fields[self.field1] = self.board.fields[ self.field2] = 0 self.last_correct = True if sum(self.board.fields) == 0: elapsedtime = datetime.datetime.now() - self.starttime liblog.log( 'goal reached after {} steps and {} seconds'. format(self.numsteps, elapsedtime.total_seconds())) self.current_state = self.States.FINISH return 'finished' else: liblog.log( 'user was wrong with field1: {} ({}) and field2: {} ({}).' .format( self.field1, self.things[self.board.fields[self.field1] - 1], self.field2, self.things[self.board.fields[self.field2] - 1])) self.last_correct = False self.field1 = None self.field2 = None self.current_state = self.States.SELECT_1 return 'select1' return None