+: finales 146-150
80
README.md
@ -4,71 +4,61 @@ Guia interactiva con la resolución de los retos propuestos en el libro
|
||||
[Python by Example](https://www.google.cl/books/edition/Python_by_Example/gDGdDwAAQBAJ)
|
||||
de *Nichola Lacey*
|
||||
|
||||
![img](./imgs/main_menu.png)
|
||||
|
||||
### Retos Básicos
|
||||
|
||||
- [001-011](./basic/basic01.py)
|
||||
- [012-019](./basic/basic02.py)
|
||||
- [020-026](./basic/basic03.py)
|
||||
- [027-034](./basic/basic04.py)
|
||||
- [035-044](./basic/basic05.py)
|
||||
- [045-051](./basic/basic06.py)
|
||||
- [052-059](./basic/basic07.py)
|
||||
- [001-011](./basic/basic01.py) | [012-019](./basic/basic02.py) |
|
||||
[020-026](./basic/basic03.py) | [027-034](./basic/basic04.py) |
|
||||
[035-044](./basic/basic05.py) | [045-051](./basic/basic06.py) |
|
||||
[052-059](./basic/basic07.py) ![img](./imgs/basics_001-059.png)
|
||||
|
||||
### Retos Turtle
|
||||
|
||||
- [060](./trtl/turtle01.py)
|
||||
- [061](./trtl/turtle02.py)
|
||||
- [062](./trtl/turtle03.py)
|
||||
- [063](./trtl/turtle04.py)
|
||||
- [064](./trtl/turtle05.py)
|
||||
- [065](./trtl/turtle06.py)
|
||||
- [066](./trtl/turtle07.py)
|
||||
- [067](./trtl/turtle08.py)
|
||||
- [068](./trtl/turtle09.py)
|
||||
- [060](./trtl/turtle01.py) | [061](./trtl/turtle02.py) |
|
||||
[062](./trtl/turtle03.py) | [063](./trtl/turtle04.py) |
|
||||
[064](./trtl/turtle05.py) | [065](./trtl/turtle06.py) |
|
||||
[066](./trtl/turtle07.py) | [067](./trtl/turtle08.py) |
|
||||
[068](./trtl/turtle09.py) ![img](./imgs/turtle_060-068.png)
|
||||
|
||||
### Retos Intermedios
|
||||
|
||||
- [069-079](./interm/interm01.py)
|
||||
- [080-087](./interm/interm02.py)
|
||||
- [088-095](./interm/interm03.py)
|
||||
- [096-104](./interm/interm04.py)
|
||||
- [105-110](./interm/interm05.py)
|
||||
- [111-117](./interm/interm06.py)
|
||||
- [118-123](./interm/interm07.py)
|
||||
- [069-079](./interm/interm01.py) | [080-087](./interm/interm02.py) |
|
||||
[088-095](./interm/interm03.py) | [096-104](./interm/interm04.py) |
|
||||
[105-110](./interm/interm05.py) | [111-117](./interm/interm06.py) |
|
||||
[118-123](./interm/interm07.py) ![img](./imgs/interm_069-123.png)
|
||||
|
||||
### Retos Tkinter
|
||||
|
||||
- [124](./tkgui/tk01.py)
|
||||
- [125](./tkgui/tk02.py)
|
||||
- [126](./tkgui/tk03.py)
|
||||
- [127](./tkgui/tk04.py)
|
||||
- [128](./tkgui/tk05.py)
|
||||
- [129](./tkgui/tk06.py)
|
||||
- [130](./tkgui/tk07.py)
|
||||
- [131](./tkgui/tk08.py)
|
||||
- [132](./tkgui/tk09.py)
|
||||
- [133](./tkgui/tk10.py)
|
||||
- [134](./tkgui/tk11.py)
|
||||
- [135](./tkgui/tk12.py)
|
||||
- [136](./tkgui/tk13.py)
|
||||
- [137](./tkgui/tk14.py)
|
||||
- [138](./tkgui/tk15.py)
|
||||
- [124](./tkgui/tk01.py) | [125](./tkgui/tk02.py) | [126](./tkgui/tk03.py) |
|
||||
[127](./tkgui/tk04.py) | [128](./tkgui/tk05.py) | [129](./tkgui/tk06.py) |
|
||||
[130](./tkgui/tk07.py) | [131](./tkgui/tk08.py) | [132](./tkgui/tk09.py) |
|
||||
[133](./tkgui/tk10.py) | [134](./tkgui/tk11.py) | [135](./tkgui/tk12.py) |
|
||||
[136](./tkgui/tk13.py) | [137](./tkgui/tk14.py) | [138](./tkgui/tk15.py)
|
||||
![img](./imgs/tkinter_124-138.png)
|
||||
|
||||
### Retos SQLite3
|
||||
|
||||
- [139](./sqlite/sql01.py)
|
||||
- [140](./sqlite/sql02.py)
|
||||
- [141](./sqlite/sql03.py)
|
||||
- [142](./sqlite/sql04.py)
|
||||
- [143](./sqlite/sql05.py)
|
||||
- [144](./sqlite/sql06.py)
|
||||
- [145](./sqlite/sql07.py)
|
||||
- [139](./sqlite/sql01.py) | [140](./sqlite/sql02.py) |
|
||||
[141](./sqlite/sql03.py) | [142](./sqlite/sql04.py) |
|
||||
[143](./sqlite/sql05.py) | [144](./sqlite/sql06.py) |
|
||||
[145](./sqlite/sql07.py)
|
||||
|
||||
### Retos Finales
|
||||
|
||||
- [146](./final/fin01.py) | [147](./final/fin02.py) | [148](./final/fin03.py) |
|
||||
[149](./final/fin04.py) | [150](./final/fin05.py)
|
||||
![img](./imgs/final_146-150.png)
|
||||
|
||||
## Uso
|
||||
|
||||
Requiere **Tkinter** para retos [124-128](./tkgui/)
|
||||
|
||||
```sh
|
||||
git clone https://gitea.kickto.net/devfzn/python_by_example.git
|
||||
|
||||
cd python_by_example
|
||||
python main.py
|
||||
```
|
||||
|
||||
Mas [imagenes](./images.md)
|
||||
|
1
final/files/files_directory
Normal file
@ -0,0 +1 @@
|
||||
directorio para creación/lectura/escritura de archivos y bd.
|
75
final/fin01.py
Normal file
@ -0,0 +1,75 @@
|
||||
from common.common import clear
|
||||
|
||||
def fin_01():
|
||||
"""A shift code is where a message can be easily encoded and is one of the
|
||||
simplest codes to use. Each letter is moved forwards through the alphabet
|
||||
a set number of letters to be represented by a new letter. For instance,
|
||||
'abc' becomes 'bcd' when the code is shifted by one (i.e. each letter in
|
||||
the alphabet is moved forward one character). You need to create a
|
||||
program which will display the following menu:
|
||||
1) Make a code
|
||||
2) Decode a message
|
||||
3) Quit
|
||||
|
||||
Enter your selection:
|
||||
If the user selects 1, they should be able to type in a message
|
||||
(including spaces) and then enter a number. Python should then display
|
||||
the encoded message once the shift code has been applied. If the user
|
||||
selects 2, they should enter an encoded message and the correct number
|
||||
and it should display the decoded message (i.e. move the correct number
|
||||
of letters backwards through the alphabet). If they select 3 it should
|
||||
stop the program from running. After they have encoded or decoded a
|
||||
message the menu should be displayed to them again until they select quit."""
|
||||
abc = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'ñ', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
|
||||
|
||||
def code_msg(msg, steps):
|
||||
coded_message = ""
|
||||
for letter in msg:
|
||||
if letter in abc:
|
||||
ind = abc.index(letter)
|
||||
ind += steps
|
||||
while ind >= len(abc):
|
||||
ind -= len(abc)
|
||||
coded_message += abc[ind]
|
||||
else:
|
||||
coded_message += letter
|
||||
print(coded_message)
|
||||
|
||||
def decode_msg(msg, steps):
|
||||
decoded_message = ""
|
||||
for letter in msg:
|
||||
if letter in abc:
|
||||
ind = abc.index(letter)
|
||||
ind -= steps
|
||||
while ind < -len(abc):
|
||||
ind += len(abc)
|
||||
decoded_message += abc[ind]
|
||||
else:
|
||||
decoded_message += letter
|
||||
print(decoded_message)
|
||||
|
||||
while True:
|
||||
clear()
|
||||
print("""
|
||||
1) Codificar mensaje
|
||||
2) Decodificar mensaje
|
||||
s) Salir
|
||||
""")
|
||||
sel = input("Ingresa una opción: ")
|
||||
match sel:
|
||||
case '1':
|
||||
msg = input("Ingresa el mensaje a codificar: ")
|
||||
steps = int(input("Ingresa el nro. de pasos: "))
|
||||
code_msg(msg, steps)
|
||||
input("\nPresiona Enter para continuar\n")
|
||||
case '2':
|
||||
msg = input("Ingresa el mensaje a decodificar: ")
|
||||
steps = int(input("Ingresa el nro. de pasos: "))
|
||||
decode_msg(msg, steps)
|
||||
input("\nPresiona Enter para continuar\n")
|
||||
case 's':
|
||||
break
|
||||
case _:
|
||||
print("Debes ingresar una opción válida")
|
||||
input("\nPresiona Enter para continuar\n")
|
79
final/fin02.py
Normal file
@ -0,0 +1,79 @@
|
||||
from random import choice
|
||||
from common.common import clear
|
||||
|
||||
def fin_02():
|
||||
"""You are going to make an on-screen version of the board game 'Mastermind'.
|
||||
The computer will automatically generate four colours from a list of
|
||||
possible colours (it should be possible for the computer to randomly
|
||||
select the same colour more than once). For instance, the computer may
|
||||
choose 'red', 'blue', 'red', 'green'. This sequence should not be
|
||||
displayed to the user. After this is done the user should enter their
|
||||
choice of four colours from the same list the computer used. For
|
||||
instance, they may choose 'pink', 'blue', 'yellow' and 'red'. After the
|
||||
user has made their selection, the program should display how many
|
||||
colours they got right in the correct position and how many colours they
|
||||
got right but in the wrong position. In the example above, it should
|
||||
display the message 'Correct colour in the correct place: 1' and 'Correct
|
||||
colour but in the wrong place: 1'. The user continues guessing until they
|
||||
correctly enter the four colours in the order they should be in. At the
|
||||
end of the game it should display a suitable message and tell them how
|
||||
many guesses they took."""
|
||||
colours = {
|
||||
'NEGRO': "\033[0;30;1;47m",
|
||||
'PURPURA': "\033[1;35m",
|
||||
'CIAN': "\033[0;1;36m",
|
||||
'ROJO': "\033[1;31m",
|
||||
'VERDE': "\033[1;32m",
|
||||
'AMARILLO': "\033[1;33m",
|
||||
'AZUL': "\033[1;34m",
|
||||
'BLANCO': "\033[1;37m",
|
||||
'END': "\033[0m"
|
||||
}
|
||||
secrets = []
|
||||
guesses = []
|
||||
tries = 0
|
||||
for _ in range(4):
|
||||
secrets.append(choice(list(colours.keys())[:-1]))
|
||||
#print(colours[secrets[i]]+"█████"+secrets[i]+"█████"+colours['END'])
|
||||
|
||||
print("\n COLORES\n")
|
||||
for color in list(colours.keys())[:-1]:
|
||||
print(' '+color.capitalize(), end=' ')
|
||||
print()
|
||||
|
||||
def guess_colours():
|
||||
guesses.clear()
|
||||
print("\nIngresa 4 colores de la lista")
|
||||
cont = 1
|
||||
while len(guesses) < 4:
|
||||
resp = input(f"Ingresa el color nro. {cont}: ").upper()
|
||||
if resp in list(colours.keys())[:-1]:
|
||||
guesses.append(resp)
|
||||
cont += 1
|
||||
print()
|
||||
|
||||
def check_colours():
|
||||
ok_guess = 0
|
||||
for i, guess in enumerate(guesses):
|
||||
if guess in secrets:
|
||||
print(colours[guess]+f"{guess} está en los colores", end='')
|
||||
if guess == secrets[i]:
|
||||
print(", en está misma posición"+colours["END"])
|
||||
ok_guess +=1
|
||||
else:
|
||||
print(", en otra posición"+colours["END"])
|
||||
else:
|
||||
print(f"{guess} no está entre los colores")
|
||||
print()
|
||||
if ok_guess == 4:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
win = False
|
||||
while not win:
|
||||
guess_colours()
|
||||
win = check_colours()
|
||||
tries += 1
|
||||
|
||||
print(f"Ganaste en {tries} intentos")
|
137
final/fin03.py
Normal file
@ -0,0 +1,137 @@
|
||||
from os import getcwd as pwd
|
||||
from getpass import getpass
|
||||
from common.common import clear
|
||||
import csv
|
||||
|
||||
def fin_03():
|
||||
"""You need to create a program that will store the user ID and passwords
|
||||
for the users of a system. It should display the following menu:
|
||||
1) Create a new User ID
|
||||
2) Change a password
|
||||
3) Display all User IDs
|
||||
4) Quit
|
||||
|
||||
Enter selection:
|
||||
If the user selects 1, it should ask them to enter a user ID. It should check
|
||||
if the user ID is already in the list. If it is, the program should display
|
||||
a suitable message and ask them to select another user ID. Once a suitable
|
||||
user ID has been entered it should ask for a password. Passwords should be
|
||||
scored with 1 point for each of the following:
|
||||
- it should have at least 8 characters.
|
||||
- it should include uppercase letters.
|
||||
- it should include lower case letters.
|
||||
- it should include numbers.
|
||||
- it should include at least one special character such as
|
||||
!, £, $, %, &, <, * or @.
|
||||
If the password scores only 1 or 2 it should be rejected with a message
|
||||
saying it is a weak password; if it scores 3 or 4 tell them that "This
|
||||
password could be improved." Ask them if they want to try again. If it
|
||||
scores 5 tell them they have selected a strong password. Only acceptable
|
||||
user IDs and passwords should be added to the end of the .csv file. If they
|
||||
select 2 from the menu they will need to enter a user ID, check to see if
|
||||
the user ID exists in the list, and if it does, allow the user to change the
|
||||
password and save the changes to the .csv file. Make sure the program only
|
||||
alters the existing password and does not create a new record. If the user
|
||||
selects 3 from the menu, display all the user IDs but not the passwords. If
|
||||
the user selects 4 from the menu it should stop the program."""
|
||||
file_path = f"{pwd()}/final/files/users.csv"
|
||||
menu = """
|
||||
Administrador de Usuarios
|
||||
|
||||
1) Crear nuevo ID de usuario
|
||||
2) Cambiar una contraseña
|
||||
3) Ver todos los ID de usuario
|
||||
s) Salir
|
||||
"""
|
||||
def create_pass():
|
||||
points = 0
|
||||
while points < 3:
|
||||
points = 0
|
||||
password = getpass("Ingresa la contraseña: ")
|
||||
if len(password) >= 8:
|
||||
points += 1
|
||||
x = len([1 for p in password if p.isupper()])
|
||||
points += 1 if x > 0 else 0
|
||||
x = len([1 for p in password if p.islower()])
|
||||
points += 1 if x > 0 else 0
|
||||
x = len([1 for p in password if p.isdigit()])
|
||||
points += 1 if x > 0 else 0
|
||||
x = len([1 for p in password if p in '!£$%&<*@'])
|
||||
points += 1 if x > 0 else 0
|
||||
if points < 3:
|
||||
print("La contraseña es demasiado debil")
|
||||
continue
|
||||
elif 2 < points < 5:
|
||||
resp = input("El password podría ser mejor, ¿quieres mejorarlo? (S|n): ").lower()
|
||||
if resp != 'n':
|
||||
points = 0
|
||||
continue
|
||||
repass = getpass("Verificar la contraseña:")
|
||||
if repass != password:
|
||||
points = 0
|
||||
return password
|
||||
|
||||
def create_user():
|
||||
user = input("Ingresa el nombre de usuario: ").strip()
|
||||
temp_users = get_users()
|
||||
if temp_users is None or user not in temp_users:
|
||||
password = create_pass()
|
||||
with open(file_path, '+a') as file:
|
||||
file.write(f"{user},{password}\n")
|
||||
input("Usuario creado, presiona Enter para continuar")
|
||||
else:
|
||||
input("Usuario ya existe, presiona Enter para continuar")
|
||||
|
||||
def change_pass():
|
||||
user = input("Ingresa el nombre del usuario a modificar contraseña: ")
|
||||
temp_users = get_users()
|
||||
if temp_users is not None and user in temp_users:
|
||||
password = create_pass()
|
||||
temp_data = []
|
||||
with open(file_path, 'r') as file:
|
||||
reader = csv.reader(file)
|
||||
for line in reader:
|
||||
if user in line[0]:
|
||||
temp_data.append([line[0],password])
|
||||
else:
|
||||
temp_data.append([line[0],line[1]])
|
||||
with open(file_path, 'w') as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerows(temp_data)
|
||||
print(f"Password actualizado exitosamente")
|
||||
else:
|
||||
print("El usuario ingresado no existe")
|
||||
input("Presiona Enter para continuar")
|
||||
|
||||
def get_users():
|
||||
temp_users = []
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
read = csv.reader(file)
|
||||
for r in read:
|
||||
temp_users.append(r[0])
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return temp_users
|
||||
|
||||
while True:
|
||||
clear()
|
||||
print(f"Ruta archivo:\n{file_path}")
|
||||
print(menu)
|
||||
sel = input("Ingresa una opción: ")
|
||||
match sel:
|
||||
case "1":
|
||||
create_user()
|
||||
case "2":
|
||||
change_pass()
|
||||
case "3":
|
||||
users = get_users()
|
||||
print("\n Usuarios \n----------")
|
||||
for user in users:
|
||||
print(" "+user)
|
||||
input("\nPresiona Enter para continuar")
|
||||
case "s":
|
||||
break
|
||||
case _:
|
||||
print("Debes ingresar una opción válida")
|
||||
input("Presiona enter para continuar")
|
60
final/fin04.py
Normal file
@ -0,0 +1,60 @@
|
||||
import tkinter as tk
|
||||
|
||||
def fin_04():
|
||||
"""Create a program that will display the following screen:
|
||||
+-------------------------------------------------+
|
||||
| ___________ ________________ |
|
||||
| Enter a number: |___________| |View Times Table||
|
||||
| ___________ |________________||
|
||||
| | | ________________ |
|
||||
| | | | Clear ||
|
||||
| | | |________________||
|
||||
| | | |
|
||||
| | | |
|
||||
| |___________| |
|
||||
|_________________________________________________|
|
||||
When the user enters a number in the first box and clicks on the "View
|
||||
Times Table" button it should show the times table in the list area.
|
||||
For instance, if the user entered 99 they would see the list as shown
|
||||
in the example on the right. The "Clear" button should clear both boxes."""
|
||||
com_bg = "dodger blue"
|
||||
window = tk.Tk()
|
||||
window.title("Tablas de Multiplicar")
|
||||
window.geometry("400x300")
|
||||
window["bg"] = com_bg
|
||||
|
||||
lbl_num = tk.Label(text="Ingresa un número:", font="Verdana 10")
|
||||
lbl_num["bg"] = com_bg
|
||||
lbl_num.place(x=20, y=20, width=130, height=30)
|
||||
|
||||
txt_in = tk.Entry()
|
||||
txt_in.place(x=150, y=20, width=120, height=30)
|
||||
|
||||
def view():
|
||||
num = txt_in.get()
|
||||
clear()
|
||||
if num.isdigit():
|
||||
num = int(num)
|
||||
for i in range(1,13):
|
||||
lst_table.insert('end', f"{i} x {num} = {i*num}")
|
||||
else:
|
||||
clear()
|
||||
|
||||
def clear():
|
||||
lst_table.delete(0, 'end')
|
||||
txt_in.delete(0, 'end')
|
||||
txt_in.focus()
|
||||
|
||||
btn_view = tk.Button(text="Ver tablas", width=100, height=30, command=view)
|
||||
btn_view.place(x=280, y=20, width=100, height=30)
|
||||
|
||||
lst_table = tk.Listbox()
|
||||
lst_table["justify"] = "left"
|
||||
lst_table.place(x=150, y=60, width=120 ,height=230)
|
||||
|
||||
btn_clear = tk.Button(text="Limpiar", width=100, height=30, command=clear)
|
||||
btn_clear.place(x=280, y=60, width=100, height=30)
|
||||
|
||||
txt_in.focus()
|
||||
|
||||
window.mainloop()
|
387
final/fin05.py
Normal file
@ -0,0 +1,387 @@
|
||||
from os import getcwd as pwd
|
||||
import tkinter as tk
|
||||
import sqlite3
|
||||
|
||||
|
||||
def fin_05():
|
||||
"""A small art gallery is selling works from different artists and wants to
|
||||
keep track of the paintings using an SQL database. You need to create a
|
||||
user-friendly system to keep track of the art. This should include using a
|
||||
GUI. Below is the current data that needs to be stored in a database.
|
||||
Artists Contact Details:
|
||||
|
||||
ArtistID Name Address Town Country Postcode
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
1 Martin Leighton 5 Park Place Peterborough Cambridgeshire PE32 5LP
|
||||
2 Eva Czariecka 77 Warner Close Chelmsford Essex CM22 5FT
|
||||
3 Roxy Parkin 90 Hindhead Road London SE12 6WM
|
||||
4 Nigel Farnworth 41 Whitby Road Huntly Aberdeenshire AB54 5PN
|
||||
5 Teresa Tanner 70 Guild Street London NW7 1SP
|
||||
|
||||
PieceID ArtistID Title Medium Price
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
1 5 Woman with black Labrador Oil 220
|
||||
2 5 Bees & thistles Watercolour 85
|
||||
3 2 A stroll to Westminster Ink 190
|
||||
4 1 African giant Oil 800
|
||||
5 3 Water daemon Acrylic 1700
|
||||
6 4 A seagull Watercolour 35
|
||||
7 1 Three friends Oil 1800
|
||||
8 2 Summer breeze 1 Acrylic 1350
|
||||
9 4 Mr Hamster Watercolour 35
|
||||
10 1 Pulpit Rock, Dorset Oil 600
|
||||
11 5 Trawler Dungeness beach Oil 195
|
||||
12 2 Dance in the snow Oil 250
|
||||
13 4 St Tropez port Ink 45
|
||||
14 3 Pirate assassin Acrylic 420
|
||||
15 1 Morning walk Oil 800
|
||||
16 4 A baby barn swallow Watercolour 35
|
||||
17 4 The old working mills Ink 395
|
||||
|
||||
The art gallery must be able to add new artists and pieces of art. Once a
|
||||
piece of art has been sold, the data about that art should be removed from
|
||||
the main SQL database and stored in a separate text file. Users should be
|
||||
able to search by artist, medium or price."""
|
||||
db_path = f"{pwd()}/final/files/artgallery.db"
|
||||
file_path = f"{pwd()}/final/files/art_sales.txt"
|
||||
|
||||
def exec_query(query, params=None):
|
||||
with sqlite3.connect(db_path) as db:
|
||||
cursor = db.cursor()
|
||||
if params is not None:
|
||||
result = cursor.execute(query, params)
|
||||
else:
|
||||
result = cursor.execute(query)
|
||||
db.commit()
|
||||
return result
|
||||
|
||||
def exec_queries(query, params):
|
||||
with sqlite3.connect(db_path) as db:
|
||||
cursor = db.cursor()
|
||||
result = cursor.executemany(query, params)
|
||||
db.commit()
|
||||
return result
|
||||
|
||||
def create_tables():
|
||||
query="""CREATE TABLE IF NOT EXISTS artists(
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
town TEXT,
|
||||
country TEXT NOT NULL,
|
||||
postcode TEXT NOT NULL)"""
|
||||
exec_query(query)
|
||||
query="""CREATE TABLE IF NOT EXISTS pieces(
|
||||
id INTEGER PRIMARY KEY,
|
||||
artistid INTEGER,
|
||||
title TEXT NOT NULL,
|
||||
medium TEXT NOT NULL,
|
||||
price FLOAT,
|
||||
FOREIGN KEY (artistid) REFERENCES artists(id))"""
|
||||
exec_query(query)
|
||||
|
||||
def populate_tables():
|
||||
query = """INSERT INTO artists(name, address, town, country, postcode)
|
||||
VALUES(?,?,?,?,?)"""
|
||||
artists = [
|
||||
('Martin Leighton', '5 Park Place', 'Peterborough', 'Cambridgeshire', 'PE32 5LP'),
|
||||
('Eva Czariecka', '77 Warner Close', 'Chelmsford', 'Essex', 'CM22 5FT'),
|
||||
('Roxy Parkin', '90 Hindhead Road', None, 'London', 'SE12 6WM'),
|
||||
('Nigel Farnworth', '41 Whitby Road', 'Huntly', 'Aberdeenshire', 'AB54 5PN'),
|
||||
('Teresa Tanner', '70 Guild Street', None ,'London', 'NW7 1SP')
|
||||
]
|
||||
exec_queries(query, artists)
|
||||
query = "INSERT INTO pieces(artistid, title, medium, price) VALUES(?,?,?,?)"
|
||||
pieces = [
|
||||
('5', 'Woman with black Labrador', 'Oil', 220),
|
||||
('5', 'Bees & thistles', 'Watercolour', 85),
|
||||
('2', 'A stroll to Westminster', 'Ink' , 190),
|
||||
('1', 'African giant', 'Oil', 800),
|
||||
('3', 'Water daemon', 'Acrylic', 1700),
|
||||
('4', 'A seagull', 'Watercolour', 35),
|
||||
('1', 'Three friends', 'Oil', 1800),
|
||||
('2', 'Summer breeze 1', 'Acrylic', 1350),
|
||||
('4', 'Mr Hamster', 'Watercolour', 35),
|
||||
('1', 'Pulpit Rock, Dorset', 'Oil', 600),
|
||||
('5', 'Trawler Dungeness beach', 'Oil', 195),
|
||||
('2', 'Dance in the snow', 'Oil', 250),
|
||||
('4', 'St Tropez port', 'Ink', 45),
|
||||
('3', 'Pirate assassin', 'Acrylic', 420),
|
||||
('1', 'Morning walk', 'Oil', 800),
|
||||
('4', 'A baby barn swallow', 'Watercolour', 35),
|
||||
('4', 'The old working mills', 'Ink', 395)
|
||||
]
|
||||
exec_queries(query, pieces)
|
||||
|
||||
def drop_tables():
|
||||
query = "DROP TABLE IF EXISTS pieces"
|
||||
exec_query(query)
|
||||
query = "DROP TABLE IF EXISTS artists"
|
||||
exec_query(query)
|
||||
|
||||
def add_artist(artist):
|
||||
query = """INSERT INTO artists (name, address, town, country, postcode)
|
||||
VALUES(?,?,?,?,?)"""
|
||||
exec_query(query, artist)
|
||||
|
||||
def add_piece(piece):
|
||||
query = """INSERT INTO pieces (artistid, title, medium, price)
|
||||
VALUES(?,?,?,?)"""
|
||||
exec_query(query, piece)
|
||||
|
||||
def del_piece(piece_id):
|
||||
query = "DELETE FROM pieces WHERE id=?"
|
||||
exec_query(query, [piece_id])
|
||||
|
||||
def sell_piece():
|
||||
piece = lst_out.get(tk.ANCHOR)
|
||||
try:
|
||||
piece_id = piece.split()[0]
|
||||
query = "SELECT * FROM pieces WHERE id=?"
|
||||
result = exec_query(query, [piece_id])
|
||||
data = result.fetchone()
|
||||
with open(file_path, 'a+') as file:
|
||||
file.write(f"{data[0]}, {data[1]}, {data[2]}, {data[3]}, {data[4]}\n")
|
||||
del_piece(piece_id)
|
||||
clean_tk()
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
def search_by_id(artistid):
|
||||
query = f"SELECT * FROM pieces WHERE artistid = ?"
|
||||
result = exec_query(query, str(artistid))
|
||||
data = result.fetchall()
|
||||
return data
|
||||
|
||||
def search_by_medium(medium):
|
||||
query = f"SELECT * FROM pieces WHERE medium LIKE ?"
|
||||
result = exec_query(query, ['%'+medium+'%'])
|
||||
data = result.fetchall()
|
||||
return data
|
||||
|
||||
def search_by_price(price):
|
||||
query = f"SELECT * FROM pieces WHERE price <= ?"
|
||||
result = exec_query(query, [price])
|
||||
data = result.fetchall()
|
||||
return data
|
||||
|
||||
def restart_data():
|
||||
drop_tables()
|
||||
create_tables()
|
||||
populate_tables()
|
||||
with open(file_path, 'w') as file:
|
||||
file.write('')
|
||||
#add_artist(("BOB", "Mi casa", None, "Taiwan", "06660"))
|
||||
#add_piece((6, "Su Casa", "Bic sobre cuaderno", 6666.666))
|
||||
#sell_piece(18)
|
||||
|
||||
restart_data()
|
||||
|
||||
com_bg = "dodger blue"
|
||||
alt_bg = "deep sky blue"
|
||||
window = tk.Tk()
|
||||
window.title("Galeria de Arte")
|
||||
window.geometry("800x600")
|
||||
window["bg"] = com_bg
|
||||
|
||||
lbl_artist_id = tk.Label(text="Id Artista", font="Verdana 12")
|
||||
lbl_artist_id.place(x=40, y=230, width=80, height=25)
|
||||
lbl_artist_id["bg"] = com_bg
|
||||
txt_artist_id = tk.Entry(font="Verdana 12")
|
||||
txt_artist_id["justify"] = "center"
|
||||
txt_artist_id.place(x=120, y=230, width=40, height=25)
|
||||
|
||||
lbl_piece_title = tk.Label(text="Titulo", font="Verdana 12")
|
||||
lbl_piece_title.place(x=40, y=270, width=60, height=25)
|
||||
lbl_piece_title['bg'] = com_bg
|
||||
txt_piece_title = tk.Entry(font="Verdana 12")
|
||||
txt_piece_title.place(x=100, y=270, width=400, height=25)
|
||||
|
||||
def add_art_piece():
|
||||
artist_id = txt_artist_id.get()
|
||||
if artist_id == '':
|
||||
txt_artist_id.focus()
|
||||
return
|
||||
title = txt_piece_title.get()
|
||||
if title == '':
|
||||
txt_piece_title.focus()
|
||||
return
|
||||
medium = txt_medium.get()
|
||||
if medium == '':
|
||||
txt_medium.focus()
|
||||
return
|
||||
price = txt_price.get()
|
||||
if price == '' or not price.isdigit():
|
||||
txt_price.delete(0, 'end')
|
||||
txt_price.focus()
|
||||
return
|
||||
clean_tk()
|
||||
add_piece((artist_id,title,medium,price))
|
||||
|
||||
btn_add_piece = tk.Button(text="Agregar Pieza",
|
||||
font="Verdana 12",
|
||||
command=add_art_piece)
|
||||
btn_add_piece['bg'] = alt_bg
|
||||
btn_add_piece.place(x=510, y=270, width=250, height=25)
|
||||
|
||||
def display_artists():
|
||||
query = "SELECT * FROM artists"
|
||||
data = exec_query(query)
|
||||
lst_out.delete(0, 'end')
|
||||
for art in data:
|
||||
artist_id = (str(art[0]).rjust(3)).ljust(5)
|
||||
name = (art[1].rjust(15)).ljust(20)
|
||||
address = art[2].rjust(20)
|
||||
town = art[3].rjust(20) if art[3] is not None else " "
|
||||
country = art[4].rjust(20)
|
||||
postcode = art[5].rjust(20)
|
||||
line = artist_id+name+address+town+country+postcode
|
||||
lst_out.insert('end', line)
|
||||
|
||||
def display_pieces(data):
|
||||
lst_out.delete(0, 'end')
|
||||
for art in data:
|
||||
piece_id = (str(art[0]).rjust(5)).ljust(8)
|
||||
artist_id = (str(art[1]).rjust(5)).ljust(8)
|
||||
title = art[2].rjust(40)
|
||||
medium = art[3].rjust(20)
|
||||
price = str(art[4]).rjust(20)
|
||||
line = piece_id+artist_id+title+medium+price
|
||||
lst_out.insert('end', line)
|
||||
|
||||
def search():
|
||||
search_by = sel_by.get()
|
||||
lst_out.delete(0, 'end')
|
||||
match search_by:
|
||||
case 'ID Artista':
|
||||
artistid = txt_artist_id.get()
|
||||
if artistid.isdigit():
|
||||
data = search_by_id(artistid)
|
||||
display_pieces(data)
|
||||
case 'Material':
|
||||
medium = txt_medium.get()
|
||||
data = search_by_medium(medium)
|
||||
display_pieces(data)
|
||||
case 'Precio':
|
||||
price = txt_price.get()
|
||||
data = search_by_price(price)
|
||||
display_pieces(data)
|
||||
case _:
|
||||
lst_by.focus()
|
||||
|
||||
btn_find = tk.Button(text="Buscar por", font="Verdana 12", command=search)
|
||||
btn_find.place(x=510, y=230, width=135, height=25)
|
||||
btn_find['bg'] = alt_bg
|
||||
|
||||
sel_by = tk.StringVar(window)
|
||||
sel_by.set("------------")
|
||||
by_ops = [ 'ID Artista', 'Material', 'Precio' ]
|
||||
lst_by = tk.OptionMenu(window, sel_by, *by_ops)
|
||||
lst_by.place(x=645, y=230, width=115, height=25)
|
||||
lst_by['bg'] = alt_bg
|
||||
|
||||
lbl_medium = tk.Label(text="Material", font="Verdana 12")
|
||||
lbl_medium['bg'] = com_bg
|
||||
lbl_medium.place(x=160, y=230, width=80, height=25)
|
||||
txt_medium = tk.Entry(font="Verdana 12")
|
||||
txt_medium["justify"] = "center"
|
||||
txt_medium.place(x=240, y=230, width=120, height=25)
|
||||
|
||||
lbl_price = tk.Label(text="Precio <", font="Verdana 12")
|
||||
lbl_price['bg'] = com_bg
|
||||
lbl_price.place(x=370, y=230, width=70, height=25)
|
||||
txt_price = tk.Entry(font="Verdana 12")
|
||||
txt_price["justify"] = "center"
|
||||
txt_price.place(x=440, y=230, width=60, height=25)
|
||||
|
||||
btn_showall = tk.Button(text="Mostrar todos los artistas",
|
||||
font="Verdana 12",
|
||||
command=display_artists)
|
||||
btn_showall['bg'] = alt_bg
|
||||
btn_showall.place(x=510, y=190, width=250, height=25)
|
||||
|
||||
lst_out = tk.Listbox(font="Verdana 12")
|
||||
lst_out["justify"] = "left"
|
||||
lst_out["bg"] = "tomato"
|
||||
lst_out.place(x=40, y=310, width=720, height=280)
|
||||
|
||||
def new_artist():
|
||||
name = txt_in_name.get()
|
||||
if name == '':
|
||||
txt_in_name.focus()
|
||||
return
|
||||
addrs = txt_in_adrs.get()
|
||||
if addrs == '':
|
||||
txt_in_adrs.focus()
|
||||
return
|
||||
town = txt_in_town.get() #opt
|
||||
country = txt_in_country.get()
|
||||
if country == '':
|
||||
txt_in_country.focus()
|
||||
return
|
||||
postal = txt_in_code.get()
|
||||
if country == '':
|
||||
txt_in_code.focus()
|
||||
return
|
||||
new_artist = (name, addrs, town, country, postal)
|
||||
add_artist(new_artist)
|
||||
clean_tk()
|
||||
|
||||
lbl_title = tk.Label(text="Gestion de Artistas y Obras")
|
||||
lbl_title['bg'] = com_bg
|
||||
lbl_title['font'] = "Verdana 30"
|
||||
lbl_title.place(x=120, y=10, width=550, height=80)
|
||||
y1 = 100
|
||||
y2 = y1+(y1/2)
|
||||
x1 = 40
|
||||
lbl_art_name = tk.Label(text="Nombre", font="Verdana 12")
|
||||
lbl_art_name.place(x=x1, y=y1, width=70, height=25)
|
||||
lbl_art_name['bg'] = com_bg
|
||||
txt_in_name = tk.Entry(font="Verdana 12")
|
||||
txt_in_name.place(x=x1+70, y=y1, width=220, height=25)
|
||||
lbl_art_adrs = tk.Label(text="Dirección", font="Verdana 12")
|
||||
lbl_art_adrs['bg'] = com_bg
|
||||
lbl_art_adrs.place(x=340, y=y1, width=70, height=25)
|
||||
txt_in_adrs = tk.Entry(font="Verdana 12")
|
||||
txt_in_adrs.place(x=420, y=y1, width=340, height=25)
|
||||
lbl_art_town = tk.Label(text="Ciudad", font="Verdana 12")
|
||||
lbl_art_town['bg'] = com_bg
|
||||
lbl_art_town.place(x=x1, y=y2, width=80, height=25)
|
||||
txt_in_town = tk.Entry(font="Verdana 12")
|
||||
txt_in_town.place(x=x1+70, y=y2, width=180, height=25)
|
||||
lbl_art_country = tk.Label(text="Región", font="Verdana 12")
|
||||
lbl_art_country['bg'] = com_bg
|
||||
lbl_art_country.place(x=x1+260, y=y2, width=70, height=25)
|
||||
txt_in_country = tk.Entry(font="Verdana 12")
|
||||
txt_in_country.place(x=x1+330, y=y2, width=160, height=25)
|
||||
lbl_art_code = tk.Label(text="Cod. Postal", font="Verdana 12")
|
||||
lbl_art_code['bg'] = com_bg
|
||||
lbl_art_code.place(x=540, y=y2, width=90, height=25)
|
||||
txt_in_code = tk.Entry(font="Verdana 12")
|
||||
txt_in_code.place(x=630, y=y2, width=130, height=25)
|
||||
|
||||
btn_add_art = tk.Button(text="Agregar artista",
|
||||
font="Verdana 12",
|
||||
command=new_artist)
|
||||
btn_add_art["bg"] = alt_bg
|
||||
btn_add_art.place(x=x1, y=190, width=250, height=25)
|
||||
|
||||
btn_del_art = tk.Button(text="Vender pieza",
|
||||
font="Verdana 12",
|
||||
command=sell_piece)
|
||||
btn_del_art["bg"] = alt_bg
|
||||
btn_del_art.place(x=280, y=190, width=250, height=25)
|
||||
|
||||
def clean_tk():
|
||||
txt_in_name.delete(0,'end')
|
||||
txt_in_adrs.delete(0,'end')
|
||||
txt_in_town.delete(0,'end')
|
||||
txt_in_country.delete(0,'end')
|
||||
txt_in_code.delete(0,'end')
|
||||
lst_out.delete(0, 'end')
|
||||
txt_artist_id.delete(0,'end')
|
||||
txt_piece_title.delete(0,'end')
|
||||
txt_medium.delete(0,'end')
|
||||
txt_price.delete(0,'end')
|
||||
|
||||
window.mainloop()
|
47
final/final.py
Normal file
@ -0,0 +1,47 @@
|
||||
from . import (
|
||||
fin01 as ex01,
|
||||
fin02 as ex02,
|
||||
fin03 as ex03,
|
||||
fin04 as ex04,
|
||||
fin05 as ex05
|
||||
)
|
||||
|
||||
from common.common import (
|
||||
user_input,
|
||||
run_func,
|
||||
print_run_func,
|
||||
opcs_default,
|
||||
clear
|
||||
)
|
||||
|
||||
tab = ' '
|
||||
|
||||
def challenges():
|
||||
select_ok = False
|
||||
while not select_ok:
|
||||
clear()
|
||||
print(tab, '1)', "Shift Code #146")
|
||||
print(tab, '2)', "Mastermind #147")
|
||||
print(tab, '3)', "Passwords #148")
|
||||
print(tab, '4)', "Times Tables GUI #149")
|
||||
print(tab, '5)', "Art Gallery #150")
|
||||
opcs_default(1)
|
||||
selection = user_input(9)
|
||||
match selection:
|
||||
case 1:
|
||||
run_func(ex01.fin_01)
|
||||
case 2:
|
||||
run_func(ex02.fin_02)
|
||||
case 3:
|
||||
print_run_func(ex03.fin_03)
|
||||
case 4:
|
||||
print_run_func(ex04.fin_04)
|
||||
case 5:
|
||||
print_run_func(ex05.fin_05)
|
||||
case 'v':
|
||||
return
|
||||
case 's':
|
||||
select_ok = True
|
||||
exit(0)
|
||||
case _:
|
||||
continue
|
13
images.md
Normal file
@ -0,0 +1,13 @@
|
||||
![img](./imgs/basics_001-059.png)
|
||||
![img](./imgs/final_146-150.png)
|
||||
![img](./imgs/final_150.png)
|
||||
![img](./imgs/interm_069-123.png)
|
||||
![img](./imgs/main_menu.png)
|
||||
![img](./imgs/pattern_067.png)
|
||||
![img](./imgs/sqlite_145.png)
|
||||
![img](./imgs/tkinter_124-138.png)
|
||||
![img](./imgs/tkinter125.png)
|
||||
![img](./imgs/tkinter_128.png)
|
||||
![img](./imgs/tkinter_134.png)
|
||||
![img](./imgs/tkinter_138.png)
|
||||
![img](./imgs/turtle_060-068.png)
|
BIN
imgs/basics_001-059.png
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
imgs/final_146-150.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
imgs/final_150.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
imgs/interm_069-123.png
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
imgs/main_menu.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
imgs/sqlite_145.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
imgs/tkinter125.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
imgs/tkinter_124-138.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
imgs/tkinter_128.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
imgs/tkinter_134.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
imgs/tkinter_138.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
imgs/turtle_060-068.png
Normal file
After Width: | Height: | Size: 351 KiB |
@ -2,14 +2,12 @@ class interm004:
|
||||
|
||||
def two_d(self):
|
||||
"""Create the following using a simple 2D list using the standard Python
|
||||
indexing
|
||||
- 0 1 2
|
||||
indexing - 0 1 2
|
||||
━━━━━━━━━━━━━━━
|
||||
0 2 5 8
|
||||
1 3 7 4
|
||||
2 1 6 9
|
||||
3 4 2 0
|
||||
"""
|
||||
3 4 2 0"""
|
||||
bidims = [[2,5,8],[3,7,4],[1,6,9],[4,2,0]]
|
||||
print(" | 0 | 1 | 2 |\n━━━━━━━━━━━━━━━")
|
||||
for i in range(len(bidims)):
|
||||
|
@ -1,9 +1,9 @@
|
||||
class interm007:
|
||||
|
||||
def sub_118(self):
|
||||
"""Define a subprogram that will ask the user to enter a number and
|
||||
save it as the variable \'num\'. Define another subprogram that will
|
||||
use \'num\' and count from 1 to that number."""
|
||||
"""Define a subprogram that will ask the user to enter a number and save
|
||||
it as the variable 'num'. Define another subprogram that will use 'num'
|
||||
and count from 1 to that number."""
|
||||
def save_num():
|
||||
return int(input("Ingresa un número: "))
|
||||
|
||||
@ -16,15 +16,13 @@ class interm007:
|
||||
def sub_119(self):
|
||||
"""Define a subprogram that will ask the user to pick a low and a high
|
||||
number, and then generate a random number between those two values and
|
||||
store it in a variable called \'comp_num\'.
|
||||
Define another subprogram that will give the instruction \'I am thinking
|
||||
of a number…\' and then ask the user to guess the number they are
|
||||
thinking of.
|
||||
Define a third subprogram that will check to see if the comp_num is the
|
||||
same as the user's guess. If it is, it should display the message
|
||||
\'Correct, you win\', otherwise it should keep looping, telling the user
|
||||
if they are too low or too high and asking them to guess again until they
|
||||
guess correctly."""
|
||||
store it in a variable called 'comp_num'. Define another subprogram that
|
||||
will give the instruction 'I am thinking of a number…' and then ask the
|
||||
user to guess the number they are thinking of. Define a third subprogram
|
||||
that will check to see if the comp_num is the same as the user's guess.
|
||||
If it is, it should display the message 'Correct, you win', otherwise it
|
||||
should keep looping, telling the user if they are too low or too high
|
||||
and asking them to guess again until they guess correctly."""
|
||||
from random import randint
|
||||
def num_gen():
|
||||
ini = int(input("Ingresa un número inicial: "))
|
||||
@ -50,25 +48,21 @@ class interm007:
|
||||
check_nums(secret, guess)
|
||||
|
||||
def sub_120(self):
|
||||
"""Display the following menu to the user:
|
||||
1) Addition
|
||||
"""Display the following menu to the user: 1) Addition
|
||||
2) Subtraction
|
||||
Enter 1 or 2:
|
||||
If they enter a 1, it should run a subprogram that will generate two
|
||||
random numbers between 5 and 20, and ask the user to add them together.
|
||||
Work out the correct answer and return both the user's answer and the
|
||||
correct answer.
|
||||
If they entered 2 as their selection on the menu, it should run a
|
||||
subprogram that will generate one number between 25 and 50 and another
|
||||
number between 1 and 25 and ask them to work out num1 minus num2. This
|
||||
way they will not have to worry about negative answers. Return both the
|
||||
user's answer and the correct answer.
|
||||
Create another subprogram that will check if the user's answer matches
|
||||
the actual answer. If it does, display \'Correct\', otherwise display a
|
||||
message that will say \'Incorrect, the answer is\' and display the real
|
||||
answer.
|
||||
If they do not select a relevant option on the first menu you should
|
||||
display a suitable message."""
|
||||
correct answer. If they entered 2 as their selection on the menu, it
|
||||
should run a subprogram that will generate one number between 25 and 50
|
||||
and another number between 1 and 25 and ask them to work out num1 minus
|
||||
num2. This way they will not have to worry about negative answers. Return
|
||||
both the user's answer and the correct answer. Create another subprogram
|
||||
that will check if the user's answer matches the actual answer. If it
|
||||
does, display 'Correct', otherwise display a message that will say
|
||||
'Incorrect, the answer is' and display the real answer. If they do not
|
||||
select a relevant option on the menu you should display a suitable message."""
|
||||
from random import randint
|
||||
def menu():
|
||||
print(
|
||||
@ -170,8 +164,7 @@ class interm007:
|
||||
menu()
|
||||
|
||||
def sub_122(self):
|
||||
"""Create the following menu:
|
||||
1) Add to file
|
||||
"""Create the following menu: 1) Add to file
|
||||
2) View all records
|
||||
3) Quit program
|
||||
Enter the number of your selection:
|
||||
@ -229,14 +222,8 @@ class interm007:
|
||||
"""In Python, it is not technically possible to directly delete a record
|
||||
from a .csv file. Instead you need to save the file to a temporary list
|
||||
in Python, make the changes to the list and then overwrite the original
|
||||
file with the temporary list.
|
||||
Change the previous program to allow you to do this. Your menu should
|
||||
now look like this:
|
||||
1) Add to file
|
||||
2) View all records
|
||||
3) Delete a record
|
||||
4) Quit program
|
||||
Enter the number of your selection:"""
|
||||
file with the temporary list. Change the previous program to allow you to
|
||||
do this. Your menu should have the new option: 3) Delete a record"""
|
||||
from os import getcwd as pwd
|
||||
from os.path import isfile
|
||||
import csv
|
||||
|
4
main.py
@ -5,6 +5,7 @@ from trtl import trtl
|
||||
from interm import interm
|
||||
from tkgui import tkgui
|
||||
from sqlite import sqlite
|
||||
from final import final
|
||||
from common.common import clear, user_input, opcs_default
|
||||
|
||||
def toc():
|
||||
@ -147,8 +148,7 @@ def main():
|
||||
case 5:
|
||||
sqlite.challenges()
|
||||
case 6:
|
||||
#final_challenges()
|
||||
pass
|
||||
final.challenges()
|
||||
case 's':
|
||||
select_ok = True
|
||||
exit(0)
|
||||
|