How to select an item from the selected list? - python

The player enters the letter (a-z).
The program randomizes a word from a list starting with the entered letter and displays the drawn word.
What to do to make the entered key the name of the list from which it will be possible to randomly select a word beginning with the entered character?
Possibly what other way to do this?
Thank you.
Code:
import random
import pygame
# list of letters (a-z)
a = ["ananas", "arbuz", "agrest"]
b = ["banan", "balon", "beton"]
c = ["cytryna", "cebula", "candy"]
# ...
z = ["zebra", "zombie", "zonk"]
pygame.init()
screen = pygame.display.set_mode((0, 0))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN :
if event.key == pygame.K_ESCAPE:
running = False
else:
print(event.unicode)
pygame.quit()

I implemented the following function using a dictionary though it is not necessary. Depending on what you would like to do with the word list, you can write the script with or without using the dictionary. (Both of which should be easy to directly implement into your pygame script)
import keyboard
import random
a = ["ananas", "arbuz", "agrest"]
b = ["banan", "balon", "beton"]
c = ["cytryna", "cebula", "candy"]
# ...
words_dict = {}
words_dict['a'] = a
words_dict['b'] = b
words_dict['c'] = c
# ...
while True:
try:
if keyboard.is_pressed('a'):
print(random.choice(words_dict['a']))
break
elif keyboard.is_pressed('b'):
print(random.choice(words_dict['b']))
break
elif keyboard.is_pressed('c'):
print(random.choice(words_dict['c']))
break
# implement more elif here
except:
break
Instead of assigning each list with a key into the dict like what I did above, you can also directly create a dict with everything included:
words_dict = {
'a': ["ananas", "arbuz", "agrest"],
'b': ["banan", "balon", "beton"],
# and so on
}
Without using a dictionary:
import keyboard
import random
a = ["ananas", "arbuz", "agrest"]
b = ["banan", "balon", "beton"]
c = ["cytryna", "cebula", "candy"]
# ...
while True:
try:
if keyboard.is_pressed('a'):
print(random.choice(a))
break
elif keyboard.is_pressed('b'):
print(random.choice(b))
break
elif keyboard.is_pressed('c'):
print(random.choice(c))
break
# implement more elif here
except:
break
============================================================
Update: The following script detects the user's key clicks and retrieves/displays the correct information without having to use cases to check which key the user entered.
import random
import msvcrt
words_dict = {
'a': ["ananas", "arbuz", "agrest"],
'b': ["banan", "balon", "beton"],
'c': ["cytryna", "cebula", "candy"]
# ...
}
while True:
if msvcrt.kbhit():
key_pressed = msvcrt.getch()
try:
if words_dict.__contains__(key_pressed.decode('utf-8')):
print(random.choice(words_dict[key_pressed.decode('utf-8')]))
break
else:
print(f'Input "{key_pressed.decode("utf-8")}" is not recognized. Please try again!')
except:
break
Note that the variable key_pressed is of type bytes and needs to be decoded like above before been used.

Instead of creating separate lists for each character, consider using a dictionary to hold all of the lists, with the keys being the various characters. For instance,
ch_lsts = {
"a": ["ananas", "arbuz", "agrest"],
"b": ["banan", "balon", "beton"],
"c": ["cytryna", "cebula", "candy"],
...,
"z": ["zebra", "zombie", "zonk"]
}
Then, when you're ready to select the list of a given character, simply retrieve the specified list with ch_lsts["c"] (or whatever the character is) and do whatever you'd like to that list.

Related

For loop breaks whole script

I'm trying to build a Wordle clone, a word game where one gets 6 chances to guess a 5 letter word. The game itself works but when I try to show the definition of the word at the end of the game, my whole game gets stuck.
My code is this:
import pygame
import pygame.display
import sys
import random
from words import *
from PyDictionary import PyDictionary
pygame.init()
# a py file with list of words
CORRECT_WORD = WORDS
CORRECT_WORD_LIST = list(CORRECT_WORD)
word = random.choice(CORRECT_WORD_LIST)
# number of attempts, 6 in total
attempts = 0
# a list to store the previous guesses
guesses = [[]] * 6
cur_guess = []
cur_guess_str = ""
current_letter_bg_x = 110
game_result = ""
# get the meaning of the word
def get_meaning(word):
dicto = PyDictionary()
meaning = dicto.meaning(word)
if meaning == "":
meaning = "No definition found"
return meaning
meaning = get_meaning(word)
def blit_text(surface, text, pos, font):
"""Multi-line text blit from https://stackoverflow.com/a/42015712/2280890"""
def check_guess(guess):
# Check if letter is Green, Yellow or grey if not in word
# trimmed, for not being part of the problem
attempts += 1
cur_guess = []
cur_guess_str = ""
current_letter_bg_x = 110
def play_again():
SCREEN.blit(BACKGROUND, BG_RECT)
play_again_text = play_again_font.render("ENTER to Play Again? or Q to Quit!", True, "#FCFCFC")
pygame.display.update()
word_text = play_again_font.render(f"{word.upper()}", True, "#FFB90F")
SCREEN.blit(play_again_text, play_again_rect)
SCREEN.blit(word_text, word_rect)
pygame.display.flip()
def reset():
# Reset all global variables
I've trimmed/removed a bunch of lines relating to creating/drawing letters and backspace etc.
Up until this point everything works as expected. The letters, if in correct position get colored as expected.
My problem starts here. Instead of only showing the definition after 6 attempts it shows the meaning as soon as the game starts. This is the block of code that breaks the game:
for i in enumerate(guesses[attempts]):
if i == 6 and game_result is not "W":
word = random.choice(CORRECT_WORD_LIST)
meaning = get_meaning(word)
txt = f"{meaning}"
txt_pos = (40, 70)
window.blit(BACKGROUND, [-317, -300])
f"{blit_text(window, txt, txt_pos, sys_font)}", True, "#FFB90F"
pygame.display.update
If I omit that block the game runs as expected and if I leave as below, it works as expected.
Game
while running:
if game_result != "":
play_again()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
if game_result != "":
reset()
else:
if len(cur_guess_str) == 5 and cur_guess_str.lower() in WORDS:
check_guess(cur_guess)
elif event.key == pygame.K_BACKSPACE:
if len(cur_guess_str) > 0:
delete_letter()
else:
key_pressed = event.unicode.upper()
if key_pressed in "QWERTYUIOPASDFGHJKLZXCVBNM" and key_pressed != "":
if len(cur_guess_str) < 5:
new_letter()
Can someone help me understand why my logic/reasoning is flawed?
The block of code that is causing issues I insert it right after ### game, in between while running: and right before
if game_result != "":
play_again()
while True:
meaning = ""
for i in range(len(guesses[attempts])):
if i == 6 and game_result is not "W":
word = random.choice(CORRECT_WORD_LIST)
meaning = get_meaning(word)
txt = f"{meaning}"
txt_pos = (40, 70)
window.blit(BACKGROUND, [-317, -300])
f"{blit_text(window, txt, txt_pos, sys_font)}", True, "#FFB90F"
pygame.display.update()
for the code above you have put while running but you never change running so wouldn`t it be better to do while True. Also if you put while True a better way of ending the game is to just do break instead of pygame.quit() and sys.exit(). Also can I see the output that prints when the game breaks please?
Don't Work (I have edited the code and it prints because as soon as the game starts to run you have put txt=f"{meaning}" by moving it across that only happens when i == 6 and game_result is not "W". I don't know if this will work but its worth a try.)
If that doesn`t work from what I can see you don't use enumerate so I would replace it with range(len(guesses[attempts]))

Detect a key pressed within a while Python

I want to detect a key pressed in python without using "with", because I want it to show a text in a while
all this with the pynput library:
import time
from pynput import keyboard
i = 0
while True:
if event.key == keyboard.Key.esc:
break
else:
if a == "hello":
print("y")
else:
print("n")
if i % 2 = 0:
a = "hello"
else
a = "good bye"
i += 1
print(a)
time.sleep(2)
pynput's Events blocks by default. You can .get to limit how long it blocks for:
from pynput import keyboard
import time
i = 0
a = "start"
while True:
if a == "hello":
print("y")
else:
print("n")
if i % 2 == 0:
a = "hello"
else:
a = "good bye"
i += 1
print(a)
# Not needed anymore, we're going to block waiting for key events for 2 seconds
# time.sleep(2)
with keyboard.Events() as events:
# Block at most for two seconds
event = events.get(2.0)
if event is not None:
if event.key == keyboard.Key.esc:
break
This won't necessarily always block for two seconds if the user presses some other key. You can either add code to check for that condition and keep calling events.get till enough time has passed, or use keyboard.Listener to react to events in real time.

Random dictionary searches which never returns same item twice

Is there a way when asking the program to chose a random entry from a dictionary of key-value entries is there a way that once every entry has been picked once the program will let the user know that all entries have been picked and then stop, ultimately only allowing each entry to be picked once so, if there are only 3 entries the program will only run 3 times and if there are 100 entries it will run 100 times and so on? New to python coding so please bear with me.
from random import *
def show_keys():
""" Show the user a random key and ask them
to define it. Show the definition
when the user presses return.
"""
random_key = choice(list(keys))
print('Define: ', random_key)
input('Press return to see the definition')
print(keys [random_key])
# Set up the keys
keys = {'key1':'definition1',
'key2':'definition2',
'key3':'definition3'}
# The loop
exit = False
while not exit:
user_input = input('Enter s to show a key, or q to quit: ')
if user_input == 'q':
exit = True
elif user_input == 's':
show_keys()
else:
print('You need to enter either q or s.')
You can get the keys from the dictionary, select random elements from that list, get the dictionary entry and remove the key from the list subsequently.
import random
dictionary = {
'one': '1',
'two': '2',
'three': '3'
}
# getting list of keys from dictionary
keys = list(dictionary.keys())
print(keys)
# picking random elemt from list
elem = random.choice(keys)
print(elem, dictionary.get(elem))
# remove an element from a list
keys.remove(elem)
print(keys)
Use a set to collect which keys you aready asked for.
Provide the set and the dict to the function that asks for a definition so it can add a new key to it - do not use globals.
Loop until either no more guesses possible (len(already)==len(data)) and handle that case or until user wants to quit:
from random import choice # do not import ALL - just what you need
def show_keys(d,a): # provide data and already used key set
""" Show the user a random key and ask them
to define it. Show the definition
when the user presses return.
d : your dict of keys and definitions
a : a set of already used keys
"""
# choice only for those keys that are not yet used
random_key = choice( [k for k in d if k not in a] )
print('Define: ', random_key)
input('Press return to see the definition')
print(d [random_key])
# add used key to a - you could ask (y/n) if the definition was correct
# and only then add the key - if wrong it has a chance of being asked again
a.add(random_key)
# Set up the data with keys and defs
data = {'key1':'definition1',
'key2':'definition2',
'key3':'definition3'}
# set up already seen keys
already = set()
# The loop
while True: # loop until break
# nothing more to guess
if len(already)==len(data):
y = input("Game over. Play again? [y, ]").lower()
if y=="y":
# reset set of seen stuff to empty set()
already = set()
else:
break
user_input = input('Enter s to show a key, or q to quit: ')
if user_input == 'q':
break
elif user_input == 's':
# provide data and already to the function, don't use globals
show_keys(data,already)
else:
print('You need to enter either q or s.')
Alternativly: create a shuffled list and use that:
from random import shuffle
data = {'key1':'definition1',
'key2':'definition2',
'key3':'definition3'}
already = set()
shuffled = list(data.items())
shuffle(shuffled)
# The loop
while shuffled:
user_input = input('Enter s to show a key, or q to quit: ')
if user_input == 'q':
break
elif user_input == 's':
key,value = shuffled.pop()
print('Define: ', key)
input('Press return to see the definition')
print(value)
else:
print('You need to enter either q or s.')

A novice's hangman project: Dealing with duplicate letters

First, I realize the following code is probably not very good, so apologies for anything that makes you cringe, I'm just trying to code as much as I can in hopes of getting better.
This is part of a small hangman game project, I'm trying to figure the best way to deal with duplicate letters in strings.
This is what I got for now:
def checkDupes(word):
global dupeList
global repeatTimesDupes
if repeatTimesDupes != 0:
dupeCount = 0
for i in range(len(word)):
temp = word[i]
print("temp letter is: ", temp)
for j in range(i+1,len(word)):
if word[j] == temp:
if temp not in dupeList:
dupeList.append(word[j])
print("the dupeList contains: ", dupeList)#debug
repeatTimesDupes -= 1
def getLetter(position,buttons,word):
i = 96
index = 0
letter = chr(i)
for button in buttons:
if button != None:
i+=1
if button.collidepoint(position):
print("the position is: ", position)
print(i)
for j in range(len(word)):
print(word[j] , chr(i))
if word[j] == chr(i):
index = j
return chr(i), index
else:
return '?', -1
def checkForLetter(word,letter):
inWord = " "
for i in range(len(word)):
if word[i] == letter:
inWord = True
break
else:
print(len(word))
print (word[i])
inWord = False
return inWord
#========================== Start Loop ===========================================
while done == False:
events = pygame.event.get()
screen.fill(BGCOLOR)
timedelta = clock.tick_busy_loop(60)
timedelta /= 1000 # Convert milliseconds to seconds
for event in events:
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
if event.type == pygame.MOUSEBUTTONUP:
if event.button == MOUSEBUTTONLEFT:
pos = pygame.mouse.get_pos()
for button in buttonsList:
if button.collidepoint(pos):
if button != None:
checkDupes(gameWord)
letter, atIndex = getLetter(pos,buttonsList,gameWord)
letterSelected = True
moveCounter+=1
screen.blit(blackBG,(0,0))
showButtons(letterList)
showLetterSlots(gameWord,screenRect)
setCounters(moveMade,mistakeMade)
if letterSelected:
inGameWord = checkForLetter(gameWord, letter)
if inGameWord:
print(atIndex)
print(letter)
letterRen = wordFonts.render(letter,1,(0,255,0))
renderList[atIndex] = letterRen
print("The render list is: ", renderList)
renCount = 0
for r in lineRectList:
if renderList[renCount] != '?' :
screen.blit(renderList[renCount],((r.centerx-10),430))
if renCount <= len(gameWord):
renCount+=1
#update game screen
clock.tick(60)
pygame.display.update()
#========================== End Loop =============================================
pygame.quit()
I'm looking for quick way to deal with duplicates so they are blitted along with their matches. I'm already slowing down my letter blits with all that looping, so I'm not really sure my current getDupes is the way to go.
If anyone is willing to look at this and give some input, I'd very much appreciate it.
Thanks for your time.
Based on what you've described in the comments, it seems reasonable to use a dictionary object in this case. You don't just want to store the letter, you want to store where those letters occur.
Dictionaries have a key and a value. For example:
{'jack': 4095, 'jill': 12}
The key is jack and the value is 4095.
In this case, we won't be using an int for the value. We'll actually be using an array of ints.
So, your dictionary might look like this:
{'o':[1, 5, 6, 3, 2, 1]} where those numbers are the index that the letter was encountered at. That will work for an arbitrary number of duplicate letters. Then, in your buttons, you know which ones to 'blit' because they're in the same order as the string.
Python dictionary documentation:
https://docs.python.org/3/tutorial/datastructures.html
FWIW, some refactoring would do you service here as well.

Python Windows `msvcrt.getch()` only detects every 3rd keypress?

My code is below:
import msvcrt
while True:
if msvcrt.getch() == 'q':
print "Q was pressed"
elif msvcrt.getch() == 'x':
sys.exit()
else:
print "Key Pressed:" + str(msvcrt.getch()
This code is based on this question; I was using it to acquaint myself with getch.
I've noticed that it takes 3 pressing the key 3 times to output the text once. Why is this? I'm trying to use it as an event loop, and that's too much of a lag...
Even if I type 3 different keys, it only outputs the 3rd keypress.
How can I force it to go faster? Is there a better way to achieve what I'm trying to achieve?
Thanks!
evamvid
you call the function 3 times in your loop. try calling it only once like this:
import msvcrt
while True:
pressedKey = msvcrt.getch()
if pressedKey == 'q':
print "Q was pressed"
elif pressedKey == 'x':
sys.exit()
else:
print "Key Pressed:" + str(pressedKey)
You can optimize things a little bit by also using themsvcrt.kbhit function which will allow you callmsvcrt.getch()only as much as is necessary:
while True:
if msvcrt.kbhit():
ch = msvcrt.getch()
if ch in '\x00\xe0': # arrow or function key prefix?
ch = msvcrt.getch() # second call returns the scan code
if ch == 'q':
print "Q was pressed"
elif ch == 'x':
sys.exit()
else:
print "Key Pressed:", ch
Note that theKey Pressedvalue printed won't make sense for things like function keys. That's because it those cases it's really the Windows scan code for the key, not a regular key code for the character.

Categories