|
| 1 | +import time |
| 2 | +from pywebio import start_server, config |
| 3 | +from pywebio.output import * |
| 4 | +from pywebio.session import run_js, local as session_local |
| 5 | + |
| 6 | +TODAY_WORD = 'PYWEBIO' # need to be uppercase |
| 7 | + |
| 8 | +MAX_TRY = 6 |
| 9 | +WORD_LEN = len(TODAY_WORD) |
| 10 | + |
| 11 | + |
| 12 | +CSS = """ |
| 13 | +.pywebio {padding-top: 0} .markdown-body table {display:table; width:250px; margin:10px auto;} |
| 14 | +.markdown-body table th, .markdown-body table td {font-weight:bold; padding:0; line-height:50px;} |
| 15 | +th>div,td>div {width:50px; height:50px}.btn-light {background-color:#d3d6da;} |
| 16 | +@media (max-width: 435px) {.btn{padding:0.375rem 0.5rem;}} |
| 17 | +@media (max-width: 355px) {.btn{padding:0.375rem 0.4rem;}} |
| 18 | +""" |
| 19 | + |
| 20 | + |
| 21 | +# To check if a user's input word is actually a legit word |
| 22 | +# We just implement a placeholder function in this example |
| 23 | +# If a guess word is UNHAPPY, toast a message |
| 24 | +def is_word(s): |
| 25 | + return 'UNHAPPY' not in s |
| 26 | + |
| 27 | + |
| 28 | +def on_key_press(char): |
| 29 | + if session_local.curr_row >= MAX_TRY or session_local.game_pass: |
| 30 | + return |
| 31 | + |
| 32 | + if char == '◀': |
| 33 | + session_local.curr_word = session_local.curr_word[:-1] |
| 34 | + return clear(f's-{session_local.curr_row}-{len(session_local.curr_word)}') |
| 35 | + |
| 36 | + # show the char in grid |
| 37 | + with use_scope(f's-{session_local.curr_row}-{len(session_local.curr_word)}', clear=True): |
| 38 | + put_text(char) |
| 39 | + |
| 40 | + session_local.curr_word += char |
| 41 | + if len(session_local.curr_word) == WORD_LEN: # submit a word guess |
| 42 | + if not is_word(session_local.curr_word): |
| 43 | + toast('Not in word list!', color='error') |
| 44 | + session_local.curr_word = '' |
| 45 | + for i in range(WORD_LEN): |
| 46 | + clear(f's-{session_local.curr_row}-{i}') |
| 47 | + else: |
| 48 | + for idx, c in enumerate(session_local.curr_word): |
| 49 | + time.sleep(0.2) |
| 50 | + if TODAY_WORD[idx] == c: |
| 51 | + session_local.green_chars.add(c) |
| 52 | + run_js('$("button:contains(%s)").css({"background-color":"#6aaa64", "color":"white"})' % c) |
| 53 | + text_bg = '#6aaa64' |
| 54 | + session_local.game_result += '🟩' |
| 55 | + elif c in TODAY_WORD: |
| 56 | + text_bg = '#c9b458' |
| 57 | + session_local.game_result += '🟨' |
| 58 | + if c not in session_local.green_chars: |
| 59 | + run_js('$("button:contains(%s)").css({"background-color":"#c9b458", "color":"white"})' % c) |
| 60 | + else: |
| 61 | + text_bg = '#787c7e' |
| 62 | + session_local.game_result += '⬜' |
| 63 | + run_js('$("button:contains(%s)").css({"background-color":"#787c7e", "color":"white"})' % c) |
| 64 | + |
| 65 | + with use_scope(f's-{session_local.curr_row}-{idx}', clear=True): |
| 66 | + put_text(c).style(f'color:white;background:{text_bg}') |
| 67 | + |
| 68 | + session_local.game_result += '\n' |
| 69 | + if session_local.curr_word == TODAY_WORD: |
| 70 | + toast('Genius', color='success') |
| 71 | + session_local.game_pass = True |
| 72 | + |
| 73 | + session_local.curr_row += 1 |
| 74 | + session_local.curr_word = '' |
| 75 | + |
| 76 | + if session_local.game_pass: |
| 77 | + message = f'Wordle {session_local.curr_row}/{MAX_TRY}\n' + session_local.game_result |
| 78 | + with popup("Game Result", size='small'): |
| 79 | + put_text(message).style('text-align: center') |
| 80 | + put_button('Share', color='success', onclick=lambda: toast('Copied to clipboard') or run_js("""navigator.clipboard.write([new ClipboardItem({"text/plain":new Blob([text],{type:"text/plain"})})]);""", text=message)).style('text-align: center') |
| 81 | + |
| 82 | + |
| 83 | +@config(title="WORDLE with PyWebIO", description="A wordle-like game implemented with PyWebIO", css_style=CSS) |
| 84 | +def main(): |
| 85 | + put_markdown( |
| 86 | + '# WORDLE \n A pure python implementation of a [Wordle-like game](https://en.wikipedia.org/wiki/Wordle), using PyWebIO library. ' |
| 87 | + '[Source code](https://github.com/pywebio/PyWebIO/blob/dev/demos/wordle.py)' |
| 88 | + ).style('text-align:center') |
| 89 | + |
| 90 | + grid = [ |
| 91 | + [put_scope(f's-{x}-{y}', content=put_text(' ')) for y in range(WORD_LEN)] |
| 92 | + for x in range(MAX_TRY) |
| 93 | + ] |
| 94 | + put_table(grid).style('text-align: center') |
| 95 | + |
| 96 | + keyboard = [ |
| 97 | + put_buttons([dict(label=c, value=c, color='light') for c in keys], on_key_press, serial_mode=True) |
| 98 | + for keys in ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM◀'] |
| 99 | + ] |
| 100 | + put_column(keyboard).style('text-align: center') |
| 101 | + |
| 102 | + session_local.curr_row = 0 |
| 103 | + session_local.curr_word = '' |
| 104 | + session_local.green_chars = set() |
| 105 | + session_local.game_pass = False |
| 106 | + session_local.game_result = '' |
| 107 | + |
| 108 | + |
| 109 | +if __name__ == '__main__': |
| 110 | + start_server(main, port=8080, cdn=False) |
0 commit comments