Lab2
Kursnotater for tema som er nye i denne laben:
- En lab er en samling med én eller flere oppgaver.
- Hver lab kan gi opp til 25 poeng.
- Dersom du består alle oppgavene i hovedfeltet, får du 20 poeng. Alt eller ingenting.
- De resterende 5 poengene kan du få ved å gjøre oppgaver fra ekstrafeltet.
- Alle oppgaver rettes automatisk. Hvis du ikke består de automatiske testene, får du ikke poeng.
- De automatiske testene for grafikk-oppgaver sjekker bare at programmet ditt faktisk kjører, og så laster den opp bildet du lager i galleriet – den sjekker ikke om du faktisk har løst riktig oppgave. Vi gjør derfor en rask manuell sjekk på de grafiske oppgavene.
- Vi vil trekke poeng manuelt dersom vi oppdager at oppgaven åpenbart ikke er løst, eller man forsøker å trikse seg gjennom de automatiske testene.
- Hver lab kan leveres så mange ganger du vil; det er siste innlevering som teller. Du kan umiddelbart se resultatene på de automatiske testene etter innlevering.
Hver lab utgjør 2.5% av den endelige karakteren din i emnet. Du må få til sammen 100 poeng eller mer på labene for å kunne ta eksamen.
Det er veldig viktig at du siterer alle kilder og eventuelle samarbeid. Se mitt.uib for mer informasjon om vår policy på plagiat og samarbeid.
Det er lurt å levere inn mange ganger underveis. Du får umiddelbart en automatisk tilbakemelding på oppgavene, og du kan prøve igjen hvis noe ikke virker.
Innlevering av lab’er foregår via verktøyet Codegrade som du kommer til via mitt.uib.
- Gå til «Oppgåver» i menyen til venstre
- Klikk deg videre til CodeGrade ved å klikke på «Last lab i eit nytt vindauge»
- Last opp filene du har laget for lab’en og trykk på «Submit.»
Fremdeles problemer? Se (merk at videoen er litt gammel, så det kan være noen små forskjeller i hvordan det ser ut nå.)
Ser du ikke knappen du skal trykke på i mitt.uib?
- Dobbeltsjekk at du er innlogget på mitt.uib.
- Prøv å laste siden i nettleseren på nytt.
- Prøv en «force refresh» (F5 eller Ctrl+F5 eller Ctrl+Shift+F5 eller Ctrl+Shift+R eller Command+R eller Command+Shift+R avhengig av nettleser og operativsystem).
- Prøv å tøm cache i nettleseren din (se refreshyourcache.com for hvordan du gjør dette) og prøv på nytt.
- Prøv en annen nettleser.
Suppe
Programmet under tegner én boks med suppe. Kopier det inn i filen soup.py.
from uib_inf100_graphics.simple import canvas, display
def draw_soup_can(canvas, x, y, bg_color, text_color):
canvas.create_rectangle(x, y+10, x+100, y+130, fill=bg_color)
canvas.create_oval(x, y, x+100, y+20, fill='gray')
canvas.create_oval(x, y+120, x+100, y+140, fill='gray')
canvas.create_text(x+50, y+50, text='SOUP',
fill=text_color, font=('Arial', 16, 'bold'))
draw_soup_can(canvas, 50, 30, 'red', 'yellow')
# TODO: make three more calls to draw_soup_can with different arguments
display(canvas)
Skriv tre nye linjer med kode hvor du kaller funksjonen draw_soup_can
med andre argumenter, slik at du får tegnet fire bokser med suppe som vist her:
Marilyn
Dette programmet tegner en vakker kvinne fire ganger. Kopier det inn i filen marilyn.py.
from uib_inf100_graphics.simple import canvas, display
def draw_marilyn(canvas, x, y):
# Background
canvas.create_rectangle(x, y, x+100, y+100, fill='red', outline='')
# Face
canvas.create_oval(x+20, y+20, x+80, y+80, outline='yellow', width=2)
# Eyes
canvas.create_oval(x+35, y+40, x+45, y+50, fill='yellow', outline='')
canvas.create_oval(x+55, y+40, x+65, y+50, fill='yellow', outline='')
# Mouth
canvas.create_arc(x+35, y+50, x+65, y+70, start=180, extent=180,
fill='yellow', outline='')
# Drawing four faces
draw_marilyn(canvas, 50, 50)
draw_marilyn(canvas, 250, 50)
draw_marilyn(canvas, 50, 250)
draw_marilyn(canvas, 250, 250)
display(canvas)
For å gjøre tegningen litt mer interessant, endre draw_marilyn -funksjonen slik at den i tillegg til x og y også tar inn to nye parametre background_color og detail_color. Oppdater funksjonskroppen (kodelinjene inne i funksjonen) slik at den benytter disse fargene i stedet for hardkodete farger når den tegner
I de fire funksjonskallene som utfører tegningen, velg ulike farger etter eget ønske. Det endelige resultatet kan for eksempel se slik ut:
Strekmenn
Dette programmet (som du kjenner igjen fra lab1) tegner en strekmann. Kopier koden til stickmen2.py
from uib_inf100_graphics.simple import canvas, display
canvas.create_oval(60, 80, 140, 160) # Head
canvas.create_line(100, 160, 100, 280) # Body
canvas.create_line(50, 180, 150, 180) # Arms
canvas.create_line(100, 280, 50, 330) # Left leg
canvas.create_line(100, 280, 150, 330) # Right leg
display(canvas)
Oppgaven er å endre koden slik at tegningen av strekmannen skjer i en funksjon draw_stickman
som tar inn tre parametre canvas
, x
og y
. Tegn strekmannen i funksjonen slik at den som kaller på metoden enkelt kan flytte hele strekmannen rundt på skjermen ved å gi ulike argumenter for x og y.
Kall funksjonen to ganger med ulike argumenter for å tegne to strekmenn ved siden av hverandre, som vist her:
Den resulterende koden din kan for eksempel se ca slik ut:
from uib_inf100_graphics.simple import canvas, display
def draw_stickman(canvas, x, y):
# TODO: Kode som tegner strekmannen her
# Koden kan være en kopi av den originale
# sterk-mannen, men pluss på x på alle
# x-koordinater, og pluss på y på alle
# y-koordinater.
draw_stickman(canvas, 0, 0)
draw_stickman(canvas, 200, 0)
display(canvas)
Volum av boks
I denne oppgaven skal vi bli kjent med funksjoner med returverdi. I en fil volume_of_box.py, opprett en funksjon volume_of_box(w, h, d)
som returnerer volumet av en eske med bredde w
, høyde h
og dybde d
.
Volumet av en boks er definert som \(V = w \cdot h \cdot d\)
Du kan teste at funksjonen fungerer ved å legge til disse linjene på slutten av filen:
print('Testing volume of box... ', end='')
assert 30 == volume_of_box(2, 3, 5)
assert 1 == volume_of_box(1, 1, 1)
print('OK')
Om du har gjort alt riktig, skal det skrives ut Testing volume of box... OK
i terminalen når du kjører programmet.
Avstand
I en fil distance.py, skriv en funksjon distance(x1, y1, x2, y2)
som regner ut og returnerer avstanden mellom to punkter \((x_1, y_1)\) og \((x_2, y_2)\).
For å teste koden, kan du legge til denne linjen nederst i filen:
from math import isclose
print("Tester distance... ", end="")
assert isclose(3, distance(103, 42, 100, 42))
assert isclose(4, distance(2, 100, 2, 104))
assert isclose(5, distance(0, 3, 4, 0))
assert isclose(1.414213562373, distance(0, 0, 1, 1))
assert isclose(1.414213562373, distance(3, 4, 2, 3))
print("OK")
For å finne absoluttverdien av et tall kan du benytte
abs()
-funksjonen som er innebygget i Python.Operatoren for eksponentiering er
**
, f. eks. vil3**2
evaluere til9
.Å ta kvadratroten av et tall er det samme som å opphøye tallet i
0.5
. For eksempel,9**0.5
vil evaluere til3.0
.
Joker
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 grunntall; for hvert av grunntallene 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 grunntallet, vinner man en større premie. Det samme skjer dersom man velger “ned” og vippetallet er lavere eller lik grunntallet. Vi antar at de hemmelige vippetallene er tilfeldig valgt mellom 0 og 9.
Strategien vi skal implementere er å si “opp” dersom grunntallet er 4 eller lavere, og si “ned” ellers.
I filen joker.py, skriv et program som ber brukeren om 5 tall. Disse representerer grunntallene vi får oppgitt når vi begynner å spille Joker. Deretter skal programmet skrive ut enten “opp” eller “ned”, for hvert av de fem grunntallene. En kjøring av programmet kan se slik ut:
tall1 = 3
tall2 = 4
tall3 = 5
tall4 = 6
tall5 = 1
opp
opp
ned
ned
opp
Grisete samarbeid
Teamet ditt med utviklere skal tegne en fin gris, og dere har fordelt arbeidet som følger:
- Ola tegner grisens hode med en funksjon
draw_head
i filen pig_head.py. - Kari tegner grisens kropp med en funksjon
draw_body
i filen pig_body.py. - Din jobb er å skrive hovedfilen pig_main.py som binder sammen tegningene og som faktisk tegner en gris når programmet kjører.
I denne oppgaven skal du ikke endre på filene pig_head.py eller pig_body.py, du skal bare laste dem ned.
Ola og Kari er ferdig med arbeidet sitt; last ned filene de har laget (høyreklikk på linkene og velg «lagre» eller lignende). Opprett deretter en fil pig_main.py som du legger i samme mappe som filene fra Ola og Kari.
- Øverst i pig_main.py, importer funksjonene draw_head og draw_body fra henholdsvis pig_head og pig_body -filene.
- Du må også importere canvas og display fra uib_inf100_graphics.simple slik du pleier. På slutten av filen må du kalle på display(canvas), slik vi også pleier når vi jobber med grafikk.
# pig_main.py
from uib_inf100_graphics.simple import canvas, display
from pig_head import draw_head
from pig_body import draw_body
# TODO: kall på funksjonene draw_body og draw_head
...
display(canvas)
På de første linjene importerer du fra ulike kilder: uib_inf100_graphics.simple er et eksternt bibliotek du har installert, mens pig_head og pig_body er .py -filer som ligger i samme mappe som din egen fil. Det ser veldig likt ut i koden fordi det er veldig likt: det eksterne biblioteket er en .py -fil det også (bare at den ligger i en skjult mappe knyttet til Python-fortolkeren din).
For å gjøre ferdig oppgaven, må du utføre kall til draw_head og draw_body -funksjonene du nettopp har importert. Du må gjøre deg kjent med hvilke parametre disse funksjonene forventer ved å lese litt i filene til Ola og Kari. Når du er ferdig, skal du kunne kjøre pig_main.py og få et vindu som ser omtrent slik ut:
Belgisk flagg
I denne oppgaven skal vi lage en funksjon som tegner et belgisk flagg.
Opprett filen belgian_flag.py med en funksjon draw_belgian_flag som har fem parametere: canvas
, x1
, y1
, x2
, y2
. Funksjonen skal tegne et belgisk flagg på canvas med øvre venstre hjørne i punktet \((x_1, y_1)\) og nedre høyre hjørne i punktet \((x_2, y_2)\). Funksjonen trenger ikke å ha noen retursetning.
# belgian_flag.py
def draw_belgian_flag(canvas, x1, y1, x2, y2):
# TOOD: replace this function body with code to draw the Belgian flag
...
Merk: du skal ikke importere noe i belgian_flag.py. Når du kjører filen forventer vi heller ikke at noe skjer, siden programmet ikke inneholder noen kall til funksjonen. For å teste at funksjonen din fungerer, kan du i stedet opprette en ny fil belgian_flag_test.py i samme mappe og kopiere inn dette programmet:
# belgian_flag_test.py
from uib_inf100_graphics.simple import canvas, display
from belgian_flag import draw_belgian_flag
draw_belgian_flag(canvas, 125, 135, 275, 265)
draw_belgian_flag(canvas, 10, 10, 40, 36)
draw_belgian_flag(canvas, 10, 340, 390, 360)
display(canvas)
Om du har gjort alt riktig i belgian_flag.py og deretter kjører belgian_flag_test.py, skal det tegnes tre belgiske flagg som vist under:
Innramming
Opprett filen frame.py og kopier inn følgende kode:
|
|
Om du kjører koden, vil du oppdage at programmet krasjer på linje 15 med en AssertionError. Vi skjønner at noe er galt, men vi vet ikke hva. Vi skal nå benytte debuggeren for å se hvilken returverdi vi faktisk får i funksjonskallene på linje 15.
- Sett et breakpoint på linje 12 eller 13 og kjør programmet i debug-modus. Bruk step over -knappen for å gå noen steg, helt til neste linje som skal utføres (den markerte linjen) er linje 15.
- Undersøk variabel-området i debuggeren. Legg merke til hva
s
er nå. - Siden alt ser bra ut, fortsetter vi: trykk på step into for å gå inn i funksjonskallet til frame.
- Her kunne du trykket på «step over» for å gå steg for steg gjennom setningene i funksjonskroppen; men akkurat nå er vi er mest interessert i selve returverdien, så trykk i stedet på step out.
- Undersøk variabel-området i debuggeren på nytt. Legg merke til at det er en «variabel» der som heter
(return) frame
. Denne viser til returverdien fra funksjonskallet vi nettopp gikk ut fra. Hva er det som er feil?
Ta et skjermbilde frame_debug.png av debuggeren som viser variabel-området i debuggeren og hvilken verdi (return) frame
har. Last opp dette bildet som besvarelse på denne oppgaven.
PS: For å kunne se returverdien må du benytte deg av «step out» -knappen. Om du benytter en av de andre knappene når du forlater funksjonskroppen kan det være du utløser assert-krasjen.
Vi forventer at skjermbildet du leverer ser omtrent slik ut (men selvfølgelig uten sladden):
Forklar for deg selv: hva er forskjellen på «step over» og «step into»?
Bonus: hvilken return-setning ble utført? Start debuggeren på nytt og gå steg for steg gjennom funksjonskroppen helt til du ser hvilken return-setning som utføres. Feilen ligger kanskje her? Fiks feilen slik at testen passerer.
Paritet
I filen parity.py, skriv en funksjon parity(x)
som tar inn et tall x
og siden returnerer Partall
hvis tallet er et partall og Oddetall
hvis tallet er et oddetall. Du kan anta i funksjonen at x
er et heltall og har typen int
.
def parity(x):
# Skriv koden din her
For å teste funksjonen din kan du legge til dette på slutten av filen:
print("Tester parity... ", end="")
assert "Partall" == parity(0)
assert "Oddetall" == parity(1)
assert "Partall" == parity(42)
assert "Oddetall" == parity(99)
print("OK")
Benytt modulo (
%
) for å avgjøre om et tall er partall eller oddetall. Mer informasjon om modulo finner i kursnotatene om operatorer
Korteste ord
I filen shortest_words.py, skriv kode som leser inn 3 ord og skriver ut det korteste ordet. Om flere ord har den korteste lengden skal programmet skrive ut alle ordene.
Kjøring av programmet ditt skal se ut slik som følgende eksempelkjøringer:
Skriv et ord:
Game
Skriv et annet ord:
Action
Skriv et siste ord:
Champion
Game
Skriv et ord:
pineapple
Skriv et annet ord:
apple
Skriv et siste ord:
grape
apple
grape
Skriv et ord:
Four
Skriv et annet ord:
Five
Skriv et siste ord:
Nine
Four
Five
Nine
Lengste ord
I filen longest_word.py skal du lage et program som leser inn 3 ord 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 lengst lengde.
Eksempelkjøringer:
Skriv et ord:
Game
Skriv et annet ord:
Action
Skriv et siste ord:
Champion
Champion
Skriv et ord:
pear
Skriv et annet ord:
apple
Skriv et siste ord:
grape
apple
Skriv et ord:
Four
Skriv et annet ord:
Five
Skriv et siste ord:
Nine
Four
Overlappende sirkler
I denne oppgaven skal du skrive et program som avgjør hvorvidt to sirkler overlapper. En sirkel kan beskrives ved hjelp av et koordinat for sirkelens sentrum \((x, y)\), samt en radius \(r\).
Opprett en funksjon circles_overlap(x1, y1, r1, x2, y2, r2)
i filen circles_overlap.py. La funksjonen returnere True
dersom to sirkler beskrevet med henholdsvis x1, y1, r1
og x2, y2, r2
overlapper, og False
hvis ikke.
To sirkler overlapper dersom avstanden mellom sirklenes sentrum er mindre enn eller lik summen av sirklenes radiuser.
For å teste funksjonen du har skrevet kan du legge til denne koden nederst i filen circles_overlap.py:
# Sirkel1 med sentrum (0, 0) og radius 1
# Sirkel2 med sentrum (1, 1) og radius 1
# Overlapper
print(circles_overlap(0, 0, 1, 1, 1, 1)) # Skal skrive ut True
# Sirkel1 med sentrum (0, 0) og radius 2
# Sirkel2 med sentrum (4, 1) og radius 2
# Overlapper ikke
print(circles_overlap(0, 0, 2, 4, 1, 2)) # Skal skrive ut False
# Sirkel1 med sentrum (0, 0) og radius 3
# Sirkel2 med sentrum (5, 0) og radius 2
# De overlapper hverandre i et enkelt punkt
print(circles_overlap(0, 0, 3, 5, 0, 2)) # Skal skrive ut True
Illustrasjon av testene:
Pop art
I denne oppgaven skal du lage din egen pop art i filen pop_art.py.
Pop art er en kunststil som ble populær på 1950-tallet. Pop art-kunstnere brukte ofte fargerike bilder av kjente personer, produkter og reklame, og benyttet seg mye av repetisjon av samme bilde i ulike farger. Den fremste eksponenten av pop art var Andy Warhol fra nydelige Pittsburgh PA, som blant annet lagde bilder av Marilyn Monroe og Campbell’s suppebokser.
Programmet ditt skal benytte en funksjon for å tegne et motiv, og funksjonen må kalles minst to ganger for å tegne variasjoner av det samme motivet ulike steder på lerretet. Du må benytte uib_inf100_graphics.simple for å lage tegningen. Du kan velge motivet ditt helt selv. Når du leverer oppgaven på CodeGrade, vil bildet ditt automatisk lastes opp i galleriet, hvor du også kan se hva dine medstudenter har laget. Noen eksempler på hva du kan lage:
Punkt i rektangel
Et hyperrektangel er et rektangel hvor sidene er vannrette og loddrette (ikke rotert). Vi kan representere et hyperrektangel med to koordinater \((x_1, y_1)\) og \((x_2, y_2)\) som representerer to diagonalt motsatte hjørner (du kan ikke anta noe om hvilken rekkefølge disse punktene kommer i, eller hvilke to motsatte hjørner i rektangelet de beskriver). I denne oppgaven skal du avgjøre hvorvidt et tredje punkt \((x_p, y_p)\) befinner seg innenfor et slikt rektangel eller ikke.
I en fil point_in_rectangle.py, skriv en funksjon point_in_rectangle
som har seks parametre x1
, y1
, x2
, y2
, xp
, yp
, 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.
Test koden din:
print("Tester point_in_rectangle... ", end="")
assert point_in_rectangle(0, 0, 5, 5, 3, 3) is True # Midt i
assert point_in_rectangle(0, 5, 5, 0, 5, 3) is True # På kanten
assert point_in_rectangle(0, 0, 5, 5, 6, 3) is False # 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(x1, x2)
ogx_right = max(x1, x2)
. Tilsvarende for topp og bunn med y-aksen.Sjekk at punktet \((x_p, y_p)\) både befinner seg mellom venstre- og høyresiden, og også mellom topp og bunn.
For eksempel: punktet \((x_p, y_p)\) er mellom høyre- og venstre siden dersom både
x_left
er mindre eller likxp
ogxp
er mindre eller likx_right
.
Hundeår
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 dog_years.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")
Skuddår
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 leapyear.py opprett en funksjon is_leap_year(year)
som tar inn et årstall og returnerer 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 is_leap_year(2022) is False # Ikke delelig med 4
assert is_leap_year(1996) is True # Normalt skuddår
assert is_leap_year(1900) is False # Delbart med 100
assert is_leap_year(2000) is True # Delbart med 400
print("OK")
Benytt modulo-operatøren (
%
) for å avgjøre om et heltall er delelig med et annet.
PS: Hvis alt er som det skal, vil programmet skrive ut
Tester is_leap_year... OK
Kollisjonsdeteksjon
Denne oppgaven består av to deler. Skriv funksjoner til begge deloppgaver (A-B) i én felles fil, collision_detection.py.
Del A
I filen collision_detection.py, skriv en funksjon rectangles_overlap
som har åtte parametre x1, y1, x2, y2, x3, y3, x4, y4
, hvor de fire første parametrene ett hyperrektangel, og de fire siste representerer et annet (et hyperrektangel representeres av to motsatte hjørner, men vi kan ikke gjøre noen ytterligere antakelser om hvilke hjørner). 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.
Test koden din:
print("Tester rectangles_overlap... ", end="")
assert rectangles_overlap(0, 0, 5, 5, 2, 2, 6, 6) is True # Delvis overlapp
assert rectangles_overlap(0, 5, 5, 0, 1, 1, 4, 4) is True # Fullstendig overlapp
assert rectangles_overlap(0, 1, 7, 2, 1, 0, 2, 7) is True # Kryssende rektangler
assert rectangles_overlap(0, 5, 5, 0, 5, 5, 7, 7) is True # Deler et hjørne
assert rectangles_overlap(0, 0, 5, 5, 3, 6, 5, 8) is False # Utenfor
print("OK")
- Omregn begge rektangler slik at du vet hva som er høyre og venstre, top og bunn (se hint for oppgaven Hyperrektangel).
- 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 i assert’ene over:
Del B
I filen collision_detection.py, skriv en funksjon circle_overlaps_rectangle
som har syv parametre x1, y1, x2, y2, xc, yc, rc
, hvor de fire første parametrene representerer to motstående hjørner i et hyperrektangel, og de tre siste representerer en sirkel sentrert i \((x_c, y_c)\) med radius \(r_c\). 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.
Test koden din:
print("Tester circle_overlaps_rectangle... ", end="")
assert circle_overlaps_rectangle(0, 0, 5, 5, 2.5, 2.5, 2) is True # på midten
assert circle_overlaps_rectangle(0, 5, 5, 0, 8, 3, 2) is False # langt utenfor
assert circle_overlaps_rectangle(0, 0, 5, 5, 2.5, 7, 2.01) is True # på kanten
assert circle_overlaps_rectangle(0, 5, 5, 0, 5.1, 5.1, 1) is True # på hjørnet
assert circle_overlaps_rectangle(0, 0, 5, 5, 8, 8.99, 5) is True # på hjørnet
assert circle_overlaps_rectangle(0, 0, 5, 5, 8, 9.01, 5) is False # bare nesten
print("OK")
- Dersom sirkelens sentrum er inne i rektangelet, er svaret
True
. Bruk funksjonen du skrev i oppgaven om punkt i rektangel for å sjekke dette.- Du kan importere funksjonen ved å legge til
from point_in_rectangle import point_in_rectangle
øverst i collision_detection.py.
- Du kan importere funksjonen ved å legge til
- La det minste x-koordinatet av
x1
ogx2
kallesx_left
, og la det største kallesx_right
. På samme måte, slutt å tenke på punkteney1
ogy2
, og regn i stedet ut punkteney_top
ogy_bottom
. - «Utvid» rektangelet med sirkelens radius i alle retninger. Hvis sirkelens sentrum er utenfor dette utvidede rektangelet (bruk funksjonen point_in_rectangle igjen), er det garantert ikke noe overlapp.
- I de gjenstående tilfellene befinner sirkelen sitt sentrum seg i rammen rundt rektangelet som er tegnet med stiplet linje i illustrasjonen over.
- Dersom sirkelens x-koordinat 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_c\) til samtlige hjørner i det opprinnelige rektangelet, er det ingen overlapp (f. eks. slik som på figuren over). For å finne avstanden, bruk funksjonen distance som du kan importere fra en tidligere oppgave (
from distance import distance
).
Illustrasjon av testcasene oppgitt over (en sirkel per testcase):
if point_in_rectangle(...): # sirkelens sentrum inne i rektangel?
return True
elif not point_in_rectange(...): # sentrum utenfor 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
...
Synlig lys
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.
Color | Wavelength (nm) | Frequency (THz) |
---|---|---|
Violet | 380 - 450 | 670 - 790 |
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 |
Forholdet mellom bølgelengde og frekvens er gitt ved formelen: $$ \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. Husk også på at vi har følgende forhold mellom enheter: $$ 1\text{ m} = 10^{9}\text{ nm} $$ $$ 1\text{ Hz} = 10^{-12}\text{ THz} $$ PS: Hz er det samme som 1/s.
I filen visible_light.py skal du skrive et program som spør brukeren om en enhet, enten nanometer (nm) eller terahertz (THz), og siden en verdi (et heltall). Programmet 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). Om du får en verdi som er akkurat på grensen mellom to farger skal du velge fargen med kortest bølgelengde (høyest frekvens) av de to.
Eksempelkjøringer:
Angi enhet (nm eller THz):
nm
Angi verdi i nm:
520
Green
Angi enhet (nm eller THz):
THz
Angi verdi i THz:
680
Violet
Angi enhet (nm eller THz):
nm
Angi verdi i nm:
320
320 nm er utenfor det synlige spekteret.
Angi enhet (nm eller THz):
THz
angi verdi i THz:
800
800 THz er utenfor det synlige spekteret.
Angi enhet (nm eller THz):
foo
Enheten må være i nm eller THz, det kan ikke være foo.
Det er mange ulike måter å løse denne oppgaven på. Programflyten over er et forslag som kan hjelpe deg å bryte ned programkoden i mer overkommelige deler. I skjemaet over er det to større oppgaver vi ikke har løst for deg:
- La \(f\) være frekvensen i antall Hz. Husk at verdien brukeren har gitt oss har enheten THz, så vi må først regne om. 1 THz er det samme som 10**12 Hz.
- Lysets hastighet er \(c = 3\cdot 10^8\text{ m/s}\).
- Plugg verdiene inn i formelen \(\lambda = c/f\) for å regne ut bølgelengden.
- Regn svaret om fra meter til nanometer.
- Det kan være lurt å benytte en if-elif -sekvens, hvor betingelsene sjekker verdien til bølgelengden opp mot grensene gitt i tabellen i oppgaveteksten.
- Ikke overskriv den enhet og verdi brukeren opprinnlig gav som input, men ta vare på dem i variabler slik at du kan skrive ut en feilmelding basert på disse hvis det trengs.