V oni stari nalogi imamo dva vrča; v vrč a
gre 7 litrov
in v vrč b
gredo 4 litri. Vodo lahko točimo:
Naloga običajno zahteva, da z vrčema namerimo določeno količino vode, na primer dva litra. Naša ni takšna.
Tole je skoraj bolj naloga iz pogojev kot iz zank.
Zaporedje pretakanj naj bo podano takole (te vrstice skopiraj na začetek programa):
poteze = [("j", "a"), ("a", "b"), ("b", "j"), ("a", "b"), ("j", "a"),
("a", "b"), ("b", "j"), ("a", "b"), ("a", "j"), ("b", "a"),
("j", "a"), ("a", "j")]
Pri tem prvi element para pove, odkod točimo, drugi pa, kam. Napiši program, ki simulira takšno pretakanje in sproti poroča, koliko vode je v katerem vrču. Za gornji primer mora izpisati:
a: 7 b: 0
a: 3 b: 4
a: 3 b: 0
a: 0 b: 3
a: 7 b: 3
a: 6 b: 4
a: 6 b: 0
a: 2 b: 4
a: 0 b: 4
a: 4 b: 0
a: 7 b: 0
a: 0 b: 0
Zelo malo imamo komentirati.
a
in b
.for odkod, kam in poteze
; odkod
in
kam
lahko seveda poimenujemo drugače, bistveno je, da gremo
čez seznam parov in ga razpakiramo v dve spremenljivk.if odkod == "a" and kam == "b"
, ali pa ločenima gnezdenima
pogojema, if odkod == "a"
in znotraj tega
if kam == "b"
. Spodnji program uporablja slednje.if
.else
sem v komentar, ki mu sledi,
dopisal, kateri primer pokriva. To je dobra praksa, ki poveča čitljivost
programa.= [("r", "a"), ("a", "b"), ("b", "j"), ("a", "b"), ("j", "a"), ("a", "b"),
poteze "b", "j"), ("a", "b"), ("a", "j"), ("b", "a"), ("j", "a"), ("a", "j")]
(
= b = 0
a for odkod, kam in poteze:
if odkod == "a":
if kam == "b":
if b + a > 4:
-= 4 - b
a = 4
b else:
+= a
b = 0
a else:
= 0
a elif odkod == "b":
if kam == "a":
if b + a > 7:
-= 7 - a
b = 7
a else:
+= b
a = 0
b else:
= 0
b else: # odkod == "j"
if kam == "a":
= 7
a else: # kam == "b"
= 4
b print("a:", a, "b:", b)
a: 7 b: 0
a: 3 b: 4
a: 3 b: 0
a: 0 b: 3
a: 7 b: 3
a: 6 b: 4
a: 6 b: 0
a: 2 b: 4
a: 0 b: 4
a: 4 b: 0
a: 7 b: 0
a: 0 b: 0
Se da kaj poenostaviti? Pogojev pri pretakanju med posodama se da
izogniti z uporabo funkcije min
: pretočimo toliko, kolikor
je v a
ali toliko, kolikor gre v b
, kar je pač
manjše.
= [("r", "a"), ("a", "b"), ("b", "j"), ("a", "b"), ("j", "a"), ("a", "b"),
poteze "b", "j"), ("a", "b"), ("a", "j"), ("b", "a"), ("j", "a"), ("a", "j")]
(
= b = 0
a for odkod, kam in poteze:
if odkod == "a":
if kam == "b":
= min(a, 4 - b)
kolicina = a - kolicina, b + kolicina
a, b else:
= 0
a elif odkod == "b":
if kam == "a":
= min(b, 7 - a)
kolicina = a + kolicina, b - kolicina
a, b else:
= 0
b else: # odkod == "j"
if kam == "a":
= 7
a else: # kam == "b"
= 4
b print("a:", a, "b:", b)
a: 7 b: 0
a: 3 b: 4
a: 3 b: 0
a: 0 b: 3
a: 7 b: 3
a: 6 b: 4
a: 6 b: 0
a: 2 b: 4
a: 0 b: 4
a: 4 b: 0
a: 7 b: 0
a: 0 b: 0
Morda pa je preprosteje, če obravnavamo posamične primere brez gnezdenja pogojev? In celo če, v nasprotju z vsem, kar poskušam študentom vbiti v glavo, ne razpakiramo terke?
= b = 0
a for poteza in poteze:
if poteza == ("j", "a"):
= 7
a if poteza == ("j", "b"):
= 7
b if poteza == ("a", "j"):
= 0
a if poteza == ("b", "j"):
= 0
b if poteza == ("a", "b"):
= a - min(a, 4 - b), b + min(a, 4 - b)
a, b if poteza == ("b", "a"):
= a + min(b, 7 - a), b - min(b, 7 - a)
a, b print("a:", a, "b:", b)
a: 0 b: 0
a: 0 b: 0
a: 0 b: 0
a: 0 b: 0
a: 7 b: 0
a: 3 b: 4
a: 3 b: 0
a: 0 b: 3
a: 0 b: 3
a: 3 b: 0
a: 7 b: 0
a: 0 b: 0
Hm, pravzaprav je bilo tole res preprosteje.
V Pythonu 3.10 pa lahko uporabimo novi stavek match
, ki
program še malo skrajša.
= b = 0
a for poteza in poteze:
match poteza:
case "j", "a":
= 7
a case "j", "b":
= 7
b case "a", "j":
= 0
a case "b", "j":
= 0
b case "a", "b":
= a - min(a, 4 - b), b + min(a, 4 - b)
a, b case "b", "a":
= a + min(b, 7 - a), b - min(b, 7 - a)
a, b print("a:", a, "b:", b)
a: 0 b: 0
a: 0 b: 0
a: 0 b: 0
a: 0 b: 0
a: 7 b: 0
a: 3 b: 4
a: 3 b: 0
a: 0 b: 3
a: 0 b: 3
a: 3 b: 0
a: 7 b: 0
a: 0 b: 0
Zdaj pa obratno: imamo zaporedje stanj vrčev, podanih s seznamom terk, na primer.
stanja = [(7, 0), (3, 4), (3, 0), (0, 3), (7, 3), (6, 4),
(6, 0), (2, 4), (0, 4), (4, 0), (7, 0), (0, 0)]
Napiši program, ki za takšno zaporedje izpiše pripadajoči vrstni red pretakanj. Izpis naj bo v takšni obliki:
j a
a b
b j
a b
j a
a b
b j
a b
a j
b a
j a
a j
Osnovna ideja je, da moramo primerjati prejšnje in novo stanje ter izpisati ustrezno spremembo.
= [(7, 0), (3, 4), (3, 0), (0, 3), (7, 3), (6, 4), (6, 0), (2, 4), (0, 4), (4, 0), (7, 0), (0, 0)]
seq = b = 0
a
for na, nb in seq: # na in nb sta novi a in novi b
if a == na: # a je ostal enak, nekaj se dogaja z b
if nb == 0:
print("b j")
else:
print("j b")
elif b == nb: # b je ostal enak, nekaj se dogaja z a
if na == 0:
print("a j")
else:
print("j a")
else: # sicer točimo med posodama
if na > a: # količina v a se je povečala ...
print("b a")
else:
print("a b")
= na, nb a, b
j a
a b
b j
a b
j a
a b
b j
a b
a j
b a
j a
a j