8 - Git, IDE'er og et lite spill
Vi har fra før lært hvordan vi kloner et git-repositorie og hvordan vi dytter endringer dit. Men den kanskje viktigste funksjonen til git er som verktøy for å samarbeide om og koordinere arbeid med kode. I denne forelesningen skal vi se litt nærmere på hvordan vi bruker git til dette.
For å forstå dette, oppretter vi et enkelt test-repositorie med en tekstfil, som vi kan teste git på.
Start med å opprette et repositorie du kaller "git-test":
Du skal så klone dette repositoriet. Finn en egnet plassering, for eksempel ved å lage en ny mappe med navn "SOK-1005".
cd <ønsket plassering>
, for eksempel cd SOK-1005
. git clone https://<token>@github.com/<brukernavn>/git-test
(bytt ut \<token> og \<brukernavn> med ditt token og brukernavn)
Opprett en ny tekstfil i den nye mappen "git-test". I windows og jupyter.uit.no
gjør du det ved å høyreklikke i mappen.
Åpne tekstfilen og kopier inn følgende linjer med tekst:
To be, or not to be, that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take Arms against a Sea of troubles,
And by opposing end them?
cd
+ mappenavn for å navigere deg inn i git-test
):git add .
git commit -m "added Shakespeare"
git push
Blir du bedt om brukernavn/passord, generer du et og bruker det som passord.
Til nå har vi forutsatt at bare én person arbeider med samme repositorie. Hele poenget med git er imidlertid samarbeid, og da oppstår det ofte "konflikt". Vi snakker ikke da om bitter uenighet, men at to personer gjør endringer i samme repositorie på en måte som git ikke klarer å ordne opp i.
Kort fortalt så klarer git fint å holde rede på at ulike personer endrer på ulike filer, men når ulike personer endrer samme fil oppstår det konflikt. La os simulere dette med den nye tekstfilen vi har laget.
Du skal nå ta rollene som begge parter i konflikten.
git add .
git commit -m "Improved Shakespeare"
Du har nå skapt en konflikt med deg selv. For å løse konflikten må du kjøre
git pull
Du skal da få en melding om at det er en konflikt du må løse. Åpne tekstfilen lokalt på nytt. Du vil da se at den er endret til noe slikt som dette:
To be, or not to be, that is the question:
<<<<<<< HEAD
Whether this nobler in the mind to suffer
=======
Whether 'it is nobler in the mind to suffer
>>>>>>> 2de43c361c099727ae6f3cabce81a2fb87fe3e48
The slings and arrows of outrageous fortune,
Or to take Arms against a Sea of troubles,
And by opposing end them?
Partitet mellom <<<<<<< HEAD
og >>>>>>> 2de43c361c099727ae6f3cabce81a2fb87fe3e48
er der konflikten befinner seg. Bytt ut teksten med
To be, or not to be, that is the question:
Whether it is nobler in the mind to suffer #" 'tis" means "it is" NOT "this", can I read?
The slings and arrows of outrageous fortune,
Or to take Arms against a Sea of troubles,
And by opposing end them?
forplikt og dytt endringene til github:
git add .
git commit -m "Modernized Shakespeare"
git push
Du har nå løst konflikten.
Av og til vil det være upraktisk å redigere i teksten, dersom endringene er for store og omfattende, eller dersom endringene for eksempel er i en jupyter-fil.
Git er laget for å samarbeide om kode, som er lagret i vanlige tekstfiler. Formatet til *.ipynb-filene som jupyter lager er også kode, men vi ser den ikke når vi åpner dokumentet i jupyter. Når git setter inn tekst i jupyter-filer, slik som over, vil den blir ubrukelig.
Den enkleste måten å løse slike situasjoner på, er å avbryte konfliktløsningen, omdøpe det lokale repositoriet og klone det originale fjernrepositoriet på på nytt. Det er ikke helt "etter boken", men å håndtere mer avanserte konflikter er det ikke plass til i dette kurset.
Om du har klonet repositoriet på nytt kan du åpne filen i repoen på nett og lokalt samtidig, og sammenligne. Du kan så endre filen i det klonede repositoriet, eller bytte ut filen i fjernrepositoriet med den nyere lokale filen. Dette gjør du på følgende måte:
Avbryt konfliktløsningen med git merge --abort
Omdøp eksisterende lokale repositorie til noe annet, for eksempel "git-test" til "git-test0".
Klon fjernrepositoriet på github på nytt (husk "cd .." slik at du befinner deg i mappen over eksempelvis "git-test0")
Sammenlign filene, gjør endringer eller lagre filen(e) i "git-test0" i det nyklonede repositoriet.
Forplikt og dytt til github:
git add .
git commit -m "Fixed Shakespeare"
git push
Generelt er det langt mer nøyaktig og sikrere å bruke gits konfliktløsningsmetode enn å selv sammenligne versjoner, men dersom du vet helt sikkert at din lokale versjon er den riktige, eller at det er opplagt hvilke endringer som skal gjøres, kan du bruke metoden over.
Følgende arbeidsflyt anbefales for git:
git add .
git commit -m "Update"
git pull
Da vil din kode hele tiden være oppdatert mot originalkoden på serveren. Dersom du oppdager konflikter, kan du håndtere dem selv eller ta opp konflikten med de andre på prosjektet. Generelt er det en god idé at flere ikke jobber med samme fil samtidig.
Du får beskjed når det skjer en konflikten etter å ha kjørt git pull
. Søk da etter "<<<<<<< HEAD" i teksten for å finne hvor konfliktene ligger, og rediger bort git-taggene som vist i eksemplet over.
Kjør alltid kommandoene i 1. før du dytter til orginalen på serveren (git push
)
En vanlig feil er at innloggingstedaljene som er lagret på maskinen din er utdaterte og feil. Når du bruker git vil ofte innloggingsdetaljene lagres på maskinen. Du kan løse problemet ved å slette detaljene
Om du må skrive inn passord hver gang du pusher til github, så kan du åpne filen som heter "config" under mappen ".git" i repositoriet lokalt. Du kan åpne den med "notepad" (eller installer Notepad++). Her kan du sette inn tokenet etterfulgt av "@" før "github.com" i nettadressen. Altså, om tokenet er "abddefg", brukernavnet er "bruker" og repositoriet heter "mitt_repo", skal adressen i config-filen se slik ut: "https://abddefg@github.com/bruker/mitt_repo"
Du må muligens endre på visningsalternativene i "Windows File Explorer" til å vise skjulte filer og mapper, for å kunne se "config"-filen.
Integrated Development Environment (IDE) er et program som hjelper deg å programmere. I motsetning til jupyter, brukes IDE'er til å redigere tekstfiler.
Jupyter er fint til å redigere korte programsnutter og å hente inn og kjøre ferdigprogrammerte pakker og moduler. Men skal du skrive kode på mer en femten linjer, bør du skrive dem i en tekstfil.
En av de mest brukte IDE'ene er Visual Studio Code, som støtter en lang rekke programmeringsspråk, inkludert python.
Før du kan bruke VSCode med python, må du sørge for at python er installert. Last det ned her. Dersom du har Windows, så vær sikker på at du installerer for alle brukere (krever adminrettigheter) og at du haker av for at python skal legges til i PATH.
Blotto er et spill der Oberst Blotto (du) skal disponere styrker over et gitt antall slagmarker. Spillet er sentralt innenfor økonomifaget og det som kalles spillteori. Vi kommer tilbake til noen interessante egenskaper med spillet senere, men la oss først spillet det.
Du laster ned spillet ved å klone det fra github. Du bruker da følgende kommando:
git clone https://github.com/espensirnes/blotto
Pass på at du er i ønsket mappe i kommandovinduet før du kloner. Les mer her om hvordan du navigerer i filsystemet i kommandovinduet. Naviger for eksempel til sok-1005-mappen du skapte over.
Du kan nå åpne spillet i VSCode. Om du har VSCode åpen, så går du på "File" og velger "Open Folder". Du kan så velge blotto-mappen du nettopp klonet.
Windows: For å lokalisere mappen du nettopp skapte i Windows, se hvilken bokstav stien begynner med, og se under "min Datamaskin"/"My Computer" for å gjenfinne rett stasjon.
Om du nå har åpen VSCode i blotto-mappen, velger du "File"->"New File" og så "File"->"Save As..." , og lagerer den nye filen som "run.py".
"run.py" er nå en python-fil, som du kan kjøre pythonkode i. Skriv for eksempel print("Hello World")
i filen og trykk ctrl+s for å lagre.
Før du kan kjøre koden i VSCode, må du konfigurere "debugging" (feilsøking).
Du kan nå trykke på -knappen oppe til venstre hver når du skal kjøre koden.
For å kjøre spillet skriver du inn:
import blotto
blotto.Run(6,100)
Du vil med stor sannsynlighet få en ModuleNotFoundError
når du forsøker å laste blotto
. Det skyldes i så fall at du ikke har installert alle pakkene du trenger. Om du har installert python riktig, for alle brukere, så kan du installere det du trenger med følgende kommandoer i kommandovinduet:
pip install tk
pip install Pillow
pip install numpy
pip3
i stedet for pip
Du kan legge inn en forhåndsdefinert strategi om du vil slippe å korrigere den i spillet hver gang. før blotto.Run()
kan du for eksempel bestemme deg for å satse alle troppene på fire av feltene.
Om du nå limer inn strategien under i "run.py", før blotto.Run(6,100)
, og bytter ut sistnevnte med blotto.Run(6,100,player_strategy)
, vil dette bli din utgangsstrategi:
import numpy as np
def player_strategy(n_battalions,n_fields):
#defining the array:
battalions=np.zeros(n_fields,dtype=int)
#assigning 25 battalions to the first four battle fields:
battalions[:4]=25
#randomizing to make strategy less predictable
battalions=battalions[np.random.rand(n_fields).argsort()]
#asserting that all and no more than all battalions are used:
assert sum(battalions)==n_battalions
return battalions
Koden over må altså limes inn i "run.py".
Legg merke til at vi importerer numpy øverst, siden denne brukes til å lage en strategi. Du byttet ut blotto.Run(6,100)
til blotto.Run(6,100,player_strategy)
fordi det tredje argumentet i blotto.Run angir din utgangsstrategi strategi.
Du kan forresten alltid sjekke hvilke argumenter en funksjon i har i VSCodev som en funksjon tar ved å holde ned Alt mens du har pekere over funksjonen.
Du kan endre koden over, og legge inn hvilken som helst strategi. I dette tilfellet er en startegi en funksjon som tar antall battaljoner og slagmarker som argumenter, og returnerer en liste over hvor battaljonene skal plasseres.
PC'en sin strategi i dette spillet er foreløpig ikke veldig smart. Strategien over vil nesten alltid slå PC'en, så la oss hjelpe PC'en med en litt smartere strategi:
def computer_strategy(n_battalions,n_fields):
battalions=np.zeros(n_fields,dtype=int)
#Will at present only work witih 100 battalions
battalions[0:1]=8
battalions[1:4]=30
battalions[4:]=1
#randomizing location to make strategy less predictable
battalions=battalions[np.random.rand(n_fields).argsort()]
assert sum(battalions)==n_battalions
return battalions
Lim koden inn i "run.py", og legg navnet på funksjonen inn som fjerde argument iblotto.Run
, slik at det blir blotto.Run(6,100,player_strategy, computer_strategy)
Om du ikke selv endrer på din forhåndsdefinerte strategi i spillet, vil du nå se at rollene er snudd om. Nå vinner PC'en alltid de fire siste slagmarkene så vidt. Problemet er at PC'en nå vet hva du skal velge. Det kan hjelpe litt å gjøre valgene dine tilfeldige, slik at PC'en ikke kan vite hvilke valg du kommer til å ta. Du kan skape litt tilfeldighet ved å legge følgende inn i strategien over, før assert
:
battalions=battalions[np.random.rand(n_fields).argsort()]
Denne koden sørge for at plasseringen av battaljonene blir tilfeldig. Du vil nå tape ofte, men ikke alltid.
Det er upraktisk og veldig ineffektivt å kjøre blotto.run
for å teste strategier. Det er enkelt å lage en funksjon som gir en poengsum for hvor god en strategi er mot en annen. Følgende funksjon returnerer en poengsum på -1 (tap), 0 (uavgjort) eller 1 (seier):
def call_battle(n_fields, n_battalions, player_strategy, computer_strategy):
c_battlions=computer_strategy(n_battalions,n_fields)
p_battlions=player_strategy(n_battalions,n_fields)
diff=p_battlions-c_battlions
points=sum(diff>0)-sum(diff<0)
return int(points>0)-int(points<0)
print(call_battle(6, 100, player_strategy, computer_strategy))
Å sjekke bare ett spill kan vi imidlertid ikke dra noen konklusjon av. Følgende kode kjører call_battle
100 000 ganger, og returner et score fra -1 (alltid tap) til 1 (alltid seier):
def test_strategies(n_fields,n_battalions,player_strategy, computer_strategy):
n_tests=100000
r=0
record=[]
for i in range(n_tests):
p=call_battle(n_fields, n_battalions,
player_strategy, computer_strategy)
record.append(p)
r+=p
return r/n_tests
test_strategies(6,100,player_strategy, computer_strategy)
Du kan nå gjøre endringer i både player_strategy
og computer_strategy
for å finne best mulig strategi, som fungerer mot flest mulig andre strategier!
Når du skal forsøke å lage best mulig strategi, kan det være lurt å benytte seg av mulighetene som ligger i IDE'en. Den store fordelen med en IDE er at du kan stoppe koden, og undersøke variabler under veis. Trykker du i margen til venstre, vil det komme et rødt punkt som indikerer et stoppunkt.
3) Gå sammen to eller flere og gjør følgende: a) Lag et repositorie 'blottokopi' på github som deles med alle b) Klon repositoriet og kopier innholdet i blottorepositoriet til 'blottokopi' c) Nå kan dere løse oppgavene under på hver deres PC, men arbeide på samme dokument d) Forsøk å lage og løse konflikter, for å se hvordan det fungerer
1) Forsøk å endre på funksjonen player_strategy
slik at den blir best mulig (gjør gjerne endringer i computer_strategy
også for å gi den best mulig konkurranse), og lagre strategien/funksjonen i en fil du kaller "strategy.py" i sok-1005-repositoriet. Koden vil bli kjørt mot den beste strategien til foreleser 100 000 ganger og får en score mellom -1 (alltid tap) og 1 (alltid seier). Du vil få vite hvordan du er rangert.
Det må være gjort større endringer i funksjonen enn bare å endre på antall bataljoner i player_strategy
, for å få godkjent.
2) Endre computer_strategy
og player_strategy
slik at du faktisk kan angi vilkårlig hvilket antall battalioner og slagmarker du skal ha (nå vil du få en assert error
om du oppgir noe annet enn hhv. 100 og 6.