Lab2
Forberedelser
- Les ukens kursnotater.
- Les første del av kapittel 2 (frem til “while loop statements”) i Automate the Boring Stuff with Python.
- Les utforskning 2 med eksempler som er spesielt relevante for denne laben.
Innlevering og automatisk retting
- Innlevering skjer via mitt.uib
- For å få bestått, må du ha 100% riktig på CodeGrade
- Du kan levere så mange ganger du vil. Siste innlevering telles.
Oppgave 1
I denne oppgaven skal du opprette en funksjon find_longest_words
med tre parametre i filen uke_02_oppg_1.py. Funksjonen skriver ut de lengeste ordene. Om flere ord har den lengste lengden skal programmet skrive ut alle ordene.
For eksempel vil et kall til find_longest_words("Game", "Action", "Champion")
skrive ut
Champion
mens et kall til find_longest_words("apple", "carrot", "ananas")
vil skrive ut
carrot
ananas
og et kall til find_longest_words("Four", "Five", "Nine")
vil skrive ut
Four
Five
Nine
Oppgave 2
Regelen for å beregne om et år er et skuddår eller ikke er som følger:
- Vanligvis er et år som er delelig med 4 et skuddår (for eksempel 1996 var et skuddår);
- bortsett fra år som også er delelige med 100 (for eksempel 1900 er ikke skuddår);
- men hvis året som er delelige med 100 også er delelig med 400, da er det et skuddår likevel (for eksempel er 2000 et skuddår).
I filen uke_02_oppg_2.py opprett en funksjon is_leap_year(year)
som tar inn et årstall og returnere True
dersom det er et skuddår, og False
hvis ikke.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester is_leap_year... ", end="")
assert(not is_leap_year(2022)) # Forventer False (ikke delelig med 4)
assert(is_leap_year(1996)) # Forventer True
assert(not is_leap_year(1900)) # Forventer False
assert(is_leap_year(2000)) # Forventer True
print("OK")
Benytt modulus-operatøren (
%
) for å avgjøre om et heltall er delelig med et annet. Sjekk kursnotater om operatøren%
.
PS: Hvis alt er som det skal, vil programmet skrive ut
Tester is_leap_year... OK
Oppgave 3
Vanligvis sier man at et menneskeår tilsvarer 7 hundeår. Dette tar ikke hensyn til at hunder blir voksne når de er ca 2 år. Derfor kan det være bedre å regne begge de første 2 menneskeårene som 10.5 hundeår hver, og etter det regne hvert menneskeår som 4 hundeår.
I filen uke_02_oppg_3.py skal du opprette funksjonen human_to_dog_years
med én parameter som representerer antall menneskeår. La funksjonen returnere hvor mange hundeår dette tilsvarer.
Test koden din ved å legge til disse linjene nederst i filen:
def almost_equals(a, b):
return abs(a - b) < 0.00000001
print("Tester human_to_dog_years... ", end="")
assert(almost_equals(15.75, human_to_dog_years(1.5)))
assert(almost_equals(21.00, human_to_dog_years(2)))
assert(almost_equals(57.00, human_to_dog_years(11)))
print("OK")
PS: Dersom en assert feiler, kan det være lurt å se hva resultatet faktisk ble. Legg til en print-setning som viser resultatet av human_to_dog_years før assertene for å hjelpe til å feilsøke.
Oppgave 4
Her skal vi gjøre nesten samme sak som i oppgave 1 igjen, men med en liten forskjell.
I filen uke_02_oppg_4.py skal du lage en funksjon find_first_longest_word
som tar inn 3 strenger som parametre og skriver ut det lengste ordet. Men om flere ord har den lengste lengden skal programmet bare skrive ut det første ordet som har en lengste lengde.
Eksempelkjøring:
find_first_longest_word("Game", "Action", "Champion")
Champion
find_first_longest_word("apple", "carrot", "ananas")
carrot
find_first_longest_word("Four", "Five", "Nine")
Four
Oppgave 5a
Våre øyne oppfatter elektromagnetisk stråling med en bølgelengde fra 380 til 740 nanometer, eller med en frekvens fra 405 til 790 terahertz. Dette område er kalt synlig lys eller bare lys. elektromagnetisk stråling i synlig lys omdannes til farger i hjernen hos mennesker og dyr. Tabellen nedenfor viser hvor de ulike fargene av synlig lys ligger i spekteret. Wikipedia.
Farge | Wavelength (nm) | Frequency (THz) |
---|---|---|
Violet | 380 - 450 | 790 - 670 |
Blue | 450 - 485 | 620 - 670 |
Cyan | 485 - 500 | 600 - 620 |
Green | 500 - 565 | 530 - 600 |
Yellow | 565 - 590 | 510 - 530 |
Orange | 590 - 625 | 480 - 510 |
Red | 625 - 750 | 400 - 480 |
I filen uke_02_oppg_5.py skal du opprette funksjonen wavelength_to_color
med en parameter som representer bølgelengde-verdi i nanometer (nm).
Funksjonen skal returnere hvilken farge i synlig lys bølgelendgen tilsvarer. Om du får en verdi som er akkurat på grensen mellom to farger skal du velge fargen med kortest bølgelengde av de to. Om du får en verdi som er utenfor synlig lys område skal funksjonen returnere None
.
Test koden din ved å legge til disse linjene nederst i filen:
assert("Green" == wavelength_to_color(565))
assert("Violet" == wavelength_to_color(400))
assert(None == wavelength_to_color(6500))
Oppgave 5b
I filen uke_02_oppg_5.py skal du opprette en funksjon frequency_to_color
som har samme oppførsel som funksjonen i oppgave a, men som i stedet har en parameter som representerer en bølgefrekvens i terahertz (THz). Funksjonen skal returnere hvilken farge i synlig lys bølgefrekvensen representerer.
I denne funksjonen skal du først omregne fra terahertz til nanometer, og deretter gjenbruke funksjonen du skrev i oppgave a for å finne fargen.
Formelen for å regne om fra Hz til meter er
$$ \lambda = \frac{c}{f} $$
hvor \(\lambda\) er bølgelengde i meter, \(f\) er frekvens i Hz, og \(c = 3\cdot 10^8\text{ m/s}\) er lysets hastighet.
Test koden din ved å legge til disse linjene nederst i filen:
assert("Cyan" == frequency_to_color(610))
assert("Red" == frequency_to_color(450))
assert(None == frequency_to_color(1.5e-2))
- Husk at Hz er samme enhet som 1/s.
- Begynn med å regne om fra terahertz til hertz. \(1\text{ THz} = 10^{12}\text{ Hz}\).
- Benytt formelen for å regne ut bølgelengden.
- Regn svaret om fra meter til nanometer. \(1\text{ m} = 10^{9}\text{ nm} \).
- Du kan gjenbruke funksjonen fra forrige deloppgave med å kalle den med bølgelengden vi nettopp regnet ut som argument. Returner resultatet:
return wavelength_to_color(...)
Stiltips:
Du kan forkorte det endelige uttrykket om du vil, men det er ikke nødvendig. Det vil gi litt høyere presisjon grunnet avrundings-feil som vil skje når vi jobber med flyttall.
Husk at store eller små flyttall kan også skrives med e-notasjon i python:
3e8
betyr \(3\cdot10^8\).
Oppgave 5c
I denne oppgaven skal du bruke funksjonene fra 5a og 5b til å behandle forkjellige input fra brukere. I filen uke_02_oppg_5.py skal du skrive et funksjon frequency_or_wavelength_to_color
uten parametre som spør brukeren om en enhet, enten nanometer (’nm’) eller terahertz (‘THz’), og siden en verdi (et tall). Funksjonen skal skrive ut hvilken farge i synlig lys den enheten og verdien tillhører. Om du får en enhet som ikke er nm
eller THz
skal programmet ditt informere brukeren at enheten må være enten nm
eller THz
, og programmet skal avslutte kjøringen (se eksempler under for nøyaktig ordlyd). Om brukeren skriver inn en bølgelengde eller frekvens som er utenfor spektrumet, skal det gis melding om dette også (se eksempler).
Gjør et kall til denne funksjonen på slutten av filen, slik at når du kjører uke_02_oppg_5.py -filen er det kun dette som skrives ut til skjermen (fjern eventuelle kall til print du har brukt for å teste tidligere funksjoner i a og b).
Eksempelkjøringer:
frequency_or_wavelength_to_color()
Enter a unit (nm or THz):
nm
Enter a value in nm:
520
Green
Enter a unit (nm or THz):
THz
Enter a value in THz:
680
Violet
Enter a unit (nm or THz):
nm
Enter a value in nm:
320
There is no color with wavelength 320 nm
Enter a unit (nm or THz):
THz
Enter a value in THz:
800
There is no color with frequency 800 THz
Enter a unit (nm or THz):
nn
The unit must be either nm or THz, it can not be nn
Oppgave 6
I filen uke_02_oppg_6.py, 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.
Oppgave 7
I filen uke_02_oppg_7.py, 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
Oppgave 8a
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.
I filen uke_02_oppg_8.py, 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
.
Oppgave 8b
I filen uke_02_oppg_8.py, 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:
Oppgave 8c
I filen uke_02_oppg_8.py, 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. ↩︎