Løsningsforslag ukeoppg. 10: 24. okt - 30. okt (INF1000 - Høst 2013)

Oppgavesettet: Ukeoppgaver 10.

[Nøkkeloppg.]: Oppgave merket med nøkkelsymbol er plukket ut som spesielt representativ for de viktigste temaene fra ukens forelesning, og alle bør ha som minimumsmål å løse denne selvstendig.

 

Oppgave 1 - HashMap: Hva skrives ut?

(Se oversikten på side 190 i læreboka)

import java.util.*;
class Personer {
    public static void main(String[] args) {
    HashMap <String, Person> register = new HashMap <String, Person> ();

    Person p1 = new Person("Ida", 19);
    Person p2 = new Person("Lars", 21);

    register.put(p1.navn, p1);
    register.put(p2.navn, p2);

// a)
    Person p = register.get("Ida");
    System.out.println(p.navn + p.alder);

// b)
    for (String s : register.keySet()) {
        System.out.println(s);
    }
// c)
    p1.alder = 24;
    for (Person p3 : register.values()) {
        System.out.println(p3.navn + ":" + p3.alder);
    }
// d)
    if (register.containsValue(p2) && ! register.containsKey("Elin")) {
        System.out.println(true);
    }
// e)
    register.remove("Lars");
    System.out.println(register.size() + " - " + register.isEmpty());
// f)
    System.out.println(register.remove("Ida") == null);
    System.out.println(register.remove("Ida") == null);
    }
}

class Person {
    String navn;
    int alder;

    Person(String navn, int alder) {
    this.navn = navn;
    this.alder = alder;
    }
}

Løsningsforslag

KJØREEKSEMPEL
$ java Personer
Ida19
Lars
Ida
Lars:21
Ida:24
true
1 - false
false
true

Oppgave 2 - Bank.java: Array vs. HashMap

a) Følgende program viser et enkelt banksystem med en array kontoer[], og metoder for å finne en konto vha. navn til eieren og vha. kontonummer. Skriv om programmet slik at det bruker en HashMap i stedet for arrayen kontoer[]. I første omgang lager vi én HashMap, med personnavn som nøkkel og et Konto-objekt som verdi, deklarert slik: HashMap kontoFraNavn = new HashMap();

Hvilke fordeler og ulemper får vi av å bruke HashMap her? Hva kan variabelen antKontoer erstattes med i programmet? (Anta foreløpig at personnavnene er unike og at hver person bare kan ha én konto i banken.)

class Konto {
    int nr; // kontonummer
    String navn; // eier
    int saldo;

    Konto(int nr, String navn, int saldo) {
    this.nr = nr;
    this.navn = navn;
    this.saldo = saldo;
    }

    void settInn(int innskudd) {
    saldo = saldo + innskudd;
    }
}

class Bank {
    Konto[] kontoer = new Konto[1000];
    int antKontoer = 0;

    public static void main(String[] args) {
    Bank b = new Bank();
    }

    Bank() {
        åpneNyttKonto(530010, "Nils", 4000);
        åpneNyttKonto(720020, "Elin", 8000);
        åpneNyttKonto(910030, "Tina", 9000);

        Konto k = finnKontoFraNavn("Elin");
        System.out.println("Elins kontonr: " + k.nr + ", saldo: " + k.saldo);

        k = finnKontoFraNr(530010);
        System.out.println("Kontonr. " + k.nr + " tilhører " + k.navn);
    }

    void åpneNyttKonto(int nr, String navn, int saldo) {
        Konto k = new Konto(nr, navn, saldo);
        kontoer[antKontoer] = k;
        antKontoer++;
    }

    Konto finnKontoFraNavn(String navn) {
    for (int i = 0; i < antKontoer; i++) {
        if (kontoer[i].navn.equals(navn)) {
           return kontoer[i];
        }
    }
    return null;
    }

    Konto finnKontoFraNr(int kontonr) {
    for (int i = 0; i < antKontoer; i++) {
        if (kontoer[i].nr == kontonr) {
        return kontoer[i];
        }
    }
    return null;
    }
}

KJØREEKSEMPEL:
Elins kontonr: 720020, saldo: 8000
Kontonr. 530010 tilhører Nils

Løsningsforslag

    
import java.util.*;

class Konto {
    int nr; // kontonummer
    String navn; // eier
    int saldo;
    Konto(int nr, String navn, int saldo) {
        this.nr = nr;
        this.navn = navn;
        this.saldo = saldo;
    }
    void settInn(int innskudd) {
        saldo = saldo + innskudd;
    }
}

class Bank2 {
    HashMap <String, Konto> kontoFraNavn = new HashMap <String, Konto>();
    HashMap <String, Konto> kontoer = new HashMap <String, Konto>();

    public static void main(String[] args) {
        Bank2 b = new Bank2();
    }

    Bank2() {
        åpneNyttKonto(530010, "Nils", 4000);
        åpneNyttKonto(720020, "Elin", 8000);
        åpneNyttKonto(910030, "Tina", 9000);

        Konto k = finnKontoFraNavn("Elin");
        System.out.println("Elins kontonr: " + k.nr + ", saldo: " + k.saldo);

        k = finnKontoFraNr(530010);
        System.out.println("Kontonr. " + k.nr + " tilhører " + k.navn);

        System.out.println("Antall kontoer: " + kontoer.size());
        avsluttKonto(k);

        System.out.println("Fins kontoen nå?: " + kontoer.containsValue(k));
        System.out.println("Antall kontoer nå: " + kontoer.size());
    }

    void åpneNyttKonto(int nr, String navn, int saldo) {
        Konto k = new Konto(nr, navn, saldo);
        kontoFraNavn.put(navn, k);
        kontoer.put("" + nr, k);
    }

    Konto finnKontoFraNavn(String navn) {
        return kontoFraNavn.get(navn);
    }

    Konto finnKontoFraNr(int kontonr) {
        return kontoer.get("" + kontonr);
    }

    void avsluttKonto(Konto k) {
        kontoFraNavn.remove("" + k.nr);
        kontoer.remove("" + k.nr);
    }
}

KJØREEKSEMPEL:

Elins kontonr: 720020, saldo: 8000
Kontonr. 530010 tilhører Nils
Antall kontoer: 3
Fins kontoen nå?: false

bLag en HashMap til, kalt kontoer, hvor du bruker som nøkkel kontonummeret konvertert til String, og fortsatt Konto-objektene som verdi. Vis at metoden finnKontoFraNr() blir enklere nå. Videre tenk deg at vi skal ha en metode for å fjerne en konto. Følgende kode viser hvordan det kan gjøres med arrayer. Hvor mange programsetninger trengs det når vi bruker én HashMap i stedet? Og med to?

// kontoer[] og flytte alle kontoene med høyere indeks en plass ned.
boolean funnet = false;
for (int i = 0; i < antKontoer && !funnet; i++) {
    if (kontoer[i] == k) {
        funnet = true;
        for (int j = i; j < antKontoer - 1; j++) {
            kontoer[j] = kontoer[j + 1];
        }
        antKontoer--;
        }
    }
}

Løsningsforslag

Se del a)

c) Disse oppgavene har begrensningen at personnavnene må være unike og at hver person bare kan ha én konto i banken. Hvordan ville man unngått disse begrensninger i et mer avansert system? Hvilke fordeler og ulemper ser du av å bruke HashMap-er i stedet for 2D-arryaer i Oblig 3? (foreslå mulige nøkkel/verdi-kombinasjoner). Hint: Se avsnitt 9.11 på side 191 i læreboka for forskjellene mellom arrayer og HashMap-er.

Løsningsfoslag

I store systemer passer det bedre å ha personnummer som nøkkel eller noe annet som er unikt for hver verdi, i stedet for navn alene. Verdi kan være et Person-objekt, som i sin tur kan ha en objektvariabel av type HashMap som refererer til alle kontoene for personen. Hvis programmet trenger å finne personer ut fra navn så kan man likevel bruke navn som nøkkel i en tilleggs-HashMap, som f.eks. kan ha som verdi en HashMap over personene med det navnet.

Arrayer passer best å bruke når maks. antall elementer er kjent på forhånd, når vi trenger en gitt rekkefølge på dataene, og når indeksene er numeriske. HashMap er bedre når maks. antall elementer er ukjent, eller man trenger å slå opp i dataene vha. "indekser" som er noe annet enn tall (f.eks. tekster), og når rekkefølgen på dataene ikke er avgjørende. Med HashMap må dataene være objekter (pekere), ikke primitive typer, men det finnes objekt-typer for alle de primitive: Integer, Double, Character, Boolean.

 

Oppgave 4 - Kort og Kortstokk

 

Programmer enum Type, som kan være Hjerter, Ruter, Spar eller Kløver. Programmer også public enum Kort, som inneholder en Type og et tall mellom 1-13, og en klasse Kortstokk. Kortstokken skal ta vare på 52 Kort i en beholder (f.eks et array). Programmer en "dealer" som har en kortstokk og skal ha metoder for å kontrollere at alle spillekortene er i Kortstokken og denne skal returnere true hvis kortstokken kan brukes og false hvis kort mangler. Videre skal Dealeren ha metoder for å stokke kortstokken - dette skal da bytte om på rekkefølgen i Kortstokkens beholder (tips bruk Random.nextInt(52) for å finne ut hvilken plass) og for å dele ut kortene. Dette skal i første omgang bare skrive ut rekkefølgen av kortene til skjerm. Lag en metode i Kortstokk som oppretter sine kort og en metode bruk. Bruk random for å finne ut om noen kort blei tapt (og evt hvilke) under bruk. I såfall må du sette dette kortets plass i beholderen tom.

 

Løsningsfoslag

 

Forslag på hvordan oppgaven kan løses ved hjelp av enum

import java.util.Random;

public class EnumCardSimulation {
    public static void main(String[] args) {
	Kortstokk ks = new Kortstokk();

	System.out.println("--- Lager kortstokken");
	ks.makeDeck();

 	System.out.println("\n--- Skriver ut kortstokken");
	ks.printDeck();

	System.out.println("\n--- Stokker kortstokken");
	ks.dealer.shuffle(ks.deck);

	System.out.println("\n--- Skriver ut kortstokken");
	ks.printDeck();

	System.out.println("\n--- Sjekker om kortstokken er komplett");
	ks.dealer.validate(ks.deck);

	System.out.println("\n--- \"Spiller\" med kortstokken");
	ks.playWithDeck();

	System.out.println("\n--- Sjekker om kortstokken er komplett");
	ks.dealer.validate(ks.deck);

	System.out.println("\n--- Skriver ut kortstokken");
	ks.printDeck();
    }
}

class Kortstokk {
    Kort[] deck;
    Dealer dealer;

    Kortstokk() {
	deck = new Kort[52];
	dealer = new Dealer();
    }

    /**
     * Lager en komplett kortstokk med alle de 52 unike kortene.
     */
    void makeDeck() {
	for (int i = 0; i < 52; i++) {
	    deck[i] = Kort.getCard(i);
	}
    }

    /**
     * Simulerer lek med kortstokken, kart kan (og mest sannsynlig)
     * mistes, det vil si at noen kort vil bli dobbelt opp og
     * overskrive andre kort (så helt riktig simulering blir det ikke,
     * ettersom det "plutselig" kommer flere like kort)
     */
    void playWithDeck() {
	Random r = new Random();

	for (int i = 0; i < 52; i++) {
	    // Henter ut tilfeldig kort og legger de inn i kortstokken
	    deck[i] = Kort.getCard(r.nextInt(52));
	}
    }

    /**
     * Skriver ut hele kortstokken
     */
    void printDeck() {
	for (Kort k : deck) {
	    System.out.println(k);
	}
    }
}

class Dealer {

    /**
     * Sjekker om kortstokken inneholder alle de 52 forskjellige
     * kortene.
     *
     * @return true om kortstokken er komplett (og riktig)
     */
    boolean validate(Kort[] deck) {
	/* Denne boolske arrayen simulerer alle kortene i kortstokken,
	 * den er som standard initialisert til "false" på alle plassene */
	boolean[] found = new boolean[52];
	boolean completeDeck = true;

	for (int i = 0; i < deck.length; i++) {
	    /* Metoden cards[i].ordinal() henter ut verdien til kortet
	     * på plass "i", om det er flere kort av samme type vil
	     * flere kort ha samme verdi, og dermed vil vi få "huller"
	     * (altså plasser i arrayen) som er false
	     */
	    found[deck[i].ordinal()] = true;
	}

	for (int i = 0; i < found.length; i++) {
	    if (!found[i] ) {
		System.out.println("Stokken mangler: " + Kort.getCard(i));
		completeDeck = false;
	    }
	}

	if (completeDeck) {
	    System.out.println("Stokken er komplett");
	}
	return completeDeck;
    }

    /**
     * Stokker en kortstokk. Ingen kort går tapt, men de vil
     * sannsynligvis endre plassering (bruker Random-klassen til å
     * finne nye tilfeldige plasseringer på kortene).
     *
     * @see swap
     * @return den samme kortstokken som ble sent inn
     */
    Kort[] shuffle(Kort[] deck) {
	Random r = new Random();

	for (int i = 0; i < 52; i++) {
	    swap(deck, i, r.nextInt(52));
	}

	return deck;
    }

    /**
     * Bytter om på plasseringen på to kort i en kortstokk.
     *
     * @param cards Korstokken som det skal byttes kort i
     * @param i første kort som skal byttes
     * @param j andre kort som skal byttes
     */
    void swap(Kort[] deck, int i, int j) {
	Kort temp = deck[i];
	deck[i] = deck[j];
	deck[j] = temp;
    }
}

enum Type {
    Hearts, Diamond, Spades, Clubs;
}

enum Kort {
    Hearts1(1, Type.Hearts),
    Hearts2(2, Type.Hearts),
    Hearts3(3, Type.Hearts),
    Hearts4(4, Type.Hearts),
    Hearts5(5, Type.Hearts),
    Hearts6(6, Type.Hearts),
    Hearts7(7, Type.Hearts),
    Hearts8(8, Type.Hearts),
    Hearts9(9, Type.Hearts),
    Hearts10(10, Type.Hearts),
    Hearts11(11, Type.Hearts),
    Hearts12(12, Type.Hearts),
    Hearts13(13, Type.Hearts),
    Spades1(1, Type.Spades),
    Spades2(2, Type.Spades),
    Spades3(3, Type.Spades),
    Spades4(4, Type.Spades),
    Spades5(5, Type.Spades),
    Spades6(6, Type.Spades),
    Spades7(7, Type.Spades),
    Spades8(8, Type.Spades),
    Spades9(9, Type.Spades),
    Spades10(10, Type.Spades),
    Spades11(11, Type.Spades),
    Spades12(12, Type.Spades),
    Spades13(13, Type.Spades),
    Clubs1(1, Type.Clubs),
    Clubs2(2, Type.Clubs),
    Clubs3(3, Type.Clubs),
    Clubs4(4, Type.Clubs),
    Clubs5(5, Type.Clubs),
    Clubs6(6, Type.Clubs),
    Clubs7(7, Type.Clubs),
    Clubs8(8, Type.Clubs),
    Clubs9(9, Type.Clubs),
    Clubs10(10, Type.Clubs),
    Clubs11(11, Type.Clubs),
    Clubs12(12, Type.Clubs),
    Clubs13(13, Type.Clubs),
    Diamond1(1, Type.Diamond),
    Diamond2(2, Type.Diamond),
    Diamond3(3, Type.Diamond),
    Diamond4(4, Type.Diamond),
    Diamond5(5, Type.Diamond),
    Diamond6(6, Type.Diamond),
    Diamond7(7, Type.Diamond),
    Diamond8(8, Type.Diamond),
    Diamond9(9, Type.Diamond),
    Diamond10(10, Type.Diamond),
    Diamond11(11, Type.Diamond),
    Diamond12(12, Type.Diamond),
    Diamond13(13, Type.Diamond);


    private int value;
    private Type color;

    Kort(int value, Type color) {
	this.value = value;
	this.color = color;
    }

    static Kort getCard(int value) {
	for (Kort k : values()) {
	    if (k.ordinal() == (value))
		return k;
	}
	return null;
    }

    public String toString() {
	return color + " " + value;
    }
}

 

Tilbakemelding på dette oppgavesettet kan du sende mail til ingridgg [a] ifi.uio.no

 

Publisert 21. nov. 2013 10:23 - Sist endret 21. nov. 2013 10:36