diff options
Diffstat (limited to 'python/problems')
-rw-r--r-- | python/problems/recursion/binary/common.py | 75 | ||||
-rw-r--r-- | python/problems/recursion/binary/en.py | 13 | ||||
-rw-r--r-- | python/problems/recursion/binary/sl.py | 30 | ||||
-rw-r--r-- | python/problems/recursion/factorial/common.py | 75 | ||||
-rw-r--r-- | python/problems/recursion/factorial/en.py | 13 | ||||
-rw-r--r-- | python/problems/recursion/factorial/sl.py | 37 | ||||
-rw-r--r-- | python/problems/recursion/sum/common.py | 70 | ||||
-rw-r--r-- | python/problems/recursion/sum/en.py | 13 | ||||
-rw-r--r-- | python/problems/recursion/sum/sl.py | 32 | ||||
-rw-r--r-- | python/problems/while_and_if/conditions_sl.html | 159 | ||||
-rw-r--r-- | python/problems/while_and_if/ifclause_sl.html | 330 | ||||
-rw-r--r-- | python/problems/while_and_if/loops_sl.html | 179 | ||||
-rw-r--r-- | python/problems/while_and_if/sl.py | 4 |
13 files changed, 1029 insertions, 1 deletions
diff --git a/python/problems/recursion/binary/common.py b/python/problems/recursion/binary/common.py new file mode 100644 index 0000000..585c5ff --- /dev/null +++ b/python/problems/recursion/binary/common.py @@ -0,0 +1,75 @@ +import re +from python.util import has_token_sequence, string_almost_equal, \ + string_contains_number, get_tokens, get_numbers, get_exception_desc, \ + all_tokens, has_comprehension, has_loop, almost_equal, get_ast +from server.hints import Hint + +id = 20808 +number = 8 +visible = True + +solution = '''\ +def binary(n): + if n <= 1: + return str(n) + return binary(n // 2) + str(n % 2) +''' + +hint_type = { + 'final_hint': Hint('final_hint'), + 'has_loop': Hint('has_loop') +} + +def test(python, code, aux_code=''): + func_name = 'binary' + tokens = get_tokens(code) + ast = get_ast(code) + if not has_token_sequence(tokens, ['def', func_name]): + return False, [{'id' : 'no_func_name', 'args' : {'func_name' : func_name}}] + + in_out = [ + (3, '11'), + (2, '10'), + (1, '1'), + (0, '0'), + (42, '101010') + ] + + test_in = [('{0}({1})'.format(func_name, str(l[0])), None) + for l in in_out] + test_out = [l[1] for l in in_out] + + answers = python(code=aux_code+code, inputs=test_in, timeout=1.0) + n_correct = 0 + tin, tout = None, None + for i, (ans, to) in enumerate(zip(answers, test_out)): + res = ans[0] + corr = res == to + n_correct += corr + if not corr: + tin = test_in[i][0] + tout = to + + passed = n_correct == len(test_in) + hints = [{'id': 'test_results', 'args': {'passed': n_correct, 'total': len(test_in)}}] + if tin: + hints.append({'id': 'problematic_test_case', 'args': {'testin': str(tin), 'testout': str(tout)}}) + if passed: + if has_loop(ast): + hints.append({'id': 'has_loop'}) + else: + hints.append({'id': 'final_hint'}) + + + return passed, hints + + +def hint(python, code, aux_code=''): + tokens = get_tokens(code) + + # run one test first to see if there are any exceptions + answer = python(code=aux_code+code, inputs=[(None, None)], timeout=1.0) + exc = get_exception_desc(answer[0][3]) + if exc: return exc + + return None diff --git a/python/problems/recursion/binary/en.py b/python/problems/recursion/binary/en.py new file mode 100644 index 0000000..01440f7 --- /dev/null +++ b/python/problems/recursion/binary/en.py @@ -0,0 +1,13 @@ +id = 20808 +name = 'Binary' + +description = '''\ +<p>(translation missing)</p>''' + +hint = { + 'plan': '''\ +<p>(translation missing)</p>''', + + 'no_input_call': '''\ +<p>(translation missing)</p>''', +} diff --git a/python/problems/recursion/binary/sl.py b/python/problems/recursion/binary/sl.py new file mode 100644 index 0000000..8360a46 --- /dev/null +++ b/python/problems/recursion/binary/sl.py @@ -0,0 +1,30 @@ +import server +mod = server.problems.load_language('python', 'sl') + +id = 20808 +name = 'Binarno' + +description = '''\ +<p> +Napiši rekurzivno funkcijo <code>binary(n)</code>, ki kot argument prejme število +<code>n</code> in kot rezultat vrne niz s tem številom v dvojiškem zapisu. </p> + +<pre> +>>> binary(42) +'101010' +</pre> +''' + +plan = [] + +hint = { + 'final_hint': ['''\ +<p>Program je pravilen! <br> +</p> +'''], + + 'has_loop': ['''\ +<p>Program sicer deluje pravilno, vendar vsebuje zanko. +</p> +'''], +} diff --git a/python/problems/recursion/factorial/common.py b/python/problems/recursion/factorial/common.py new file mode 100644 index 0000000..fec787b --- /dev/null +++ b/python/problems/recursion/factorial/common.py @@ -0,0 +1,75 @@ +import re +from python.util import has_token_sequence, string_almost_equal, \ + string_contains_number, get_tokens, get_numbers, get_exception_desc, \ + all_tokens, has_comprehension, has_loop, almost_equal, get_ast +from server.hints import Hint + +id = 20806 +number = 6 +visible = True + +solution = '''\ +def factorial(n): + if n == 0: + return 1 + return n * factorial(n - 1) +''' + +hint_type = { + 'final_hint': Hint('final_hint'), + 'has_loop': Hint('has_loop') +} + +def test(python, code, aux_code=''): + func_name = 'factorial' + tokens = get_tokens(code) + ast = get_ast(code) + if not has_token_sequence(tokens, ['def', func_name]): + return False, [{'id' : 'no_func_name', 'args' : {'func_name' : func_name}}] + + in_out = [ + (0, 1), + (1, 1), + (2, 2), + (12, 479001600), + (20, 2432902008176640000) + ] + + test_in = [('{0}({1})'.format(func_name, str(l[0])), None) + for l in in_out] + test_out = [l[1] for l in in_out] + + answers = python(code=aux_code+code, inputs=test_in, timeout=1.0) + n_correct = 0 + tin, tout = None, None + for i, (ans, to) in enumerate(zip(answers, test_out)): + res = ans[0] + corr = res == to + n_correct += corr + if not corr: + tin = test_in[i][0] + tout = to + + passed = n_correct == len(test_in) + hints = [{'id': 'test_results', 'args': {'passed': n_correct, 'total': len(test_in)}}] + if tin: + hints.append({'id': 'problematic_test_case', 'args': {'testin': str(tin), 'testout': str(tout)}}) + if passed: + if has_loop(ast): + hints.append({'id': 'has_loop'}) + else: + hints.append({'id': 'final_hint'}) + + + return passed, hints + + +def hint(python, code, aux_code=''): + tokens = get_tokens(code) + + # run one test first to see if there are any exceptions + answer = python(code=aux_code+code, inputs=[(None, None)], timeout=1.0) + exc = get_exception_desc(answer[0][3]) + if exc: return exc + + return None diff --git a/python/problems/recursion/factorial/en.py b/python/problems/recursion/factorial/en.py new file mode 100644 index 0000000..616eacd --- /dev/null +++ b/python/problems/recursion/factorial/en.py @@ -0,0 +1,13 @@ +id = 20806 +name = 'Factorial' + +description = '''\ +<p>(translation missing)</p>''' + +hint = { + 'plan': '''\ +<p>(translation missing)</p>''', + + 'no_input_call': '''\ +<p>(translation missing)</p>''', +} diff --git a/python/problems/recursion/factorial/sl.py b/python/problems/recursion/factorial/sl.py new file mode 100644 index 0000000..a0269e3 --- /dev/null +++ b/python/problems/recursion/factorial/sl.py @@ -0,0 +1,37 @@ +import server +mod = server.problems.load_language('python', 'sl') + +id = 20806 +name = 'Fakulteta' + +description = '''\ +<p> +Napiši rekurzivno funkcijo <code>faktorial(n)</code>, ki izračuna n!. +Funkcija je definirana z enačbama <code>0! = 1</code> in +<code>n! = n * (n - 1)!</code>. +Rešitev ne sme vsebovati zanke <code>for</code> ali zanke <code>while</code>.</p> +<pre> +>>> faktorial(0) +1 +>>> faktorial(1) +1 +>>> faktorial(5) +120 +>>> faktorial(20) +2432902008176640000 +</pre> +''' + +plan = [] + +hint = { + 'final_hint': ['''\ +<p>Program je pravilen! <br> +</p> +'''], + + 'has_loop': ['''\ +<p>Program sicer deluje pravilno, vendar vsebuje zanko. +</p> +'''], +} diff --git a/python/problems/recursion/sum/common.py b/python/problems/recursion/sum/common.py new file mode 100644 index 0000000..9625a76 --- /dev/null +++ b/python/problems/recursion/sum/common.py @@ -0,0 +1,70 @@ +import re +from python.util import has_token_sequence, string_almost_equal, \ + string_contains_number, get_tokens, get_numbers, get_exception_desc, \ + all_tokens, has_comprehension, has_loop, almost_equal, get_ast +from server.hints import Hint + +id = 20807 +number = 7 +visible = True + +solution = '''\ +def sum(xs): + if not xs: + return 0 + if isinstance(xs[0], list): + return sum(xs[0]) + sum(xs[1:]) + return xs[0] + sum(xs[1:]) +''' + +hint_type = { + 'final_hint': Hint('final_hint') +} + +def test(python, code, aux_code=''): + func_name = 'sum' + tokens = get_tokens(code) + if not has_token_sequence(tokens, ['def', func_name]): + return False, [{'id' : 'no_func_name', 'args' : {'func_name' : func_name}}] + + in_out = [ + ([], 0), + ([1,2,3,4,5], 15), + ([1, [], [2, 3, [4]], 5], 15), + ([1, [], [2, 3, [4]], 5, [[[[10], 6], [[7], 9], 8]]], 55), + ] + + test_in = [('{0}({1})'.format(func_name, str(l[0])), None) + for l in in_out] + test_out = [l[1] for l in in_out] + + answers = python(code=aux_code+code, inputs=test_in, timeout=1.0) + n_correct = 0 + tin, tout = None, None + for i, (ans, to) in enumerate(zip(answers, test_out)): + res = ans[0] + corr = res == to + n_correct += corr + if not corr: + tin = test_in[i][0] + tout = to + + passed = n_correct == len(test_in) + hints = [{'id': 'test_results', 'args': {'passed': n_correct, 'total': len(test_in)}}] + if tin: + hints.append({'id': 'problematic_test_case', 'args': {'testin': str(tin), 'testout': str(tout)}}) + if passed: + hints.append({'id': 'final_hint'}) + + return passed, hints + + +def hint(python, code, aux_code=''): + tokens = get_tokens(code) + + # run one test first to see if there are any exceptions + answer = python(code=aux_code+code, inputs=[(None, None)], timeout=1.0) + exc = get_exception_desc(answer[0][3]) + if exc: return exc + + return None diff --git a/python/problems/recursion/sum/en.py b/python/problems/recursion/sum/en.py new file mode 100644 index 0000000..a61f900 --- /dev/null +++ b/python/problems/recursion/sum/en.py @@ -0,0 +1,13 @@ +id = 20807 +name = 'Sum' + +description = '''\ +<p>(translation missing)</p>''' + +hint = { + 'plan': '''\ +<p>(translation missing)</p>''', + + 'no_input_call': '''\ +<p>(translation missing)</p>''', +} diff --git a/python/problems/recursion/sum/sl.py b/python/problems/recursion/sum/sl.py new file mode 100644 index 0000000..e23bd97 --- /dev/null +++ b/python/problems/recursion/sum/sl.py @@ -0,0 +1,32 @@ +import server +mod = server.problems.load_language('python', 'sl') + +id = 20807 +name = 'Vsota seznama' + +description = '''\ +<p> +Napiši funkcijo <code>sum(xs)</code>, ki sešteje elemente vgnezdenega seznama xs. +Pomagajte si s funkcijo isinstance.</p> +<pre> +>>> isinstance([1, 2, 3], list) +True +>>> isinstance(1, list) +False +>>> sum([]) +0 +>>> sum([1, 2, 3, 4, 5]) +15 +>>> sum([1, [], [2, 3, [4]], 5]) +15 +</pre> +''' + +plan = [] + +hint = { + 'final_hint': ['''\ +<p>Program je pravilen! <br> +</p> +'''], +} diff --git a/python/problems/while_and_if/conditions_sl.html b/python/problems/while_and_if/conditions_sl.html new file mode 100644 index 0000000..6d6f838 --- /dev/null +++ b/python/problems/while_and_if/conditions_sl.html @@ -0,0 +1,159 @@ +<!DOCTYPE html> +<html lang="sl"> +<head> + <meta charset="utf-8" /> + <title></title> + <link rel="stylesheet" type="text/css" href="/css/codeq.css" /> + <link rel="stylesheet" type="text/css" href="../../style.css" /> +</head> +<body> + +<h2>Pogoji</h2> + +<p>Zdaj pa povejmo nekaj splošnejšega o pogojih. Kakšni vse so lahko? Najprej, + pogoj je izraz. Torej nekaj, kar se da izračunati (po naši garažni + definiciji izraza). Doslej so bili vsi naši izrazi nekako številski, + aritmetični: v njih so nastopala števila in le-ta smo seštevali, množili, + odštevali in kar se še takega dela s števili. Pogoji pa so logični izrazi. + (V resnici se "logičnost" in "številskost" lahko poljubno prepletata, a to + bomo mimogrede odkrili sproti.)</p> + +<p>Rezultat logičnega izraza je logična vrednost. Logične vrednosti niso števila + (torej niso <code>int</code> ali <code>float</code>) in niso nizi, torej so + nekaj četrtega. Podatkovni tip, ki hrani logične vrednosti, se imenuje + <code>bool</code> (iz Boolean, po slovensko Booleov). Medtem ko je + različnih števil (<code>int</code>, <code>float</code>) kar veliko, + ima tip <code>bool</code> lahko le eno od dveh + vrednosti, <code>True</code> ali <code>False</code>. Tudi <code>True</code> + in <code>False</code> rezervirani besedi. </p> + +<p>S števili že znamo računati. Z nizi tudi malo. Kako pa računamo z logičnimi + vrednostmi? Menda jih ne moremo kar tako seštevati in odštevati?</p> + +<p>Za zdaj se delajmo, da ne. Kasneje bomo videli, da zna Python z logičnimi + izrazi početi še to in ono zanimivo reč, ki pa za začetnika niso tako + pomembne.</p> + +<p>Za logične izraze so nam na voljo trije operatorji: <code>or</code>, + <code>and</code> in <code>not</code>. + +<pre> +>>> True and True +True +>>> True and False +False +>>> False or True +True +>>> not False +True +>>> False or not False +True +</pre> + +<p>(<code>and</code>, <code>or</code> in <code>not</code> so rezervirane besede.</p> + +<p>Operator <code>not</code> ima prednost pred <code>and</code>, + <code>and</code> pa pred <code>or</code>. Spet si lahko pomagamo z + oklepaji: <code>a or b and c</code> pomeni isto kot + <code>a or (b and c)</code> in bo resničen (<code>True</code>), če je resničen + <code>a</code> ali pa sta resnična <code>b</code> in <code>c</code>. Izraz + <code>(a or b) and c</code> pa bo resničen, če sta resnična <code>a</code> + ali <code>b</code> (ali oba), poleg tega pa nujno še <code>c</code>. Pri + tem seveda predpostavljamo, da <code>a</code>, <code>b</code> in + <code>c</code> vsebujejo logične vrednosti.</p> + +<p>Da bo reč lažje razumljiva, jo potrenirajmo na prav tem izrazu, vendar tako, + da namesto <code>a</code>, <code>b</code> in <code>c</code> oziroma namesto + "golih" <code>True</code> in <code>False</code> pišemo bolj "konkretne" + izraze.</p> + +<pre> +>>> 352 > 0 +True +>>> 5 < 3 +False +>>> 352 > 0 or 5 < 3 +True +>>> 352 > 0 or 5 > 3 +True +>>> 352 > 0 and 5 > 3 +True +>>> 352 > 0 and 5 < 3 +False +>>> 352 > 0 and not 5 < 3 +True +>>> 10 > 8 or 352 > 0 and 5 < 3 +True +>>> 10 > 8 or (352 > 0 and 5 < 3) +True +>>> (10 > 8 or 352 > 0) and 5 < 3 +False +>>> (10 > 8 or 352 > 0) and not 5 < 3 +True +</pre> + +<p>Operatorja > in < pričakujeta na levi in desni neke reči, ki jih je + mogoče primerjati; zadovoljna nista le s števili, temveč tudi z, recimo, + nizi (primerjala jih bosta po abecedi), ne moreta pa primerjati števila z + nizom. Njun rezultat je logična vrednost. Za "večje ali enako" in "manjše + ali enako" uporabimo <code>>=</code> in <code><=</code>.</p> + +<p>Če želimo preveriti enakost dveh števil (ali, v splošnem, enakost dveh + stvari), uporabimo dvojni enačaj, <code>==</code>. Enojni enačaj je dobil + svojo zadolžitev prejšnjo uro, namenjen je namreč prirejanju. Ali sta dve + stvari različni, preverimo z <code>!=</code>.</p> + +<pre>>>> 1 + 1 == 2 +True +>>> 1 + 1 != 2 +False</pre> +</p> + +<p>Ne zamenjujte dvojnih in enojnih enačajev. Če pomotoma napišemo (a to se nam + bo rekdo zgodilo),</p> +<pre> a == 1 + 1</pre> +<p>s tem nismo priredili <code>a</code>-ju dvojke, temveč smo le preverili, ali je + enak 2. Pogostejša napaka pa bo</p> +<pre> if a = 1: + print("Vrednost a je ena")</pre> +<p>Ta program pa je sintaktično nepravilen, saj Python za <code>if</code> +pričakuje pogoj, mi pa smo napisali prireditveni stavek.</p> + + + +<p>Zdaj pa Pythonova posebnost, ki je v drugih jezikih ne bo: operatorje smemo nizati. Izraz + <code>10 < T < 20</code> je resničen, če je <code>T</code> med 10 in + 20. Izraz <code>10 < T1 < T2 < 20</code> je resničen, če sta + <code>T1</code> in <code>T2</code> med 10 in 20, pri čemer je + <code>T1</code> manjši od <code>T2</code>. Izraz + <code>T1 < 10 < T2</code> je resničen, če je <code>T1</code> manjši + od 10, <code>T2</code> pa večji od deset. + <code>10 < T1 == T2 < 20</code> je resničen, če sta + <code>T1</code> in <code>T2</code> enaka in sta nekje med 10 in 20.</p> + +<p>Če se torej končno vrnemo k suhcem in debeluhom: če bi se hoteli + skoncentrirati le na te, ki so ravno pravšnji, bi lahko napisali, + recimo</p> + +<pre>if bmi > 18.5 and bmi < 25: + print("Čestitamo, ravno pravšnji ste.")</pre> + +<p>Če kdo napiše</p> + +<pre>if (bmi > 18.5) and (bmi < 25): + print("Čestitamo, ravno pravšnji ste.")</pre> + +<p>ali celo</p> + +<pre>if ((bmi > 18.5) and (bmi < 25)): + print("Čestitamo, ravno pravšnji ste.")</pre> + +<p>Ga bomo čudno gledali (((kdor hoče oklepaje, naj gre raje programirat v +<a href="http://xkcd.com/297/">Lisp</a>))). Prav po Pythonovsko pa se reče:</p> + +<pre>if 18.5 < bmi < 25: + print("Čestitamo, ravno pravšnji ste.")</pre> + + +</body> +</html> diff --git a/python/problems/while_and_if/ifclause_sl.html b/python/problems/while_and_if/ifclause_sl.html new file mode 100644 index 0000000..c1f9134 --- /dev/null +++ b/python/problems/while_and_if/ifclause_sl.html @@ -0,0 +1,330 @@ +<!DOCTYPE html> +<html lang="sl"> +<head> + <meta charset="utf-8" /> + <title></title> + <link rel="stylesheet" type="text/css" href="/css/codeq.css" /> + <link rel="stylesheet" type="text/css" href="../../style.css" /> +</head> +<body> + +<h2>Pogojni stavki</h2> + +<p> Sledijo zapiski predavanj prof. Demšarja. Najnovejšo verzijo zapiskov dobite na + <a href="https://ucilnica.fri.uni-lj.si/course/view.php?id=166">spletni + učilnici</a>.</p></p> + +<p>Začnimo s preprostim programom za izračun indeksa telesne teže.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi)</pre> + +<p>Želimo si, da bi program povedal še, ali je uporabnik slučajno + preobilen. Prvi, seveda napačni poskus, bi bil takšen.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +print("Potrebno bo shujšati!")</pre> + +<p>Program v tej obliki bi, v širši rabi, povzročal anoreksijo, saj vse po +vrsti pošilja na hujšanje. Zadnjo vrstico, izpis poziva k hujšanju, mora izvesti +le, če je <code>bmi</code> večji od 25 (ta meja namreč velja za mejo debelosti, +oziroma, politično korektno, prekomerne telesne teže).</p> + +<p>To storimo tako, da pred vrstico dodamo pogoj. Ta se glasi "če bmi > 25", +le v angleščini.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!")</pre> + +<p>Ne spreglejmo dveh pomembnih reči. Prva: na konec pogoja smo postavili + dvopičje. To ne služi le za okras: dvopičja ne smemo izpustiti. Python na + tem mestu <em>zahteva</em> dvopičje.</p> + +<p>Druga: za <code>if</code>-om sem vrstico nekoliko zamaknil. Obilajno je zamik + štiri presledke. Ni obvezno, a če boste uporabljali štiri presledke, boste + pisali enako kodo kot drugi. In nikoli nikoli ne uporabljajte tabulatorjev, + ti naredijo zmedo!</p> + +<p>Zamaknjenih vrstic bi lahko bilo še več. Vse se izvedejo le, če +je pogoj izpolnjen.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Tako kot smo zastavili zdaj, se <code>print</code>a, ki sta zamaknjena, +izvedeta le, če je oseba preobilna. Zadnji <code>print</code> ni več znotraj +pogoja, zato se izvede v vsakem primeru, za suhe in debele.</p> + +<p>Program bi bil še bolj simpatičen, če bi tiste, ki niso predebeli, pohvalil. +</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Pogojnemu stavku lahko sledi še + <code>else</code>, ki vsebuje tisto, kar naj se zgodi, če pogoj ni + izpolnjen.</p> + +<p>Znotraj pogojnih stavkov seveda lahko pišemo tudi druge reči, ne le +<code>print</code>ov. Takole: uporabniki programa se bodo pogosto zmotili in +namesto višine v metrih vpisali višino v centimetrih, zato jih bo program +obtožil težke anoreksije. To lahko popravimo preprosto tako, da program še pred +računanjem BMI preveri, ali je višina slučajno večja od, recimo, treh metrov. +V tem primeru sklepa, da je uporabnik podal višino v centimetrih, zato številko, +ki jo je vpisal uporabnik, deli s 100.</p> + +<p>Začetek programa tako postane takšen.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +if visina > 3: + visina = visina / 100 +bmi = teza / visina ** 2</pre> + +<p>Še ena estetska zadeva: za dvopičjem vedno pojdite v novo vrsto. Kot boste + zvedavi kmalu odkrili, Python sicer dovoli, da napišete tudi +<pre>if bmi > 25: print ("Potrebno bo shujšati")</pre> +vendar to vodi v nepregledne programe. To se ne dela.</p> + +<p>Tule pa je še nekaj primerov napačno zamikanih programov.</p> + +<pre>if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Tretja vrstica mora imeti enak zamik kot druga, sicer Python ne more vedeti, + ali je še znotraj pogoja ali ne.</p> + +<pre>if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Ne, tudi v to smer ne smemo. Tu se Python vpraša, zakaj je tretja vrstica + zamaknjena še bolj kot druga - smo pozabili še kakšen pogoj ali kaj?</p> + +<pre>if bmi > 25: +print("Potrebno bo shujšati!") +print("Da, gospod ali gospa, preveč vas je skupaj.") +</pre> + +<p>Blok za stavkom <code>if</code> mora biti zamaknjen.</p> + +<pre>if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") + else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p><code>if</code> in <code>else</code> morata biti poravnana. Kmalu bomo videli +programe z več <code>if</code>i in <code>else</code>i; zamiki bodo potrebni, +da bomo vedeli, kateri <code>else</code> sodi h kateremu <code>if</code>.</p> + +<p>Če poskušamo zagnati kateregakoli od naštetih programov, bo Python javil + sintaktično napako. Za razliko od običajnih napak, ki jih boste delali, in + ko bodo programi naredili vsaj nekaj malega in potem crknili, ta ne bo niti + trznil, temveč kar takoj javil napako. Spodnji program pa je sintaktično + pravilen. Python ga lahko izvede. Najbrž pa to ni to, kar smo hoteli, saj + se zadnji <code>print</code> izvede le, če pogoj ni izpolnjen.</p> + +<pre>if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + print("Odlično, le še naprej jejte toliko kot doslej!") + print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + + +<h2>Gnezdeni pogoji</h2> + +<p>Do sem vse lepo in prav, vendar: kaj bomo z anoreksičnimi? Program bi jim +mirno svetoval, naj še naprej jedo toliko kot doslej (torej: premalo). +Ne: pri takšnih, ki imajo BMI manjši od +18.5, moramo zastokati, naj vendar že začnejo jesti.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + if bmi < 18.5: + print("Trlica!") + print("Zunaj so avtomati s sendviči in čokolado. Med pavzo si le postrezite!") + else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Vidimo? Znotraj <code>if</code>a ali <code>else</code>a smemo +ugnezditi nov pogoj. Zamikamo ga lepo naprej.</p> + +<p>Da bodo reči še nekoliko daljše (a poučnejše), dodajmo še en + <code>print</code>.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + print("Predebeli ravno niste.") + if bmi < 18.5: + print("Trlica!") + print("Zunaj so avtomati s sendviči in čokolado. Med pavzo si le postrezite!") + else: + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Zdaj program vsem, ki niso predebeli, napiše dobro novico, da niso predebeli. +Šele nato se loti preverjanja, da niso slučajno presuhi.</p> + +<p>Tule mimogrede (prvič - a še velikokrat bomo) posvarimo pred ponavljanjem +kode. Gornji program bi lahko napisali tudi tako:</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") +else: + if bmi < 18.5: + print("Predebeli ravno niste.") + print("Trlica!") + print("Zunaj so avtomati s sendviči in čokolado. Med pavzo si le postrezite!") + else: + print("Predebeli ravno niste.") + print("Odlično, le še naprej jejte toliko kot doslej!") +print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>Ali celo tako.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") + print("Da, gospod ali gospa, preveč vas je skupaj.") + print("Pregled je končan, oglasite se spet čez dva tedna.") +else: + if bmi < 18.5: + print("Predebeli ravno niste.") + print("Trlica!") + print("Zunaj so avtomati s sendviči in čokolado. Med pavzo si le postrezite!") + print("Pregled je končan, oglasite se spet čez dva tedna.") + else: + print("Predebeli ravno niste.") + print("Odlično, le še naprej jejte toliko kot doslej!") + print("Pregled je končan, oglasite se spet čez dva tedna.")</pre> + +<p>To ni dobra ideja, ker je program daljši, manj pregleden, težje mu je + slediti, težje ga je spreminjati... Vedno se izogibajte ponavljanju. Več + o tem pa čez dva ali tri tedne.</p> + +<h2>Sicerče</h2> + +<p>Da se ne izgubimo, spet malo skrajšajmo program.</p> + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") +else: + if bmi < 18.5: + print("Trlica!") + else: + print("Odlično, le še naprej jejte toliko kot doslej!")</pre> + +<p>Pogojni stavki se nam lahko hitro zagnezdijo precej globoko in vrstice +zbežijo nekam daleč proti desni. (Da ne govorimo o tem, da pogojni stavki +niso niti približno edina reč, za katero bomo morali zamikati vrstice.) Ker +so situacija, kakršna je zgornja, kar pogoste, imajo nekateri programski jeziki +- in Python je med njimi - poleg <code>if</code> in <code>else</code> še +<code>elseif</code> oziroma <code>elif</code>. (Še ena rezervirana beseda!) +V Pythonu se uporablja slednja različica, <code>elif</code>. V gornjem programu +ga uporabimo takole: + +<pre>teza = float(input("Teža: ")) +visina = float(input("Telesna višina: ")) +bmi = teza / visina ** 2 +print("Indeks vaše telesne teže je", bmi) +if bmi > 25: + print("Potrebno bo shujšati!") +elif bmi < 18.5: + print("Trlica!") +else: + print("Odlično, le še naprej jejte toliko kot doslej!")</pre> + +<p>Program se zdaj prebere še lepše kot prej: če je BMI prevelik, pozovemo + k hujšanju, sicerče je premajhen, ozmerjamo dotično najstnico s trlico, + sicer pa izrečemo pohvalo.</p> + +<p>Po izkušnjah je <code>elif</code> za študente huda, nenavadna skušnjava: + nekateri ga pogosto uporabljajo namesto <code>else</code>a. Recimo, da bi + hoteli sprogramirati skrajšano pesimistično različico, po kateri so vsi, + ki niso debeluhi, trlice. Radi bi torej tole:</p> +<pre>if bmi > 25: + print("Potrebno bo shujšati!") +else: + print("Trlica!") +</pre> + +<p>Mnogi bi (iz meni neznanega razloga) naredili takole:</p> + +<pre>if bmi > 25: + print("Potrebno bo shujšati!") +elif bmi < 25: + print("Trlica!") +</pre> + +<p>Python ni pozabil <code>if</code>a in bo tudi, če napišemo le + <code>else</code>, čisto dobro vedel, kakšen je pogoj zanj. Drugi pogoj + je nepotreben; če <code>bmi</code> ni večji od 25, je pač očitno manjši.</p> + +<p>Torej: ne zamenjujte <code>else</code> brez potrebe z <code>elif</code>.</p> + +<p>Mimogrede, program ne izpiše ničesar za tiste, ki imajo BMI natančno +25. Drugi pogoj, če ga res hočemo imeti, bi se moral vprašati, ali je +<code>bmi</code> manjši <em>ali enak</em> 25.</p> + + + +</body> +</html> diff --git a/python/problems/while_and_if/loops_sl.html b/python/problems/while_and_if/loops_sl.html new file mode 100644 index 0000000..17d89c4 --- /dev/null +++ b/python/problems/while_and_if/loops_sl.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html lang="sl"> +<head> + <meta charset="utf-8" /> + <title></title> + <link rel="stylesheet" type="text/css" href="/css/codeq.css" /> + <link rel="stylesheet" type="text/css" href="../../style.css" /> +</head> +<body> + +<h1>Zanka <code>while</code></h1> + +<h2>Naša prva zanka</h2> + +<p>Najprej malo refleksije. Kaj znamo narediti doslej: znamo napisati program, + ki kaj vpraša, kaj računa in kaj izpiše. Naši programi se izvajajo od + začetka do konca, s tem da lahko vmes preskočijo kak blok ukazov, ki se + nahajajo znotraj kakega <code>if</code>, <code>else</code> ali + <code>elif</code>. Večino časa pa smo preživeli ob tem, kako napisati + pogoj, se pravi, izraz, katerega vrednost je lahko resnično ali neresnično, + <code>True</code> ali <code>False</code>. Zdaj pa se bomo naučili napisati + programe, v katerih se del programa ponavlja.</p> + +<p>V večini programskih jezikov to naredimo z nečim, čemur mi rečemo zanka, + Avstralci (razen aboriginov) pa <em>loop</em>. Jeziki imajo navadno več + vrst zank, navadno tri. Python premore samo dve in danes bomo spoznali prvo + od njiju: zanko <em>while</em>.</p> + +<p>Tisočletna tradicija veleva, da mora biti začetnikov prvi program z zanko + program, ki šteje do deset. V Pythonu je videti takole +<pre>x = 1 +while x <= 10: + print(x) + x = x + 1 +print('Pa sva preštela')</pre> + +<p>Zanka <code>while</code> je po svoje podobna stavku <code>if</code>. Medtem + ko se stavki znotraj <code><b>if</b></code> izvedejo, <b>če</b> je pogoj + resničen, se stavki znotraj <code><b>while</b></code> ponavljajo, + <b>dokler</b> je pogoj resničen. "If" je "če" in "while" je "dokler", to + vedo celo učiteljice angleščine. (Mimogrede, če že štejemo, + <code>while</code> je zadnja, enajsta rezervirana beseda danes. Smo že na + tretjini!) Gornji program lahko torej kar dobesedno prevedemo iz Pythona v + slovenščino: + +<pre> +postavi x na 1 +dokler je x manjši ali enak 10: + izpiši vrednost x + povečaj x za 1 +izpiši 'Pa sva preštela' +</pre> + +<p>K temu ni potrebna več nobena razlaga, ne?</p> + +<p>Trenutek je tako dober kot katerikoli drugi, morda pa še boljši: tale + <code>x = x + 1</code> smo "prevedli" v "povečaj x za 1". V resnici nismo + napisali tega, računalniku smo naročili, naj izračuna, koliko je + <code>x + 1</code> in to shrani nazaj v <code>x</code>. Ker pa to reč + tolikokrat potrebujemo in ker je lepo, da se stvar napiše tako, kot se + misli - misli pa se "povečaj x za 1" -, obstaja tudi praktičnejši zapis: + <code>x += 1</code>. Točneje, napisali smo "k x prištej 1". Rečemo lahko + tudi, <code>x += 6</code> ali <code>x += 1.13</code>; kaj to pomeni, je + menda jasno. Podobno moremo pisati tudi <code>x -= 1</code> (zmanjšaj + <code>x</code> za 1) ali, recimo <code>x *= 2</code>, podvoji + <code>x</code> in <code>x /= 10</code>, zdesetkaj <code>x</code>. + Pazite: <code>+=</code> (in vse druge kombinacije) se štejejo kot ena + beseda in med znaka <code>+</code> in <code>=</code> ne smemo napisati + presledka.</p> + +<p>Tisti, ki veste še kaj več: <code>x++</code> boste v Pythonu zaman iskali. + Nima ga, iz več razlogov, ki pa so malo pregloboki za nas tule.</p> + +<h2>Kaj je domneval Collatz</h2> + +<p>Vzemimo poljubno število in z njim počnimo tole: če je sodo, ga delimo z 2, +če je liho, pa ga pomnožimo s 3 in prištejmo 1. To ponavljamo, dokler ne dobimo +1.</p> + +<p>Za primer vzemimo 12. Ker je sodo, ga delimo z 2 in dobimo 6. 6 je sodo, +torej ga delimo z 2 in dobimo 3. 3 je liho, torej ga množimo s 3 in prištejemo +1 - rezultat je 10. 10 je sodo, zato ga delimo z 2 in dobimo 5... Celotno +zaporedje je 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. Ko pridemo do 1, se ustavimo.</p> + +<p>Matematiki, ki vedno radi počnejo koristne reči, si belijo glavo z +vprašanjem, ali se reč vedno izteče ali pa se lahko kdaj tudi zacikla tako, da +se zaporedje ponavlja in ponavlja v nedogled. Lothar Collatz, konkretno je že od +leta 1937 +<a href="https://en.wikipedia.org/wiki/Collatz_conjecture">domneval</a>, da se +zaporedje vedno izteče. Kot pravi njegov +<a href="https://en.wikipedia.org/wiki/Lothar_Collatz">življenjepis</a>, se je +njegovo domnevanje končalo leta 1990, matematiki pa domnevajo domnevo še naprej. +Eden sicer najbolj neustrašnih matematikov 20. stoletja, +<a href="https://en.wikipedia.org/wiki/Paul_Erd%C5%91s#Personality">couch + surfer Erdos</a>, je na to temo rekel, da matematika za takšna vprašanja še + ni zrela.</p> + +<p>Naši cilji bodo skromnejši: napisali bomo program, ki mu bo uporabnik vpisal +število in program bo izpisal zaporedje, kot je bilo gornje.</p> + +<p>Najprej povejmo kar po slovensko:</p> + +<pre>stevilo = kar vpiše uporabnik +dokler stevilo != 1: + če je število sodo: + deli število z 2 + sicer: + pomnoži število s 3 in prištej 1</pre> + +<p>Tole skoraj že znamo prevesti v Python (prevod bo pravzaprav dobeseden), + odkriti moramo le, kako preveriti, ali je število sodo. Če kdo misli, da + tudi za to obstaja funkcija, se, izjemoma, moti. Pač pa znamo izračunati + ostanek po deljenju, konkretno, ostanek po deljenju z 2. Če je enak 0, je + število sodo.</p> + +<p>Prevedimo torej one slovenske besede v pythonovske.</p> + +<pre>n = int(input("Vnesi število: ")) +while n != 1: + print(n) + if n % 2 == 0: + n //= 2 + else: + n = n * 3 + 1 +print(1)</pre> + +<p>Ne spreglejte, da smo uporabili celoštevilsko deljenje. Če bi uporabili +navadnega, <code>n /= 2</code>, bi se <code>n</code> spremenil v necelo število +(<code>float</code>) in v izpisu bi se pojavile zoprne decimalke (za vsakim +številom bi pisalo še .0).</p> + +<p>Popaziti je potrebno, da izpišemo tako prvo kot zadnje število, zato bomo +potrebovali še en <code>print</code> izven zanke: po zanki izpišemo še zadnji +člen zaporedja, 1. Namesto <code>print(1)</code> bi lahko napisali tudi +<code>print(n)</code> - tako ali tako vemo, da je <code>n</code> enak 1, saj +program sicer ne bi prišel do tam, do koder je prišel, namreč onstran zanke, ki +teče, dokler je <code>n</code> različen od 1.</p> + +<p>Dodajmo še nekaj: na koncu naj se izpiše, koliko členov ima zaporedje.</p> + +<pre>n = int(input("Vnesi število: ")) +clenov = 1 +while n != 1: + clenov += 1 + print(n) + if n % 2 == 0: + n //= 2 + else: + n = n * 3 + 1 +print(1) +print("Zaporedje, ki se začne z", n, "ima", clenov, "členov")</pre> + +<p>Ups. V zanki smo pokvarili <code>n</code>, spremenil smo ga v 1. To bomo +rešili tako, da shranimo začetno število v še eno spremenljivko.</p> + +<pre>zac = n = int(input("Vnesi število: ")) +clenov = 1 +while n != 1: + clenov += 1 + print(n) + if n % 2 == 0: + n //= 2 + else: + n = n * 3 + 1 +print(1) +print("Zaporedje, ki se začne z", zac, "ima", clenov, "členov")</pre> + +<p>Število smo si zapomnili v prvi vrstici, shranili smo ga v +<code>zac</code>. (V tem programu tudi prvič vidimo, da lahko prirejanja kar +nizamo - pisati smemo <code>a = b = c = 42</code>.) Ustrezno popravimo še +izpis v zadnji vrsti.</p> + +<script type="text/javascript"> + SyntaxHighlighter.config.tagName = "xmp"; + SyntaxHighlighter.defaults["gutter"] = false; + SyntaxHighlighter.all() +</script> +</body> +</html> diff --git a/python/problems/while_and_if/sl.py b/python/problems/while_and_if/sl.py index fbb177a..7caffb4 100644 --- a/python/problems/while_and_if/sl.py +++ b/python/problems/while_and_if/sl.py @@ -1,2 +1,4 @@ name = 'Pogojni stavki in zanke' -description = 'Logični izrazi, pogojni stavek if-else, zanka while.' +description = '''<a target="_blank" href="[%@resource ifclause_sl.html%]">Pogojni stavek if-else</a>, +<a target="_blank" href="[%@resource conditions_sl.html%]">logični izrazi</a> +<a target="_blank" href="[%@resource loops_sl.html%]">zanka <code>while</code></a>''' |