24 game/Solve: Difference between revisions

Line 6,832:
[8, 7, 9, 7] : No solution found
[9, 4, 4, 5] : No solution found</pre>
 
===Python: using tkinter===
 
<lang python>
''' Python 3.6.5 code using Tkinter graphical user interface.
Combination of '24 game' and '24 game/Solve'
allowing user or random selection of 4-digit number
and user or computer solution.
Note that all computer solutions are displayed'''
 
from tkinter import *
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
# 'from tkinter import scrolledtext' in later versions?
import random
import itertools
 
# ************************************************
 
class Game:
def __init__(self, gw):
self.window = gw
self.digits = '0000'
 
a1 = "(Enter '4 Digits' & click 'My Digits'"
a2 = "or click 'Random Digits')"
self.msga = a1 + '\n' + a2
 
b1 = "(Enter 'Solution' & click 'Check Solution'"
b2 = "or click 'Show Solutions')"
self.msgb = b1 + '\n' + b2
 
# top frame:
self.top_fr = Frame(gw,
width=600,
height=100,
bg='dodger blue')
self.top_fr.pack(fill=X)
 
self.hdg = Label(self.top_fr,
text=' 21 Game ',
font='arial 22 bold',
fg='navy',
bg='lemon chiffon')
self.hdg.place(relx=0.5, rely=0.5,
anchor=CENTER)
 
self.close_btn = Button(self.top_fr,
text='Quit',
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.close_window)
self.close_btn.place(relx=0.07, rely=0.5,
anchor=W)
 
self.clear_btn = Button(self.top_fr,
text='Clear',
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.clear_screen)
self.clear_btn.place(relx=0.92, rely=0.5,
anchor=E)
 
# bottom frame:
self.btm_fr = Frame(gw,
width=600,
height=500,
bg='lemon chiffon')
self.btm_fr.pack(fill=X)
self.msg = Label(self.btm_fr,
text=self.msga,
font='arial 16 bold',
fg='navy',
bg='lemon chiffon')
self.msg.place(relx=0.5, rely=0.1,
anchor=CENTER)
 
self.user_dgt_btn = Button(self.btm_fr,
text='My Digits',
width=12,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.get_digits)
self.user_dgt_btn.place(relx=0.07, rely=0.2,
anchor=W)
 
self.rdm_dgt_btn = Button(self.btm_fr,
text='Random Digits',
width=12,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.gen_digits)
self.rdm_dgt_btn.place(relx=0.92, rely=0.2,
anchor=E)
 
self.dgt_fr = LabelFrame(self.btm_fr,
text=' 4 Digits ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.dgt_fr.place(relx=0.5, rely=0.27,
anchor=CENTER)
 
self.digit_ent = Entry(self.dgt_fr,
justify='center',
font='arial 16 bold',
fg='navy',
disabledforeground='navy',
bg='lemon chiffon',
disabledbackground='lemon chiffon',
bd=4,
width=6)
self.digit_ent.grid(row=0, column=0,
padx=(8,8),
pady=(8,8))
self.chk_soln_btn = Button(self.btm_fr,
text='Check Solution',
state='disabled',
width=14,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.check_soln)
self.chk_soln_btn.place(relx=0.07, rely=.42,
anchor=W)
 
self.show_soln_btn = Button(self.btm_fr,
text='Show Solutions',
state='disabled',
width=14,
bd=5,
bg='navy',
fg='lemon chiffon',
font='arial 12 bold',
command=self.show_soln)
self.show_soln_btn.place(relx=0.92, rely=.42,
anchor=E)
 
self.soln_fr = LabelFrame(self.btm_fr,
text=' Solution ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.soln_fr.place(relx=0.07, rely=0.58,
anchor=W)
 
self.soln_ent = Entry(self.soln_fr,
justify='center',
font='arial 16 bold',
fg='navy',
disabledforeground='navy',
bg='lemon chiffon',
disabledbackground='lemon chiffon',
state='disabled',
bd=4,
width=15)
self.soln_ent.grid(row=0, column=0,
padx=(8,8), pady=(8,8))
 
self.solns_fr = LabelFrame(self.btm_fr,
text=' Solutions ',
bg='dodger blue',
fg='navy',
bd=4,
relief=RIDGE,
font='arial 12 bold')
self.solns_fr.place(relx=0.92, rely=0.5,
anchor='ne')
 
self.solns_all = ScrolledText(self.solns_fr,
font='courier 14 bold',
state='disabled',
fg='navy',
bg='lemon chiffon',
height=8,
width=14)
self.solns_all.grid(row=0, column=0,
padx=(8,8), pady=(8,8))
 
# validate '4 Digits' entry.
# save if valid and switch screen to solution mode.
def get_digits(self):
txt = self.digit_ent.get()
if not(len(txt) == 4 and txt.isdigit()):
self.err_msg('Please enter 4 digits (eg 1357)')
return
self.digits = txt # save
self.reset_one() # to solution mode
return
 
# generate 4 random digits, display them,
# save them, and switch screen to solution mode.
def gen_digits(self):
self.digit_ent.delete(0, 'end')
self.digits = ''.join([random.choice('123456789')
for i in range(4)])
self.digit_ent.insert(0, self.digits) # display
self.reset_one() # to solution mode
return
 
# switch screen from get digits to solution mode:
def reset_one(self):
self.digit_ent.config(state='disabled')
self.user_dgt_btn.config(state='disabled')
self.rdm_dgt_btn.config(state='disabled')
self.msg.config(text=self.msgb)
self.chk_soln_btn.config(state='normal')
self.show_soln_btn.config(state='normal')
self.soln_ent.config(state='normal')
return
 
# edit user's solution:
def check_soln(self):
txt = self.soln_ent.get() # user's expression
d = '' # save digits in expression
dgt_op = 'd' # expecting d:digit or o:operation
for t in txt:
if t not in '123456789+-*/() ':
self.err_msg('Invalid character found: ' + t)
return
if t.isdigit():
if dgt_op == 'd':
d += t
dgt_op = 'o'
else:
self.err_msg('Need operator between digits')
return
if t in '+-*/':
if dgt_op == 'o':
dgt_op = 'd'
else:
self.err_msg('Need digit befor operator')
return
if sorted(d) != sorted(self.digits):
self.err_msg("Use each digit in '4 Digits' once")
return
try:
# round covers up Python's
# representation of floats
if round(eval(txt),5) == 24:
messagebox.showinfo(
'Success',
'YOUR SOLUTION IS VADLID!')
self.show_soln() # show all solutions
return
except:
self.err_msg('Invalid arithmetic expression')
return
messagebox.showinfo(
'Failure',
'Your expression does not yield 24')
return
 
# show all solutions:
def show_soln(self):
# get all sets of 3 operands: ('+', '+', '*'), ...)
ops = ['+-*/', '+-*/', '+-*/']
combs = [p for p in itertools.product(*ops)]
# get unique permutations for requested 4 digits:
d = self.digits
perms = set([''.join(p) for p in itertools.permutations(d)])
 
# list of all (hopefully) expressions for
# 4 operands and 3 operations:
formats = ['Aop1Bop2Cop3D',
'(Aop1Bop2C)op3D',
'((Aop1B)op2C)op3D',
'(Aop1(Bop2C))op3D',
'Aop1Bop2(Cop3D)',
'Aop1(Bop2C)op3D',
'(Aop1B)op2Cop3D',
'(Aop1B)op2(Cop3D)',
'Aop1(Bop2Cop3D)',
'Aop1((Bop2C)op3D)',
'Aop1(Bop2(Cop3D))']
 
lox = [] # list of valid expressions
for fm in formats: # pick a format
for c in combs: # plug in 3 ops
f = fm.replace('op1', c[0])
f = f.replace('op2', c[1])
f = f.replace('op3', c[2])
for A, B, C, D in perms: # plug in 4 digits
x = f.replace('A', A)
x = x.replace('B', B)
x = x.replace('C', C)
x = x.replace('D', D)
try: # evaluate expression
# round covers up Python's
# representation of floats
if round(eval(x),5) == 24:
lox.append(' ' + x)
except ZeroDivisionError: # can ignore these
continue
if lox:
txt = '\n'.join(x for x in lox)
else:
txt =' No Solution'
self.solns_all.config(state='normal')
self.solns_all.insert('end', txt) # show solutions
self.solns_all.config(state='disabled')
 
self.chk_soln_btn.config(state='disabled')
self.show_soln_btn.config(state='disabled')
self.soln_ent.config(state='disabled')
return
 
def err_msg(self, msg):
messagebox.showerror('Error Message', msg)
return
 
# restore screen to it's 'initial' state:
def clear_screen(self):
self.digits = ''
self.digit_ent.config(state='normal')
self.user_dgt_btn.config(state='normal')
self.rdm_dgt_btn.config(state='normal')
self.digit_ent.delete(0, 'end')
self.chk_soln_btn.config(state='disabled')
self.show_soln_btn.config(state='disabled')
self.soln_ent.config(state='normal')
self.soln_ent.delete(0, 'end')
self.soln_ent.config(state='disabled')
self.msg.config(text=self.msga)
self.clear_solns_all()
return
 
# clear the 'Solutions' frame.
# note: state must be 'normal' to change data
def clear_solns_all(self):
self.solns_all.config(state='normal')
self.solns_all.delete(1.0, 'end')
self.solns_all.config(state='disabled')
return
def close_window(self):
self.window.destroy()
 
# ************************************************
 
root = Tk()
root.title('24 Game')
root.geometry('600x600+100+50')
root.resizable(False, False)
g = Game(root)
root.mainloop()
</lang>
 
=={{header|R}}==