Uke 5
Generelt tips: les alltid gjennom kursnotatene før du begynner på lab’en!
Oppgave 1
Oppgave 1 består av fire deler. Skriv alle funksjoner til de fire delene (A-D) i én felles fil: uke_05_oppg_1.py
Del A
I filen uke_05_oppg_1.py, skriv en funksjon multiply_5_minus_pi(my_number)
som:
- tar et argument
my_number
, - multipliserer dette med \(5\) og trekker fra akkurat \(3.14\)
- returnerer resultatet. Det er ikke nødvendig å printe ut resultatet.
Test koden din ved å legge til disse linjene nederst i uke_05_oppg_1.py filen:
from math import isclose
print("Tester multiply_5_minus__pi... ", end="")
assert isclose(1.86, multiply_5_minus_pi(1))
assert isclose(56.86, multiply_5_minus_pi(12))
assert isclose(611.86, multiply_5_minus_pi(123))
print("OK")
PS: Fra og med denne uken vil vi gi deg en såkalt ‘assert-test’ for hver oppgave (hvis det passer seg) som du kan bruke til å teste koden din og sikre at den fungerer som den skal.
En “assert” setning i Python brukes til å sjekke om en bestemt betingelse er sann (
True
). Hvis betingelsen er sann, vil programmet kjøre videre. Hvis betingelsen viser seg å være falsk (False
), vil “assert” setningen utløse “AssertionError” og programmet vil stoppe.
Hvis alt er som det skal, vil assert testen i Oppgave 1 Del A skrive ut
Tester multiply_5_minus_pi... OK
IKKE ha med
assert
i innleveringen, det kan stoppe de automatiske testene!
Del B
Nå skal vi prøve et likt problem som oppgave 1, men denne tiden med typen str
. Skriv en funksjon shout(text)
som:
- tar et argument
text
- legger til en “!” til slutten av ordet eller frasen,
- returnerer resultatet.
(Ikke print noe!)
Test koden din ved å legge til disse linjene nederst i uke_05_oppg_1.py filen:
print("Tester shout... ", end="")
assert "I love programming!" == shout("I love programming")
assert "Adventure awaits!" == shout("Adventure awaits")
assert "Excitement ahead!" == shout("Excitement ahead")
print("OK")
Del C
Skriv en funksjon som heter name_age(name, gender, age)
:
Funksjonen skal ta tre argumenter:
- navnet til en person,
- personens kjønn og
- personens alder.
- Funksjonen skal returnere en streng med setningen “
name
ergender
og erage
år gammel.” For eksempel skal name_age(“Ola”, “kvinne”, 7) returnere strengen “Ola er kvinne og er 7 år gammel.”
Test koden din ved å legge til disse linjene nederst i uke_05_oppg_1.py filen:
print("Tester name_age... ", end="")
assert "Ola er kvinne og er 7 år gammel." == name_age("Ola", "kvinne", 7)
assert "Sigurd er mann og er 20 år gammel." == name_age("Sigurd", "mann", 20)
print("OK")
Del D
Skriv en funksjon som heter kinetic_energy(m,v)
. Funksjonen skal ta to argumenter \(m\) og \(v\) og skal returnere \( \frac{1}{2}mv^2\).
Test koden din ved å legge til disse linjene nederst i uke_05_oppg_1.py filen:
from math import isclose
print("Tester kinetic_energy... ", end="")
assert isclose(4.0, kinetic_energy(2,2))
assert isclose(128.0, kinetic_energy(4,8))
assert isclose(2.5, kinetic_energy(5,1))
print("OK")
Oppgave 2
Del A
Begrepet \(pH\) er en forkortelse for potensialet til hydrogen. pH er en måleenhet som representerer konsentrasjonen av hydrogenioner i en løsning.
En løsning med hydr.-konsentrasjon \(0.1\frac{\text{mol}}{\text{L}} \)har pH-verdien \(1\),
En løsning med hydr.-konsentrasjon \(0.01\frac{\text{mol}}{\text{L}} \) har pH-verdien \(2\),
En løsning med hydr.-konsentrasjon \(0.001\frac{\text{mol}}{\text{L}} \) har pH-verdien \(3\), osv…
Om vi kaller konsentrasjonen for \([H⁺]\), beregnes pH-verdien med følgende ligning:
$$ pH = - log_{10}[H⁺]$$
og motsatt kan vi beregne \([H⁺]\) fra pH-verdien som:
$$ [H⁺] = 10^{- pH}$$
I filen uke_05_oppg_2.py skal du definere funksjonen conc_from_pH(pH)
skal ta som input en float tall som representerer pH-verdien i en løsning og skal returnere konsentrasjonen av hydrogenioner til løsningen (vi antar at enhet er \(\frac{\text{mol}}{\text{L}} \)).
Test koden din ved å legge til disse linjene nederst i uke_05_oppg_2.py filen:
from math import isclose
print("Tester conc_from_pH... ", end="")
assert isclose(0.1, conc_from_pH(1))
assert isclose(1e-7, conc_from_pH(7))
assert isclose(1e-10, conc_from_pH(10))
print("OK")
Del B
pH-skalaen beskriver surheten til løsningen: sur, nøytral eller basisk. En løsning med pH mindre enn 7 er en syre, nøyaktig 7 er en nøytral løsning og over 7 er en base.
Skriv funksjonen find_acidity(conc)
, og bør ta som input en konsentrasjons-verdi og returnere dens surhet som string: enten acidic, neutral eller basic.
print("Tester find_acidity... ", end="")
assert 'acidic' == find_acidity(0.1)
assert 'neutral'== find_acidity(1e-7)
assert 'basic' == find_acidity(1e-10)
print("OK")
Bruk \( pH = - log_{10}[H⁺]\)
Du kan importere log10 fra math-biblioteket
Oppgave 3
Tone ser etter drømmejobben, men har noen krav som skal oppfylles.
- Hun elsker Bergen og ville tatt en jobb der hvis den betalte 400 000 kr i året eller mer.
- Hun misliker Oslo og krever minst 950 000 kr for å jobbe der.
- Ethvert annet sted er hun fornøyd med å jobbe for 600 000 kr i året, med mindre det snakk om verdensrommet, i så fall ville hun jobbet gratis.
I filen uke_05_oppg_3.py, skrive funksjonen will_work(city, salary)
som tar inn sted og lønn som parametere og returnerer True
hvis Tone ville tatt jobben, False
hvis ikke.
print("Tester will_work...", end="")
assert not will_work('Oslo', 949_999)
assert will_work('Kolvereid', 600_000)
assert will_work('Bergen', 400_000)
assert not will_work('Bergen', 399_999)
assert not will_work('Kristiansand', 590_000)
assert will_work('Oslo', 950_000)
assert will_work('Verdensrommet', 10)
print("OK")
Oppgave 4
Del A
I filen uke_05_oppg_4.py skriv en funksjon cross_sum
med en parameter n
som returnerer tverrsummen av et gitt tall. Tverrsummen er summen av sifrene i tallet, for eksempel er tverrsummen av 12 lik 3, siden 1 + 2 = 3.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester cross_sum... ", end="")
assert 1 == cross_sum(1)
assert 3 == cross_sum(12)
assert 6 == cross_sum(123)
assert 10 == cross_sum(1234)
assert 10 == cross_sum(4321)
print("OK")
Du kan isolere det siste sifferet i et tall
n
med modulo-operasjonenn % 10
(for eksempel evaluerer 123 % 10 til 3).Du kan fjerne det siste sifferet i et tall
n
med heltallsdivisjonn // 10
(for eksempel evaluerer 123 // 10 til 12).Begynn med å opprette en variabel for tverrsummen, som i utgangsposisjon (før løkken starter) har verdien 0. Planen er å la dette være en løpende total, altså en variabel der vi adderer inn nye verdier flere ganger.
Så lenge tallet
n
er større enn 0: isoler det siste sifferet og legg det til i tverrsummen. Fjern så det siste sifferet fran
og fortsett med en ny iterasjon.Det finnes også en løsning med
str()
som er veldig pent.
Del B
I filen uke_05_oppg_4.py skriv en funksjon nth_number_with_cross_sum_x(n, x)
som returnerer det n’te tallet hvor tverrsummen av tallet er x.
Det første tallet med tverrsum 7 er bare tallet 7, mens det andre tallet med tverrsum 7 er 16. Derfor skal nth_number_with_cross_sum_x(1, 7)
returnere 7, mens nth_number_with_cross_sum_x(2, 7)
skal returnere 16.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester nth_number_with_cross_sum_x... ", end="")
assert 7 == nth_number_with_cross_sum_x(1, 7)
assert 16 == nth_number_with_cross_sum_x(2, 7)
assert 25 == nth_number_with_cross_sum_x(3, 7)
assert 19 == nth_number_with_cross_sum_x(1, 10)
assert 28 == nth_number_with_cross_sum_x(2, 10)
assert 37 == nth_number_with_cross_sum_x(3, 10)
assert 2000 == nth_number_with_cross_sum_x(10, 2)
print("OK")
Merk: i denne oppgaven vet du ikke før løkken starter hvor mange iterasjoner løkken skal ha. Derfor bør du velge en
while
-løkke, og ikke en for-løkke.
Bonus 1
Opprett en funksjon is_even_positive_int
som har en parameter x
. Funksjonen skal returnere True
hvis x
er et positivt partall av typen int
, og False
ellers.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester is_even_positive_int...", end="")
assert is_even_positive_int(123456) # True, dette er et positivt partall
assert not is_even_positive_int(-2) # False (er ikke positivt)
assert not is_even_positive_int(123) # False (er ikke et partall)
assert not is_even_positive_int("huffda") # False (er ikke en int)
print("OK")
For å sjekke om en variabel
x
er av typen int, benytttype(x) == int
.Benytt
%
-operatøren for å avgjøre om et tall er partall eller oddetall.
Bonus 2
Skriv en funksjon is_legal_triangle
som har tre parametre. La funksjonen returnere True
dersom de tre parametrene representerer postive tall som kan representere lengden på sidene i en trekant,1 og False
hvis en slik trekant ikke kan eksistere. Merk fra trekantulikheten at summen av ethvert valg av to sider alltid er større enn den tredje siden.
Funksjonen skal fungere dersom argumentene er enten float
eller int
; dersom et argument har en annen type skal funksjonen returnere False
, og ikke krasje.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester is_legal_triangle... ", end="")
assert is_legal_triangle(2, 2, 3) # True, dette er en mulig trekant
assert not is_legal_triangle(3, 2, 1) # False (1 + 2 er ikke større enn 3)
assert not is_legal_triangle("2", "2", "3") # False (dette er ikke tall)
print("OK")
Begynn med å sjekke at argumentene har riktig type. For hver parameter, sjekk om typen er int eller float, og hvis ikke returner
False
.For hver sidelengde, sjekk at summen av de to andre sidelengdene er større. Om du finner en sidelengde som er like lang eller lengre enn summen av de to andre, returner
False
.Til slutt returnerer du bare
True
Bonus 3
I denne oppgaven skal vi skrive en kunstig intelligens for å spille Joker fra Norsk Tipping. I dette spillet får man på forhånd vite fem hovedtall; for hvert av hovedtallene må man velge om man skal gå “opp” eller “ned” før et hemmelig vippetall avsløres. Dersom man valgte “opp” og det avslørte vippetallet er høyere eller lik hovedtallet, vinner man en større premie. Det samme skjer dersom man velger “ned” og vippetallet er lavere eller lik hovedtallet. Vi antar at de hemmelige vippetallene er tilfeldig valgt mellom 0 og 9.
Strategien vi skal implementere er å si “opp” dersom hovedtallet er 4 eller lavere, og si “ned” ellers.
Skriv en funksjon joker(x1, x2, x3, x4, x5)
som har fem parametre (x1, x2, x3, x4 og x5) som representerer hovedtallene vi får oppgitt når vi begynner å spille Joker. Funksjonen skal skrive ut fem linjer, hvor hver enkelt linje gir oss strategien, enten “opp” eller “ned”, for hvert av de fem hovedtallene. For eksempel skal et kall
joker(3, 4, 5, 6, 1)
skrive ut følgende til terminalen:
opp
opp
ned
ned
opp
Merk: denne funksjonen behøver ikke returnere noen verdi.
Bonus 4
Del A
Et hyperrektangel er et rektangel hvor sidene er vannrette og loddrette (ikke rotert). Vi kan representere et hyperrektangel med to koordinater \((x_0, y_0)\) og \((x_1, y_1)\) som representerer to diagonalt motsatte hjørner. I denne oppgaven skal du avgjøre hvorvidt et punkt befinner seg innenfor et slikt rektangel eller ikke.
Skriv en funksjon point_in_rectangle
som har seks parametre x0, y0, x1, y1, x2, y2
, hvor de fire første parametrene representerer et hyperrektangel, og de to siste representerer et vilkårlig punkt. La metoden returnere True
dersom punktet er innenfor rektangelet, og False
hvis ikke. Dersom punktet befinner seg akkurat på linjen, regner vi det som at den er innenfor.
Du skal ikke importere noen biblioteker for å løse denne oppgaven.
Test koden din:
print("Tester point_in_rectangle... ", end="")
assert point_in_rectangle(0, 0, 5, 5, 3, 3) # Midt i
assert point_in_rectangle(0, 5, 5, 0, 5, 3) # På kanten
assert not point_in_rectangle(0, 0, 5, 5, 6, 3) # Utenfor
print("OK")
Omregn rektangelet slik at du vet hva som er høyre og venstre, top og bunn. For eksempel, opprett variabler
x_left = min(x0, x1)
ogx_right = max(x0, x1)
. Tilsvarende for topp og bunn med y-aksen.Sjekk at punktet \((x_2, y_2)\) både befinner seg mellom venstre- og høyresiden, og også mellom topp og bunn.
For eksempel: punktet \((x_2, y_2)\) er mellom høyre- og venstre siden dersom både
x_left
er mindre eller likx2
ogx_right
er større enn eller likx_2
.
Del B
Skriv en funksjon rectangles_overlap
som har åtte parametre x0, y0, x1, y1, x2, y2, x3, y3
, hvor de fire første parametrene representerer ett hyperrektangel, og de fire siste representerer et annet. La metoden returnere True
dersom rektanglene overlapper hverandre, og False
hvis ikke. Vi sier at rektanglene overlapper selv om de kun deler ett enkelt punkt.
Du skal ikke importere noen biblioteker for å løse denne oppgaven.
Test koden din:
print("Tester rectangles_overlap... ", end="")
assert rectangles_overlap(0, 0, 5, 5, 2, 2, 6, 6) # Delvis overlapp
assert rectangles_overlap(0, 5, 5, 0, 1, 1, 4, 4) # Fullstendig overlapp
assert rectangles_overlap(0, 1, 7, 2, 1, 0, 2, 7) # Kryssende rektangler
assert rectangles_overlap(0, 5, 5, 0, 5, 5, 7, 7) # Deler et hjørne
assert not rectangles_overlap(0, 0, 5, 5, 3, 6, 5, 8) # Utenfor
print("OK")
- Omregn begge rektangler slik at du vet hva som er høyre og venstre, top og bunn (se hint for 8a).
- Dersom høyresiden til ett rektangel er til venstre for venstresiden av det andre, blir svaret false (tilsvarende logikk med topp og bunn). Husk å sjekke begge retninger.
Illustrasjon av testcasene over:
Del C
Skriv en funksjon circle_overlaps_rectangle
som har syv parametre x0, y0, x1, y1, x2, y2, r2
, hvor de fire første parametrene representerer et hyperrektangel, og de tre siste representerer en sirkel sentrert i \((x_2, y_2)\) med radius \(r_2\). La metoden returnere True
dersom sirkelen overlapper rektangelet, og False
hvis ikke. Dersom sirkelen og rektangelet deler kun ett enkelt punkt regnes det fremdeles som at de er overlappende.
Du skal ikke importere noen biblioteker for å løse denne oppgaven.
Test koden din:
print("Tester circle_overlaps_rectangle... ", end="")
assert circle_overlaps_rectangle(0, 0, 5, 5, 2.5, 2.5, 2) # sirkel i midten
assert not circle_overlaps_rectangle(0, 5, 5, 0, 8, 3, 2) # langt utenfor
assert circle_overlaps_rectangle(0, 0, 5, 5, 2.5, 7, 2.01) # langs kanten
assert circle_overlaps_rectangle(0, 5, 5, 0, 5.1, 5.1, 1) # på hjørnet
assert circle_overlaps_rectangle(0, 0, 5, 5, 8, 8.99, 5) # på hjørnet
assert not circle_overlaps_rectangle(0, 0, 5, 5, 8, 9.01, 5) # akkurat ikke
print("OK")
- Dersom sirkelens sentrum er inne i rektangelet, er svaret
True
. Bruk funksjonen du skrev i 8a for å sjekke dette. Du kan kalle på funksjonen, du trenger ikke å skrive logikken på nytt. For eksempel:if point_in_rectangle(...):
. - Konverter punktene fra x0 og x1 til venstrekant (minimum av x0 og x1) og høyrekant (maksimum) (se også hint til 8a). På samme måte, omgjør punktene y0 og y1 til topp og bunn.
- “Utvid” rektangelet med sirkelens radius i alle retninger. Hvis sirkelens sentrum er utenfor dette utvidede rektangelet (bruk funksjonen fra 8a igjen), er det garantert ikke noe overlapp.
- I de gjenstående tilfellene befinner sirkelen sitt sentrum seg i rammen rundt rektangelet (se figur over).
- Dersom sirkelens x-koodinat befinner seg mellom x-koordinatene til det opprinnelige rektangelet, er det overlapp.
- Tilsvarende for y-aksen.
- Hvis sirkelens sentrum ikke tilfredsstiller noen av de to punktene over, befinner det seg i et av hjørnene. Dersom sirkelens sentrum har større avstand enn \(r_2\) til samtlige hjørner i det opprinnelige rektangelet, er det ingen overlapp (f. eks. slik som på figuren over). For å finne avstanden, bruk funksjonen fra lab1.
Illustrasjon av testcasene oppgitt over (en sirkel per testcase):
if point_in_rectangle(...): # orginal rektangel
return True
elif not point_in_rectange(...): # utvidet rektangel
return False
elif ... # punkt er mellom venstre og høyresiden til rektangel (x-aksen)
return True
elif ... # punkt er mellom topp og bunn til rektangel (y-aksen)
return True
elif distance(...) # sirkelen overlapper hjørnet oppe til venstre
return True
elif ... # sirkelen overlapper hjørnet oppe til høyre
return True
...
Vår definisjon på en trekant tillater ikke “tomme” trekanter uten areal. ↩︎