Oblig2 - obligatorisk oppgave nr. 2 (av 4) i INF1000 ­ høsten 2009

Leveringsfrist
Oppgaven må løses individuelt og leveres senest fredag 25. september 2009 kl 16.00 via Joly.  Viktig: Les slutten av oppgaven for detaljerte leveringskrav.

Formål
Formålet med denne oppgaven er å gi trening i bruk av forgreninger, løkker, arrayer og metoder, samt trening i å programmere kommunikasjon med bruker via terminal.

Oppgave
Utenfor kysten av Utopia er det et område med store oljeforekomster under havbunnen, og myndighetene i Utopia har bestemt seg for å selge rettighetene til å utvinne olje til oljeselskaper. Det aktuelle havområdet er rektangulært og er delt opp i et rutenett med 11 x 17 ruter (se figuren under), hvor radene er nummerert fra 0 til 10 og kolonnene er nummerert fra 0 til 16.  Hver rute kalles et utvinningsfelt (eller bare felt).  Hvert felt har et entydig navn på formen radnr-kolnr hvor radnr er et heltall mellom 0 og 10, og kolnr er et heltall mellom 0 og 16.  For eksempel angir 0-0, 0-1, 0-2, ... 0-16 feltene i øverste rad (fra venstre mot høyre) i figuren under.

kolonnenummer
radnr.
   0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16
 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
     

Feltene (eller mer presist: utvinningsrettighetene til dem) legges ut for salg enkeltvis.  Det er ingen grenser for hvor mange felter et oljeselskap kan eie, men et felt kan ikke ha mer enn ett oljeselskap som eier (dvs. hvert felt er enten ikke solgt eller det eies av ett oljeselskap).

Myndighetene i Utopia trenger nå et datasystem som kan holde rede på hvilke felter som er solgt og hvilke eiere disse har.  Systemet skal også holde rede på hvor mye olje (målt i antall fat) som er utvunnet i hvert felt.  Brukeren av systemet skal være en funksjonær som jobber for myndighetene i Utopia.  Når et oljeselskap ønsker å kjøpe et gitt felt, ringer de funksjonæren som så bruker ditt program for å registrere kjøpet av feltet.  Funksjonæren skal også kunne få ut fra programmet en oversikt over feltene med eiere og en del andre ting (se under).

Programmet skal være kommandostyrt: det skal kunne ta imot en kommando fra brukeren, utføre kommandoen, ta imot ny kommando, osv., helt til brukeren ønsker å avslutte. Mer konkret skal programmet oppføre seg slik sett fra brukerens side:

Programmet skal gjenta de tre trinnene ovenfor helt til brukeren gir kommando om å avslutte.  Brukeren skal kunne gi følgende kommandoer:

  1. Kjøp felt:
    Denne kommandoen vil funksjonæren gi hvis et oljeselskap ringer og sier at de ønsker å kjøpe et felt.  Programmet skal da først spørre om navnet på feltet som ønskes kjøpt og navnet på det oljeselskapet som ønsker å kjøpe feltet.  Deretter skal programmet sjekke om feltet er ledig (dvs. ikke har noen eier):

    (a) Hvis feltet er ledig skal programmet registrere at det inntastede oljeselskapet nå eier det aktuelle feltet.  Programmet skal også skrive ut på skjermen at kjøpet gikk i orden, f.eks. med en utskrift som dette: Felt 3-12 er nå kjøpt av Shell

    (b) Hvis feltet ikke var ledig skal programmet først sjekke om selskapet som eier feltet nå er det samme selskapet som bruker tastet inn.  I så fall skal programmet skrive en melding om det, f.eks. Oljeselskapet Shell eier felt 3-12 fra før!

    (c) Hvis verken (a) eller (b) var tilfelle, så betyr det at feltet som bruker tastet inn har en annen eier.  Da skal programmet skrive ut nåværende eier av feltet og spørre bruker om kjøpet virkelig skal gjennomføres, dvs. om feltet skal overtas av det nye selskapet.  Hvis bruker svarer ja skal kjøpet registreres som i del (a).  Hvis bruker ikke svarte ja skal det gis en melding til bruker om at ingen endring ble registrert.

  2. Lag feltliste:
    Programmet skal da gå gjennom alle feltene, og for de feltene som eies av et oljeselskap skal programmet skrive ut på skjermen feltnavnet og navnet på eier-selskapet. Listen skal også vise antall fat olje som er utvunnet i hvert felt (se deloppgave 4 ("Oppdater oljeutvinning)). Du kan anta at antall fat utvunnet olje er et heltall og at det kan representeres med en int-variabel. Eksempel på utskrift:
    Felt 3-4 eies av Shell. Total utvinning i dette feltet er 0 fat.
    Felt 5-6 eies av Esso. Total utvinning i dette feltet er 100 fat.
    Felt 10-0 eies av Shell. Total utvinning i dette feltet er 500 fat.
    
    Du avgjør selv i hvilken rekkefølge programmet skal gå gjennom alle feltene og skrive ut informasjon om eide felter (f.eks rad for rad fra toppen og ned).

  3. Lag oversiktskart:
    Programmet skal da skrive ut på skjermen et kart hvor hvert felt er markert med en "." hvis det er ledig og "x" hvis det er solgt (dvs. kjøpt av et oljeselskap).  Etter at kartet er skrevet ut skal programmet ditt skrive ut en linje som sier hvor mange felt som var solgt og hvilken andel av feltene det tilsvarer i prosent. Prosentandelen skal avrundes til ett desimal.   Her er et eksempel på hvordan kartet kan se ut: her er det 14 "x" slik at statistikken blir 14 solgte felt (7.5% av feltene).

        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
     0  x  x  x  .  .  .  .  .  .  .  .  .  .  .  .  .  .
     1  x  x  .  .  .  .  .  .  .  .  .  .  .  x  x  .  .
     2  .  x  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
     3  .  .  .  .  x  .  .  .  .  .  .  .  .  .  .  .  .
     4  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
     5  .  .  .  .  .  .  x  .  .  .  .  .  .  .  .  .  .
     6  .  .  .  .  .  .  .  .  .  .  x  .  .  .  .  .  .
     7  .  .  .  .  .  .  .  .  .  .  x  .  .  .  .  .  .
     8  .  .  .  .  .  .  .  .  .  .  .  x  .  .  .  .  .
     9  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
    10  x  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
    
           Antall solgte felt: 14 (7.5% av feltene)
    
  4. Halvårsoppdatering:
    Hver sjette måned må oljeselskapene ringe til funksjonæren og fortelle hvor mye olje de har utvunnet på feltene sine i løpet av de seks siste månedene.  Da bruker funksjonæren denne kommandoen for å registrere informasjonen.  Programmet skal spørre, for hvert felt som er solgt, hvor mye olje som er blitt utvunnet der de siste seks månedene (målt i antall fat), f.eks. slik:
    Antall fat utvunnet i felt 3-4 (Shell) siste 6 mnd.: 10
    Antall fat utvunnet i felt 5-6 (Esso) siste 6 mnd.: 20
    Antall fat utvunnet i felt 10-0 (Shell) siste 6 mnd.: 30
    
    Programmet skal registrere disse opplysningene (dvs. legge til de nye antall oljefat i arrayen som holder dataene om utvinning, f.eks. hvis utvinningen i felt 3-4 var 100 oljefat fra før, skal verdien nå bli 110).

  5. Lag statistikk:
    Programmet skal da regne ut og skrive ut på skjerm følgende opplysninger: (1) antall fat olje som utvinnes totalt; (2) største antall fat olje som utvinnes i et enkelt felt; (3) gjennomsnittlig antall fat olje som utvinnes i et felt (da tar du med i beregningen de feltene som har en eier, uansett om det er utvunnet olje eller ikke på feltet); og (4) antall oljeselskaper som opererer som eiere (hvis f.eks. 16 oljefelter er solgt og hver av disse eies av enten Shell eller Esso, så skal svaret være 2).

  6. Avslutt.
    Programmet skal da avslutte. Det er ikke meningen at programmet skal ta vare på (skrive til fil) de dataene som er registrert av funksjonæren.
Nedenfor ser du et eksempel på starten av en kjøring av programmet (bruker-input er markert med understreking). Utskriften er bare ment å illustrere hvordan kommunikasjonen kan foregå; dersom du ønsker å presentere menyen annerledes osv, så kan du gjøre det.

> java Oblig2

*** VELKOMMEN TIL UTOPIAS OLJEFELTOVERSIKT ***

Du har følgende valgmuligheter:
 1) Kjøp felt
 2) Lag feltliste
 3) Lag oversiktskart
 4) Halvårsoppdatering
 5) Lag statistikk
 6) Avslutt
Velg kommando: 1

** Kjøp felt **
Oppgi feltet som ønskes kjøpt: 3-6
Oppgi oljeselskapets navn: BP
Felt 3-6 er nå kjøpt av BP

Du har følgende valgmuligheter:
 1) Kjøp felt
 2) Lag feltliste
 3) Lag oversiktskart
 4) Halvårsoppdatering
 5) Lag statistikk
 6) Avslutt
Velg kommando: 2

** Lag feltliste **
Felt 3-6 eies av BP, utvinning: 0 fat

.... osv ....

Tips og forutsetninger som kan gjøres
For hvert felt er det to opplysninger som skal tas vare på: (1) navnet på oljeselskapet som eier det; og (2) hvor mye olje som er utvunnet i feltet.  Du kan bruke to to-dimensjonale arrayer til å lagre disse opplysningene:

  String[][] eier = new String[11][17];
  double[][] utvunnet = new double[11][17];

Dermed vil f.eks. eier[0][3] være navnet på oljeselskapet som eier feltet 0-3; og utvunnet[0][3] vil være antall fat olje som er utvunnet på dette feltet (sistnevnte array kunne også vært deklarert som en int-array - her står du fritt til å velge).  Det finnes andre måter å løse oppgaven på (vi kunne klart oss med en enkelt to-dimensjonal array med pekere til objekter av en klasse som vi selv lager - men denne teknikken gjennomgås ikke før senere i kurset og skal ikke anvendes i denne oppgaven).

Programstruktur:
Nedenfor er det en programskisse du kan bruke som utgangspunkt (du behøver ikke å følge det, men det er i alle fall et forslag til en ryddig start på programmet ditt).  Hvis du følger denne skissen så trenger du ikke endre noe i den første klassen (class Oblig2), det er nok at du gjør alle endringene dine i klassen Olje.


import easyIO.*;

class Oblig2 {
    public static void main(String[] args) {
        Olje ol = new Olje();
        ol.ordreløkke();
        System.out.println("Takk for nå");
    }
}

class Olje {
    In tast = new In();
    Out skjerm = new Out();

    < Her kan du deklarere arrayene eier[][] og utvunnet[][] >

    void ordreløkke() {
        int ordre = 0;

        while (ordre != 6) {

            < Her skriver du ut ordremenyen med nummer foran hver ordre
             slik at brukeren kan velge ordre ved å angi et nummer >
            
            < Be om og les inn ny ordre fra brukeren; legg ordrenummeret
             som brukeren oppgir i variabelen ordre >
                        
            switch (ordre) {
                case 1: kjøpFelt(); break;
                case 2: lagFeltliste(); break;
                case 3: lagOversiktskart(); break;

                < Fyll inn de resterende casene her >

                default: break;
            }
        }
    }

    // De andre metodene (en for hver ordre):

    void kjøpFelt() {
        < Be om og les inn rad-kol og oljeselskap >

        < Test om arrayen eier[][] allerede har et oljeselskap i den
         angitte rad-kol. Hvis ikke, registreres kjøpet, osv. >
    }

    void lagFeltliste() {
    
    }

    void lagOversiktskart() {
    
    }

    < Her legger du de øvrige metodene du trenger >
}


Her er noen tips og kommentarer til noen av kommandoene. Hver av disse punktene løses lettest hvis du for hvert punkt lager en metode og det er derfor et krav at din løsning har en metode for hver kommando (unntatt Avslutt-kommandoen):

  1. Kjøp felt:  Når programmet skal lese inn navnet på feltet som skal kjøpes, må du trekke ut radnummeret og kolonnenummeret fra feltnavnet.  Hvis f.eks. brukeren skriver 3-6 så må du altså "få tak i" tallene 3 og 6 siden du trenger disse når du skal sette inn navnet på oljeselskapet i eier-arrayen. Dette kan gjøres på flere måter; en av dem er å bruke setningene:
           int radnr = tast.inInt("-\n\r ");
           int kolnr = tast.inInt("-\n\r ");
    
    Her er det en variant av inInt() som brukes.  Det som står i anførselstegn er de tegnene som skal betraktes som skilletegn - altså de tegnene som inInt() skal se på som "blanke tegn" før og etter tallene.  De spesielle skilletegnene linjeskift ("\n") og vognretur ("\r") er ikke nødvendige å ta med blant skilletegnene, men kan godt være med som vist ovenfor.  Mellomroms-tegnet derimot må tas med inne i anførselstegnene hvis man vil at det skal betraktes som skilletegn (f.eks. hvis du vil godta at bruker taster inn "3 - 6" som feltnavn).

    I del (a) må programmet ha en måte å finne ut om et felt er solgt eller ikke.  En enkel måte å finne ut om f.eks. felt 3-6 er solgt er å se om eier[3][6] er satt til et navn eller ikke.  Rett etter at 2D-arrayen eier er deklarert er alle verdiene i arrayen lik den spesielle verdien null, og du kan derfor sjekke om 3-6 er ledig ved å teste om eier[3][6] == null.

    I del (b) skal du sammenligne tekst-verdier med hverandre og finne ut om de er like.  Vanligvis bruker man "==" i Java for å teste om to verdier er like, men dette kan i noen tilfeller gi et annen resultat enn ventet når det som sammenlignes er to tekster (årsaken til dette kommer vi tilbake til senere i kurset).  For å teste om to tekster er like skal man i stedet bruke metoden .equals(), slik: "if (tekst1.equals(tekst2))". Mer om dette kan du lese i avsnitt 6.4.1 på side 105 i læreboka.  Ved sammenligning av en tekst mot den spesielle verdien null derimot, så skal man bruke "==" (eller "!=" for ulikhet), se (a) ovenfor.

    I del (c) trenger du et ja/nei-spørsmål.  Det kan programmeres på mange måter, f.eks. vha. inChar("\n\r") og betrakte 'j' som ja-svaret, og alt annet som nei.  Det som står i parentesene til inChar("\n\r") angir at evt. linjeskift (\n) eller vognretur (\r) som brukeren har tastet ikke skal betraktes som svar, og kan være nødvendige fordi inChar også leser inn blanke tegn (se side 348 i læreboka).

  2. Lag feltliste:  Denne listen er nyttig for å sjekke at de andre deloppgavene fungerer, og kan programmeres f.eks. rett etter at del (a) av "Kjøp felt" er gjort.  For å forenkle arbeidet kan du først programmere utskriften til å bare vise "utvinning: 0 fat" på hver linje; og så, når du har programmert deloppgave 4 ("Halvårsoppdatering") utvider du listen til å vise riktig utvinning for feltene.

  3. Lag oversiktskart:  Denne oppgaven kan løses på mange måter.  Det enkleste er kanskje å programmere kartet alene først, og så når du har gjort det, kan du legge inn i samme kode som tegner kartet en teller-variabel som holder rede på hvor mange "x" det blir.

  4. Halvårsoppdatering:  Husk at du i denne oppgaven skal addere den innleste verdien til den verdien som allerede er registrert i systemet (siden verdien i registeret skal være det totale antall fat olje som er utvunnet i et felt).

  5. Lag statistikk:  Her kan du benytte en dobbelt for-løkke (dvs en for-løkke nestet inni en annen) for å løpe gjennom alle feltene, samtidig som du holder oversikt (med egne variable) over navnene på oljeselskapene du har støtt på til nå, summen av utvinningene du har sett så langt, antall felter med eiere så langt, og den maksimale utvinningen så langt. Når du har gått gjennom alle feltene har du den informasjonen som trengs for å besvare spørsmålene i oppgaven. Merk: for å holde oversikt over navnene på oljeselskapene du har sett til nå, kan du benytte en egen String-array (som da må deklareres og opprettes før den dobbelte for-løkken). Ideen er så at når du i den dobbelte for-løkken kommer til et felt med en eier (la oss si Shell), så sjekker du om Shell allerede ligger i din oversikt over eiere (det trenger du en egen for-løkke til, som da blir liggende inni den dobbelte for-løkken!). Ligger den ikke der fra før, så legger du den inn på første ledige plass i din oversikt over eiere, og holder samtidig orden på hvor mange eiere du så langt har sett.

Du kan gjøre egne forutsetninger etter behov så lenge disse ikke er i strid med oppgaven, men sørg for å kommentere disse i programmet.  Et tips: Sørg først for å få kommandoløkken til å fungere, dvs sørg for at programmet klarer å skrive ut lovlige kommandoer og lese inn en kommando på korrekt måte.  Deretter kan du gå videre og programmere de enkelte kommandoene (i vilkårlig rekkefølge).  Det er et krav at det lages minst en metode for hver ordre.

Husk å kompilere og teste programmet ditt ofte mens du lager det! (hvis ikke så kan det samle seg mange feil som blir vanskeligere å rette etterpå).

Leveringskrav
Du skal levere en egenprogrammert løsning (det er f.eks. ikke lov å "låne" programbiter av andre studenter eller å hente programbiter fra internett), og du plikter å ha lest og forstått følgende krav til innleverte oppgaver ved institutt for informatikk:

http://www.ifi.uio.no/studinf/skjemaer/erklaring.pdf
Oppgaven (.java-filen) skal leveres elektronisk i Joly-systemet:
http://obelix.ifi.uio.no:8080/wizard.html
Tilbakemelding blir normalt gitt innen to uker etter innleveringsfristen (og vanligvis litt raskere).

Dersom besvarelsen vurderes til ikke godkjent kan du få en begrunnelse for dette av gruppelæreren din, og hun/han kan isåfall gi deg en ny frist (som vil være kort og normalt ikke overstige 3-5 virkedager) for ny levering.

For mer informasjon se Reglementet for obligatoriske oppgaver:

www.ifi.uio.no/studier/studentinfo.html#oblig

Lykke til!