From b2e1800fa19d18840c3d399c4a379f2da53fe7b0 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 14 Sep 2015 20:15:35 +0200 Subject: Added pythagorean theorem. --- .../introduction/pythagorean_theorem/common.py | 89 +++++++++++++-------- .../introduction/pythagorean_theorem/sl.py | 92 +++++++++------------- 2 files changed, 94 insertions(+), 87 deletions(-) (limited to 'python') diff --git a/python/problems/introduction/pythagorean_theorem/common.py b/python/problems/introduction/pythagorean_theorem/common.py index b2ae10c..5f59588 100644 --- a/python/problems/introduction/pythagorean_theorem/common.py +++ b/python/problems/introduction/pythagorean_theorem/common.py @@ -18,10 +18,38 @@ razdalja = v ** 2 * sin(2 * kot_rad) / g print("Kroglo bo odneslo", razdalja, "metrov.") ''' -#hint_type = { -# 'plan': Hint('plan'), -# 'no_input_call': Hint('no_input_call'), -#} +hint_type = { + 'plan': Hint('plan'), + 'name_error': HintSequence('name_error'), + 'unsupported_operand': HintSequence('unsupported_operand'), + 'syntax_error' : HintSequence('syntax_error'), + 'indentation_error': HintSequence('indentation_error'), + 'no_input_call' : Hint('no_input_call'), + 'radians': HintSequence('radians'), + 'printing': Hint('printing'), + 'math_functions': Hint('math_functions') +} + + +def almostEqual(a, b, prec=1): + """ Compares values a and b using at most prec decimal values. """ + return int(a*10**prec) == int(b*10**prec) + +def stringAlmostEqual(s, a): + """ Searches string s for a value that is almost equal to a. + + Args: + s (str): string to search + a (float): value to find in string + + Returns: + bool: True if successful, else False + """ + for v in s.split(): + try: + if almostEqual(float(v), a): + return True + return False def test(python, code): # List of inputs: (expression to eval, stdin). @@ -32,43 +60,35 @@ def test(python, code): (None, '0\n100\n'), (None, '90\n100\n'), (None, '32\n747\n'), - #(None, '212\n'), - #(None, '-459.4\n'), - #(None, '98.6\n'), - #(None, '1832\n'), ] test_out = [ '1000', - '999.39' - '999.39' - #'100', - #'-273', - #'37', - #'1000' + '999.39', + '999.39', + '0.0', + '0.0', + '50153.5' ] # List of outputs: (expression result, stdout, stderr, exception). answers = python(code=code, inputs=test_in, timeout=1.0) outputs = [ans[1] for ans in answers] - print (answers) - n_correct = 0 for output, correct in zip(outputs, test_out): - if correct in output: + if stringAlmostEqual(output, correct): n_correct += 1 return n_correct, len(test_in) def hint(python, code): # run one test first to see if there are any exceptions - test_in = [(None, '212\n')] - exc = python(code=code, inputs=test_in, timeout=1.0)[0][3] - # have an exception! + test_in = [(None, '45\n')] + answer = python(code=code, inputs=test_in, timeout=1.0) + exc = answer[0][3] + # if have an exception! if exc: if 'NameError' in exc: return [{'id':'name_error'}] - if 'not callable' in exc: - return [{'id':'not_callable'}] if 'unsupported operand' in exc: return [{'id':'unsupported_operand'}] if 'SyntaxError' in exc: @@ -76,27 +96,28 @@ def hint(python, code): if 'IndentationError' in exc: return [{'id':'indentation_error'}] + # if result if 893.996, angle is not converted to radians + if stringAlmostEqual(answer[0][1], 893.996): + return [{'id': 'radians'}] - # the trick is to decide when to show the plan and when the first hint. - # I implemented a simple idea: show plan, when code contains something from the - # solution, but not input. + # show plan if student is lost if not code or (not has_token_sequence(code, ['input']) and - (has_token_sequence(code, ['32']) or - has_token_sequence(code, ['=', '5']) or + (has_token_sequence(code, ['pi']) or + has_token_sequence(code, ['sin']) or has_token_sequence(code, ['print']))): return [{'id': 'plan'}] # if input is not present in code, student needs to learn about input - if not has_token_sequence(code, ['input']): + if not has_token_sequence(code, ['input']) or \ + not has_token_sequence(code, ['float']): return [{'id': 'no_input_call'}] - # if tokens * or / or = are not in code, we have to teach them how to - # evaluate expressions. - if (not has_token_sequence(code, ['/']) or - not has_token_sequence(code, ['*']) or - not has_token_sequence(code, ['='])): - return [{'id' : 'expressions_python'}] + # if tokens sqrt or ** are not in code, we have to teach them how to + # use math functions. + if (not has_token_sequence(code, ['sqrt']) or + not has_token_sequence(code, ['**']): + return [{'id' : 'math_functions'}] # student is not using print function if not has_token_sequence(code, ['print']): diff --git a/python/problems/introduction/pythagorean_theorem/sl.py b/python/problems/introduction/pythagorean_theorem/sl.py index ae88d1b..ffbf6a1 100644 --- a/python/problems/introduction/pythagorean_theorem/sl.py +++ b/python/problems/introduction/pythagorean_theorem/sl.py @@ -5,9 +5,8 @@ name = 'Pitagorov izrek' slug = 'Pitagorov izrek' description = '''\ -

Napiši program, ki mu uporabnik vpiše temperaturo v Fahrenheitovih -stopinjah, program pa jo izpiše v Celzijevih. Med temperaturama pretvarjamo po -formuli C = 5/9 (F – 32).

''' +

Npiši program, ki uporabnika vpraša po dolžinah katet pravokotnega trikotnika in +izpiše dolžino hipotenuze. ''' general_exception = { 'error_head' : '

Napaka:

', @@ -45,38 +44,44 @@ poravnane.

''' hint = { 'plan': ['''\ -

Program izvedemo v treh korakih:

+

Program razdelimo na tri dele kot pri Fahrenheitih:

    -
  1. Vprašanje za temperaturo v Fahrenheitih (F = ?).
  2. -
  3. Izračun temperature v Celzijih: C = 5/9 (F – 32)
  4. -
  5. Izpis temperature v Celzijih (izpiši C).
  6. -
'''], +
  • Preberi vrednosti katet (a,b = ?)
  • +
  • Izračunaj dolžino hipotenuze c (c = …)
  • +
  • Izpis dolžine hipotenuze (print … )
  • + +'''], 'no_input_call': ['''\ -

    Uporabnika lahko nekaj vprašamo s funkcijo input. Funkcija -input sprejme kot argument niz (angl. string), ki se -prikaže uporabniku kot vprašanje in vrne niz, ki ga je uporabnik napisal. Nize -zapisujemo v narekovaje (lahko so enojni ali dvojni). Npr., naslednja -vrstica:

    +

    Tako kot pri prejšnji nalogi uporabimo funkcijo input, le da tokrat preberemo +dve vrednosti in jih shranimo v dve spremenljivki:

    -ime = input("Kako ti je ime?")
    + a = float(input("Prva kateta: "))
    + b = float(input("Druga kateta: "))
     
    -

    pokliče funkcijo input, ki povpraša uporabnika po imenu in si -shrani uporabnikov odgovor v spremenljivko ime.

    '''], +

    Imeni a in b sta spremenljivki (angl. variable). +Spremenljivke uporabljamo, kadar želimo kakšno vrednost shraniti, ki jo bomo +potrebovali kasneje v programu. Imena spremenljivk so lahko poljubno + dolga, v našem primeru bi jim lahko rekli tudi kateta_a in kateta_b. + Pri programiranju velja, da izbiramo taka imena spremenljivk, + ki bodo naredila program berljiv.

    + '''] - 'expressions_python': [''' -

    Računanje: če v Pythonu napišemo izraz, se bo ta izračunal. Npr., če napišemo

    + 'math_functions': [''' +

    Dolžina hipotenuze je kvadratni koren vsote kvadratov katet oz.

    +

    c = sqrt(a**2 + b**2)

    +

    Dvojni znak za množenje ** je potenciranje. Funkcija sqrt +izračuna kvadratni koren. Vendar pa funkcija sqrt ni vgrajena v Python, +temveč se nahaja v ločenem matematičnem modulu oz. zbirki matematičnih funkcij. +Da bi lahko dostopali do teh funkcij, moramo ta modul najprej uvoziti:

    -3 + 6
    -
    -bo Python seštel vrednosti 3 in 6 in ... rezultat pozabil. Kadar pa želimo 
    -rezultat shraniti, za to uporabimo prireditveni stavek, kjer na levo 
    -napišemo ime spremenljivke, na desno pa izraz:

    -
    -c = 2 * a * (3 + b)
    +from math import *
     
    -

    Kot vidite, izraz lahko uporablja tudi spremenljivke.

    '''], +

    Poleg funkcije sqrt matematični modul vsebuje še vrsto +uporabnih matematičnih funkcij, kot so: log, exp, trigonometrične funkcije, itd. +Opis modula najdete v Pythonovi dokumentaciji.

    +'''], 'printing': ['''

    V Pythonu izpisujemo s funkcijo print. Če želimo izpisati več elementov, @@ -86,6 +91,12 @@ ki vsebuje naše ime, potem lahko napišemo: print("Ime mi je", ime, ".")

    '''], + 'radians': [''' +

    Vse triginometrične funkcije sprejemajo kot v radianih in ne v stopinjah.

    ''', +'''

    V stopinjah ima cel krog 360°, v radianih pa 2*pi. Zato je 360° ekvivalentno 2*pi.

    ''', +'''

    Formula za pretvorbo med stopinjami in radiani je:

    +kot_rad = kot * 2 * pi / 360'''] + 'name_error' : [general_exception['error_head'], general_exception['general'], general_exception['name_error'], '''

    Verjetno uporabljate spremenljivko, ki nima vrednosti. Ali v izrazu za izračun @@ -99,36 +110,11 @@ ki jo moramo najprej pretvoriti v tip float, če želimo z njo rač

     v = float(input(" ...
     
    -

    Zakaj je tako, boste razumeli kasneje, zaenkrat je dovolj, da to poznate.

    -

    Na primeru pretvarjanja temperatur:

    -
    -fniz = input("Temperatura [F]: ")
    -f = float(fniz)
    -
    -

    ali krajše, združeno v eno vrstico:

    -
    -f = float(input("Temperatura [F]: "))
    -
    -

    Funkcijo float lahko kličemo le, če je v nizu zapisano število, -npr. "10". Če imamo v nizu tudi kakšno črko, bo Python javil napako.

    '''], - - - 'not_callable' : [general_exception['error_head'], general_exception['general'], - general_exception['type_error'], ''' -

    V programu poskušate uporabiti število kot funkcijo, a to ne gre. -Verjetni razlog: Ali ste v izrazu pozabili na znak *. Pri pretvorbi temperatur bi namesto:

    -
    -C = 5/9(F – 32)
    -
    -

    morali napisati:

    -
    -C = 5/9 * (F – 32).
    -
    -

    Python ne zna izpuščati znaka za množenje, kot to delamo pri matematiki.

    '''], +'''], 'syntax_error' : [general_exception['error_head'], general_exception['general'], general_exception['type_error'], ''' -

    Ste mogoče pozabili na kakšen zaklepaj?

    '''], +

    Ste mogoče pozabili na kakšen zaklepaj ali pa narekovaje?

    '''], 'indentation_error' : [general_exception['error_head'], general_exception['general'], general_exception['indentation_error']], -- cgit v1.2.1