Lab2

Forberedelser
Innlevering og automatisk retting

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:

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")

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.

FargeWavelength (nm)Frequency (THz)
Violet380 - 450790 - 670
Blue450 - 485620 - 670
Cyan485 - 500600 - 620
Green500 - 565530 - 600
Yellow565 - 590510 - 530
Orange590 - 625480 - 510
Red625 - 750400 - 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

Flytdiagram for frequency_or_wavelength_to_color

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, benytt type(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.

Illustrasjon av rektangel og punktIllustrasjon testcaser for 8a

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) og x_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 lik x2 og x_right er større enn eller lik x_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.

Illustrasjon av overlappende rektangler

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: Illustrasjon av testcasene for 8b

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.

Illustrasjon av sirkel og rektangel som ikke overlapper

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):

Illustrasjon av testcasene for 8c

Flytdiagram for circle_overlaps_rectangle

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
...


  1. Vår definisjon på en trekant tillater ikke “tomme” trekanter uten areal. ↩︎