def main(argv): source = ' '.join(argv[1:]).lower() global dictionary, dictionary_prefixes dictionary, dictionary_prefixes = load(dict_filename, source) with sturm.cbreak_mode(): sturm.render('Collecting words...') run(collect_words(source))
def play(grids, name='', level=0): "The UI to a sequence of Sokoban levels." trails = [[] for _ in grids] # The past history for undo for each level. while True: grid, trail = grids[level], trails[level] def frame(): yield "Move with the arrow keys or HJKL. U to undo." yield "N/P for next/previous level; Q to quit." yield "" yield "Level {} {:^50} Move {}".format(level+1, name, len(trail)) yield "" yield unparse(grid) if won(grid): yield "" yield "Done!" sturm.render('\n'.join(frame()) + '\n') key = sturm.get_key().lower() if key == 'q': break elif key == 'n': level = (level + 1) % len(grids) elif key == 'p': level = (level - 1) % len(grids) elif key == 'u': if trail: grids[level] = trail.pop() elif key in directions: previously = grid[:] push(grid, directions[key]) if grid != previously: trail.append(previously)
def run(words): nrows, ncols = sturm.ROWS-1, sturm.COLS-1 words_width = max(len(word) for word,_ in words) # N.B. assumes >=1 word def view(): grams_pane = anagrams.top(nrows) for r, (word, gram) in enumerate(izip_longest(words_pane, grams_pane, fillvalue='')): if page+r == pos: yield sturm.cursor yield word.ljust(words_width), ' ', ' '.join(gram), '\n' if anagrams.done: yield ' '*words_width, ' ', '--done--' pos, new_pos = None, 0 while True: if pos != new_pos % len(words): pos = new_pos % len(words) page = (pos // nrows) * nrows words_pane = [word for word,_ in words[page:page+nrows]] anagrams = Anagrams(gen_anagrams(words[pos])) sturm.render(view()) key = sturm.get_key(None if anagrams.done else 0) if key is None: anagrams.grow() elif key == sturm.esc: return elif key == 'up': new_pos = pos - 1 elif key in ('down','\t'): new_pos = pos + 1 elif key == 'pgup': new_pos = ((pos // nrows) - 1) * nrows elif key == 'pgdn': new_pos = ((pos // nrows) + 1) * nrows
def run(): grid = [list(line) for line in maze] glutton = Agent('<', find_glutton(maze)) glutton.place_on(grid) ghosts = [make_ghost(grid) for _ in range(4)] ghost_eater_until = 0 def collision_check(): if glutton.p in [ghost.p for ghost in ghosts]: if eating_ghosts: ghosts[:] = [ghost for ghost in ghosts if ghost.p != glutton.p] else: return 'caught' for _ in ticking(): eating_ghosts = time.time() <= ghost_eater_until sturm.render(view(grid, ghosts, eating_ghosts), [(' ', x) for x in dbg_log]) dbg_log[:] = [] key = sturm.get_key(tick_interval) if key == sturm.esc: break elif key == 'left': glutton.face('>', left) elif key == 'right': glutton.face('<', right) elif key == 'up': glutton.face('V', up) elif key == 'down': glutton.face('^', down) glutton.act(grid) if glutton.meal == 'o': ghost_eater_until = time.time() + power_pill_interval if collision_check(): break for ghost in ghosts: ghost.act(grid) if collision_check(): break
def run_anagrams((word, rest)): anagrams = extend((word, ), '', rest, '') anagrams = list(anagrams) + [['--done--']] while True: sturm.render(view_anagrams(anagrams)) key = sturm.get_key() if key == sturm.esc: return
def play(grids, name='', level=0): "The UI to a sequence of Sokoban levels." trails = [[] for _ in grids] # The past history for undo for each level. while True: grid, trail = grids[level], trails[level] def frame(): yield "Move with the arrow keys or HJKL. U to undo." yield "N/P for next/previous level; Q to quit." yield "" yield "Level {} {:^50} Move {}".format(level + 1, name, len(trail)) yield "" yield unparse(grid) if won(grid): yield "" yield "Done!" sturm.render('\n'.join(frame()) + '\n') key = sturm.get_key().lower() if key == 'q': break elif key == 'n': level = (level + 1) % len(grids) elif key == 'p': level = (level - 1) % len(grids) elif key == 'u': if trail: grids[level] = trail.pop() elif key in directions: previously = grid[:] push(grid, directions[key]) if grid != previously: trail.append(previously)
def run_anagrams((word, rest)): anagrams = extend((word,), '', rest, '') anagrams = list(anagrams) + [['--done--']] while True: sturm.render(view_anagrams(anagrams)) key = sturm.get_key() if key == sturm.esc: return
def run(words): nrows, ncols = sturm.ROWS - 1, sturm.COLS - 1 words_width = max(len(word) for word, _ in words) # N.B. assumes >=1 word def view(): grams_pane = anagrams.top(nrows) for r, (word, gram) in enumerate( izip_longest(words_pane, grams_pane, fillvalue='')): if page + r == pos: yield sturm.cursor yield word.ljust(words_width), ' ', ' '.join(gram), '\n' if anagrams.done: yield ' ' * words_width, ' ', '--done--' pos, new_pos = None, 0 while True: if pos != new_pos % len(words): pos = new_pos % len(words) page = (pos // nrows) * nrows words_pane = [word for word, _ in words[page:page + nrows]] anagrams = Anagrams(gen_anagrams(words[pos])) sturm.render(view()) key = sturm.get_key(None if anagrams.done else 0) if key is None: anagrams.grow() elif key == sturm.esc: return elif key == 'up': new_pos = pos - 1 elif key in ('down', '\t'): new_pos = pos + 1 elif key == 'pgup': new_pos = ((pos // nrows) - 1) * nrows elif key == 'pgdn': new_pos = ((pos // nrows) + 1) * nrows
def run(): strokes = [] while True: sturm.render(("Hit some keys; or hit capital Q to quit.\n\n", repr(strokes), sturm.cursor)) key = sturm.get_key() if key == 'Q': break strokes.append(key)
def run(): strokes = [] while True: echoes = textwrap.fill(' '.join(strokes), sturm.COLS) sturm.render("Hit some keys; or hit capital Q to quit.\n\n", echoes, sturm.cursor) key = sturm.get_key() if key == 'Q': break strokes.append(repr(key))
def animate(string, patterns): i = 0 computation = [sorted(set(patterns))] while True: update(computation, i, string) sturm.render(instructions, "\n\n", string[:i], sturm.cursor, string[i:], "\n\n", view(computation, i)) key = sturm.get_key() if key == sturm.esc: break elif key == 'left': i = max(0, i - 1) elif key in (' ', 'right'): i = min(i + 1, len(string))
def run(words): lines = [line.split() for line in textwrap.wrap(' '.join(word for word,_ in words), sturm.COLS)] pos = 0 while True: sturm.render(view_words(lines, pos)) key = sturm.get_key() if key == sturm.esc: return elif key == '\n': run_anagrams(words[pos]) elif key == 'left': pos = (pos - 1) % len(words) elif key == 'right': pos = (pos + 1) % len(words)
def animate(string, patterns): i = 0 computation = [sorted(set(patterns))] while True: update(computation, i, string) sturm.render(instructions, "\n\n", string[:i], sturm.cursor, string[i:], "\n\n", view(computation, i)) key = sturm.get_key() if key == sturm.esc: break elif key == 'left': i = max(0, i-1) elif key in (' ','right'): i = min(i+1, len(string))
def run(): global tick_interval tick_interval = 1./4 body = [(10,10), (11,10), (12,10)] heading = down def face(new_heading): return heading if new_heading == negate(heading) else new_heading def empties(): return [(x, y) for y in range(1, nrows-1) for x in range(1, ncols-1) if (x, y) not in body] target_x, target_y = random.choice(empties()) for _ in ticking(): outcome = '' lengthen = False grid = map(list, ['#'*ncols] + (['#'+(' '*(ncols-2))+'#'] * (nrows-2)) + ['#'*ncols]) grid[target_y][target_x] = '@' for x, y in body: if grid[y][x] == '@': lengthen = True targets = empties() if not targets: outcome = "Win" else: target_x, target_y = random.choice(targets) tick_interval = max(.99 * tick_interval, tick_interval-.01) if grid[y][x] in ' @': grid[y][x] = '*' else: outcome = "Lose" sturm.render(view(grid, outcome), [(' ', x) for x in dbg_log]) dbg_log[:] = [] if outcome: break key = sturm.get_key(tick_interval) if key == 'Q': break elif key == 'left': heading = face(left) elif key == 'right': heading = face(right) elif key == 'up': heading = face(up) elif key == 'down': heading = face(down) if not lengthen: body.pop(0) body.append(add(body[-1], heading))
def interact(): start = time.time() strokes = '' while True: banner = '%5.1f' % (time.time() - start) sturm.render((banner + '\n\n' + strokes, sturm.cursor)) key = sturm.get_key(timeout=0.1) if key is None: continue elif key == 'q': break strokes += key
def run(words): lines = [ line.split() for line in textwrap.wrap(' '.join( word for word, _ in words), sturm.COLS) ] pos = 0 while True: sturm.render(view_words(lines, pos)) key = sturm.get_key() if key == sturm.esc: return elif key == '\n': run_anagrams(words[pos]) elif key == 'left': pos = (pos - 1) % len(words) elif key == 'right': pos = (pos + 1) % len(words)
def edit(): pos = 0 things = [thing for thing in mockup if isinstance(thing, Cell)] while True: sturm.render('\n', view(mockup, pos), '\n\n', ' '.join(k+' '+v for k,v in sorted(style_map.items())), '\n\n', ' '.join(colors), '\n\n', "Right/left or tab/shift-tab to navigate; Esc to quit.") key = sturm.get_key() if key == sturm.esc: break elif key in lefts: pos = (pos - 1) % len(things) elif key in rights: pos = (pos + 1) % len(things) elif key in styles: things[pos].toggle(styles[key]) elif key in backgrounds: things[pos].background(backgrounds[key]) elif key in foregrounds: things[pos].foreground(foregrounds[key])
def edit(): pos = 0 things = [thing for thing in mockup if isinstance(thing, Cell)] while True: sturm.render( '\n', view(mockup, pos), '\n\n', ' '.join(k + ' ' + v for k, v in sorted(style_map.items())), '\n\n', ' '.join(colors), '\n\n', "Right/left or tab/shift-tab to navigate; Esc to quit.") key = sturm.get_key() if key == sturm.esc: break elif key in lefts: pos = (pos - 1) % len(things) elif key in rights: pos = (pos + 1) % len(things) elif key in styles: things[pos].toggle(styles[key]) elif key in backgrounds: things[pos].background(backgrounds[key]) elif key in foregrounds: things[pos].foreground(foregrounds[key])
def puzzle(cryptogram): def my(): pass # A hack to get a mutable-nonlocal variable. my.cursor = 0 decoder = {} code = ''.join(c for c in cryptogram if c.isalpha()) assert code def erase(): jot(' ') def jot(letter): decoder[code[my.cursor]] = letter def shift_by(offset): my.cursor = (my.cursor + offset) % len(code) def view(): # Assume 1 line, for now. yield '\n' pos = itertools.count(0) for c in cryptogram: if c.isalpha() and next(pos) == my.cursor: yield sturm.cursor yield decoder.get(c, ' ') yield '\n' yield ''.join(' -'[c.isalpha()] for c in cryptogram) + '\n' yield cryptogram + '\n\n' while True: sturm.render(view()) key = sturm.get_key() if key == sturm.esc: break elif key in string.ascii_letters: jot(key) shift_by(1) elif key == 'right': shift_by(1) elif key == 'left': shift_by(-1) elif key == 'backspace': shift_by(-1) erase() elif key == 'del': erase() shift_by(1)
def play(games): level = 0 while True: game = games[level] sturm.render(instructions, "\n\n", game.view(), "\n", "You win!" if game.is_solved() else "") key = sturm.get_key() if key == sturm.esc: break elif key == '\t': level = (level + 1) % len(games) elif key == ' ': game.toggle_mark() else: v = game.variable_of_name(key) if v is not None: game.flip(v)
def main(): with sturm.cbreak_mode(): board = make_board() while True: heading = "Use the arrow keys, or Q to quit.\n\n" game_over = not any(list(move(board)) for move in [up,down,left,right]) score = "You win!" if is_won(board) else "You lose!" if game_over else "" sturm.render((heading, view(board), score, "\n")) if game_over: break key = sturm.get_key() if key.upper() == 'Q': break elif key in globals(): # Hacky hacky, sorry. :P sliding = list(globals()[key](board)) if sliding: for board in sliding: sturm.render((heading, view(board))) time.sleep(1./25) board = plop(board, 2 if random.random() < .9 else 4)
def human_play(grid): "Just ask for a move." plaint = '' prompt = whose_move(grid) + " move? [1-9] " while True: sturm.render(plaint, "\n\n", view_valid_moves(grid) if plaint else view(grid), "\n\n", prompt, sturm.cursor) key = sturm.get_key() if key == sturm.esc: sys.exit() try: move = int(key) except ValueError: pass else: if 1 <= move <= 9: successor = apply_move(grid, from_human_move(move)) if successor: return successor plaint = "Hey, that's not a move. Give me one of the digits below."
def main(): with sturm.cbreak_mode(): board = make_board() while True: heading = "Use the arrow keys, or Q to quit.\n\n" game_over = not any( list(move(board)) for move in [up, down, left, right]) score = "You win!" if is_won( board) else "You lose!" if game_over else "" sturm.render((heading, view(board), score, "\n")) if game_over: break key = sturm.get_key() if key.upper() == 'Q': break elif key in globals(): # Hacky hacky, sorry. :P sliding = list(globals()[key](board)) if sliding: for board in sliding: sturm.render((heading, view(board))) time.sleep(1. / 25) board = plop(board, 2 if random.random() < .9 else 4)
def human_play(grid): "Just ask for a move." plaint = '' prompt = whose_move(grid) + " move? [1-9] " while True: sturm.render((view(grid) + "\n\n" + plaint + prompt, sturm.cursor)) key = sturm.get_key() if key == sturm.esc: raise Quit() try: move = int(key) except ValueError: pass else: if 1 <= move <= 9: successor = apply_move(grid, from_human_move(move)) if successor: return successor plaint = ( "Hey, that's illegal. Give me one of these digits:\n\n" + (grid_format % tuple(move if apply_move(grid, from_human_move(move)) else '-' for move in range(1, 10)) + '\n\n'))
def play(grids, name='', level=0): "The UI to a sequence of Sokoban levels." trails = [[] for _ in grids] # The past history for undo for each level. while True: grid, trail = grids[level], trails[level] def frame(): heading = """\ Move with the arrow keys or HJKL. U to undo. N/P for next/previous level; Q to quit. Level {} {:^50} Move {} """ yield heading.format(level+1, name, len(trail)) yield view_grid() if won(grid): yield "\n\nDone!" def view_grid(): for c in unparse(grid): color = sturm.unstyled if c in 'iI': color = sturm.green if c in '.I@': color = sturm.compose(sturm.bold, color) yield color(c) sturm.render(frame()) key = sturm.get_key().lower() if key == 'q': break elif key == 'n': level = (level + 1) % len(grids) elif key == 'p': level = (level - 1) % len(grids) elif key == 'u': if trail: grids[level] = trail.pop() elif key in directions: previously = grid[:] push(grid, directions[key]) if grid != previously: trail.append(previously)
def human_play(grid): "Just ask for a move." plaint = '' prompt = whose_move(grid) + " move? [1-9] " while True: sturm.render((view(grid) + "\n\n" + plaint + prompt, sturm.cursor)) key = sturm.get_key() if key == sturm.esc: raise Quit() try: move = int(key) except ValueError: pass else: if 1 <= move <= 9: successor = apply_move(grid, from_human_move(move)) if successor: return successor plaint = ("Hey, that's illegal. Give me one of these digits:\n\n" + (grid_format % tuple(move if apply_move(grid, from_human_move(move)) else '-' for move in range(1, 10)) + '\n\n'))
def tictactoe(player, opponent, grid=None): "Put two strategies to a classic battle of wits." grid = grid or empty_grid while True: if is_won(grid): _, winner = player_marks(grid) sturm.render(view(grid) + "\n\n%s wins.\n" % winner) break if not successors(grid): sturm.render(view(grid) + "\n\nA draw.\n") break if human_play not in (player, opponent): sturm.render(view(grid) + ("\n\n%s to move %s. (Press a key.)" % (player.__name__.replace('_play', ''), whose_move(grid)))) if sturm.get_key() == sturm.esc: break grid = player(grid) player, opponent = opponent, player
def tictactoe(player, opponent, grid=None): "Put two strategies to a classic battle of wits." grid = grid or empty_grid while True: if is_won(grid): _, winner = player_marks(grid) sturm.render(show(grid), "%s wins." % winner) break if not successors(grid): sturm.render(show(grid), "A draw.") break if human_play not in (player, opponent): sturm.render( show(grid), ("%s to move %s. (Press a key.)" % (player.__name__.replace('_play', ''), whose_move(grid)))) if sturm.get_key() == sturm.esc: break grid = player(grid) player, opponent = opponent, player
def frame(board, score): sturm.render(heading, view(board), score)
def main(): with sturm.cbreak_mode(): edit() sturm.render('') dump()
def show(t, body): cps = (len(body) - 1) / t if t and body else 0 sturm.render('%3d seconds %3d words/minute' % (t, round(60 / 5 * cps)), ' (Hit Esc to quit.)\n\n', body, sturm.cursor)
def puzzle(cryptogram): def my(): pass # A hack to get a mutable-nonlocal variable. my.cursor = 0 # TODO: simpler now to track line# and column#? cryptogram = cryptogram.upper() lines = map(clean, cryptogram.splitlines()) code_lines = filter(None, [''.join(c for c in line if c.isalpha()) for line in lines]) line_starts = running_sum(map(len, code_lines)) code = ''.join(code_lines) assert code decoder = {c: ' ' for c in set(code)} def jot(letter): decoder[code[my.cursor]] = letter def shift_by(offset): my.cursor = (my.cursor + offset) % len(code) def shift_to_space(offset): if ' ' in decoder.values(): while True: shift_by(offset) if ' ' == decoder[code[my.cursor]]: break def shift_to_code(offset, letter): if letter in code: while True: shift_by(offset) if letter == code[my.cursor]: break def shift_line(offset): my.cursor = line_starts[(line_number(my.cursor) + offset) % (len(line_starts)-1)] def line_number(pos): return next(i for i, start in enumerate(line_starts) # TODO: use binary search if start <= pos < line_starts[i+1]) def view(show_cursor=True): counts = collections.Counter(v for v in decoder.values() if v != ' ') letters_left = ''.join(' ' if c in counts else c for c in alphabet) clashes = set(v for v,n in counts.items() if 1 < n) pos = itertools.count(0) yield sturm.green(("Free: ", letters_left, '\n')) for line in lines: yield '\n' for c in line: if show_cursor and c.isalpha() and next(pos) == my.cursor: yield sturm.cursor yield decoder.get(c, c) yield '\n' yield ''.join(' -'[c.isalpha()] for c in line) + '\n' for c in line: color = (sturm.red if decoder.get(c) in clashes else sturm.green if c == code[my.cursor] else sturm.unstyled) yield color(c) yield '\n' while True: sturm.render(view()) key = sturm.get_key() if key == ctrl('X'): break elif key == 'home': my.cursor = 0 elif key == 'end': my.cursor = len(code)-1 elif key == 'left': shift_by(-1) elif key == 'right': shift_by( 1) elif key == 'up': shift_line(-1) elif key == 'down': shift_line( 1) elif key == '\t': shift_to_space( 1) elif key == 'shift-tab': shift_to_space(-1) elif key == 'backspace': shift_by(-1) jot(' ') elif key == 'del': jot(' ') shift_by(1) elif key in alphabet or key == ' ': jot(key) shift_by(1) elif key.isupper() and len(key) == 1: shift_to_code(1, key) # So the shell prompt after exit doesn't overwrite the middle: sturm.render(view(show_cursor=False))
def show(t, body): cps = (len(body)-1) / t if t and body else 0 sturm.render('%3d seconds %3d words/minute' % (t, round(60/5 * cps)), ' (Hit Esc to quit.)\n\n', body, sturm.cursor)