Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Expand
titleDel 1 - Dice og DiceIterator
Expand
titleInnledning til del 1

Denne delen av oppgaven omhandler Dice-klassen, som brukes til å representere (verdien av) én eller flere terninger (engelsk: dice = terninger, die = terning). En slik klasse kan være nyttig i mange typer terningspill, for å representere terninger som nettopp er slått eller de av et sett terninger som en får poeng for.

Merk at poengene ikkeer en del av Dice-klassen, de håndteres av andre klasser som beskrives senere.

Dice-klassen er vist under, ??? erstatter kodefragmenter som det spørres om i oppgaveteksten., mens ... står for kode som er utelatt fordi det ikke er viktig. Vi kreverher at terningverdiene skal representeres på en bestemt måte, som et sett tellere for hver mulig terningverdi, og har derfor oppgitt deklarasjonen av valueCounters. Det skal ikkevære nødvendig å deklarere andre felt enn dette.

Eksempel: Hvis et Dice-objekt representerer de fire verdiene 1, 2, 2 og 4, så vil tellerverdiene i valueCountersvære 1, 2, 0, 1, 0 og 0, altså 1 ener, 2 toere, ingen treere, 1 firer, ingen femmere og ingen seksere. For getDieValue-metoden sin del, vil eneren være på indeks 0, de 2 toerne vil være på indeks 1 og 2, og fireren vil være på indeks 3.

Code Block
/**
 * Represents a set of die values.
 */
public class Dice implements Iterable<Integer> {
    /**
     * Counters for each possible die value.
     * The counter at index i (0-5) is the counter for the die value i+1 (1-6).
     * I.e. the value at index 2 is the counter for die value 3.
     */
    private final int[] valueCounters;
 
    /**
     * Initializes this Dice with the values in dieValues.
     * @param dieValues sequence of die values, not counter values
     */
    public Dice(Iterator<Integer> dieValues) {
        ???
    }

    /**
     * Initializes this Dice with the values in dieValues.
     * @param dieValues sequence of die values, not counter values
     */
    public Dice(Iterable<Integer> dieValues) {
        ???
    }
 
    @Override
    public Iterator<Integer> iterator() {
        return new DiceIterator(this);
    }
 
    /**
     * @return the number of die values
     */
    public int getDieCount() {
        ???
    }
 
    /**
     * Die values are considered ordered, with the smallest die values
     * at the lowest index. The value at a specific index
     * must be computed from the counters in valueCounters.
     * @param dieNum
     * @return the value of die number dieNum
     * @throws an appropriate exception, if dieNum is out of range
     */
    public int getDieValue(int dieNum) {
        ???
    }
 
    /**
     * @param value
     * @return the number of dice with the provided value
     */
    public int getValueCount(int value) {
        ???
    }

    /**
     * @param dice
     * @return true if all die values in the Dice argument appear in this Dice
     */
    public boolean contains(Dice dice) {
        ???
    }
 
    /**
     * @param dice
     * @return true if this Dice and the one provided have exactly the same die values
     */
    public boolean isSame(Dice dice) {
        ???
    }
 
    /**
     * @param dice a Dice object
     * @return a new Dice instance with the all the die values in
     * this Dice and the Dice argument combined
     */
    public Dice add(Dice dice) {
        ???
    }
 
    /**
     * @param dice
     * @return a new Dice instance with the die values from this Dice, but
     * without those from the Dice argument
     */
    public Dice remove(Dice dice) {
        ???
    }
}
Oppgave a) - Konstruktører (8 poeng)

Skriv kode for de to konstruktørene (merk forskjellen i argumenttype), slik at valueCounters blir riktig initialisert. Du SKAL IKKE innføre andre felt. Du kan lage hjelpemetoder om du ønsker. For begge konstruktørene er argumentet en sekvens med terningverdier (altså ikke tellere) som den nyinitialiserte instansen skal representere.

Merk at det er lov å lage ekstra konstruktører for å gjøre andre metoder, f.eks. add og remove, enklere å skrive.

Expand
titleLF
Code Block
 

Vanlige feil:

 

Oppgave b) - Terningverdier (8 poeng)

Skriv metodene getDieCountgetDieValueog getValueCountiht. forklaringen og koden gitt tidligere (API-beskrivelsen).

Expand
titleLF
Code Block
 

Vanlige feil:

  • Et ekstra kommaskilletegn i toString-resultatet.
  • Ikke sjekke om score var ulik -1, før en evt. legger den til på slutten etter likhetstegnet.
  • Ideelt sett skal en sjekke syntaks og utløse hjelpsomme unntak. Men hvis en antar at syntaksen er riktig, og implisitt blir utløst unntak likevel, når en f.eks. antar at strengen inneholder et likhetstegn, så går det i praksis for det samme. Det er nesten verre å å lage så vanntett valueOf-kode at det ikke utløses unntak når syntaksen er feil.
  • Bruk av en annen type enn String[] for resultatet fra split, f.eks. List.
Oppgave c) - Flere metoder (8 poeng)

Skriv metodene containsisSameadd og remove, som alle tar et Dice-objekt som eneste argument. Merk at ingen av disse endrer på verken this-objektet eller argumentet.

Her er noen eksempler på bruken av disse metodene, hvor [t1, t2, t3, ... tn] brukes som pseudo-synaks for et Dice-objekt som representerer terningverdiene t1-tn:

[1, 2, 2, 4].contains([1, 4]) returnerer true, mens

[1, 2, 4].contains([2, 2]) returnerer false.

[1, 2, 2, 4].isSame([1, 2, 2, 4]) returnerer true, mens

[1, 2, 2, 4].isSame([1, 2, 4]) returnerer false

[1, 2].add([1, 4]) returnerer [1, 1, 2, 4]

[1, 1, 2].remove([1, 4]) returnerer [1, 2]

Merk at removei kke har samme logikk som Collectionsin removeAll-metode.

Her er poenget å skjønne hvordan tabeller virker (opprettes, leses fra og skrives til) og logikken bak valueCounters-feltet, samt hvordan iterere med Iterator (hasNext() og next()) og Iterable (iterator()).

Code Block
public Dice(Iterator<Integer> dieValues) {
	this.valueCounters = new int[6];
	while (dieValues.hasNext()) {
		int dieValue = dieValues.next();
		if (! (dieValue >= 1 && dieValue <= 6)) {
			throw new IllegalArgumentException("A die value must be in the range 1-6");
		}
		// add one to the corresponding counter
		this.valueCounters[dieValue - 1]++;
	}
}

public Dice(Iterable<Integer> dieValues) {
	this(dieValues.iterator());
}

Vanlige feil:

Oppgave b) - Terningverdier (8 poeng)

Skriv metodene getDieCountgetDieValue og getValueCount iht. forklaringen og koden gitt tidligere (API-beskrivelsen).

Expand
titleLF

Når en først har tellerne i valueCounters, så er getDieCount- og getValueCount-metodene trivielle. getDieValue er litt mer kinkig, da en må beregne hvilket tall som vil falle på en bestemt indeks, uten noen liste over alle terningverdiene.

Code Block
public int getDieCount() {
	int count = 0;
	for (int counter : valueCounters) {
		count += counter;
	}
	return count;
}

public int getDieValue(int dieNum) {
	if (dieNum < 0 || dieNum >= getDieCount()) {
		throw new IllegalArgumentException(dieNum + " is out of range");
	}
	for (int dieValue = 1; dieValue <= 6; dieValue++) {
		int counter = valueCounters[dieValue - 1];
		if (dieNum < counter) {
			return dieValue;
		}
		dieNum -= counter;
	}
	// should never come here
	throw new IllegalArgumentException();
}

public int getValueCount(final int value) {
	return valueCounters[value - 1];
}


Vanlige feil:

 

Oppgave c) - Flere metoder (8 poeng)

Skriv metodene containsisSameadd og remove, som alle tar et Dice-objekt som eneste argument. Merk at ingen av disse endrer på verken this-objektet eller argumentet.

Her er noen eksempler på bruken av disse metodene, hvor [t1, t2, t3, ... tn] brukes som pseudo-synaks for et Dice-objekt som representerer terningverdiene t1-tn:

[1, 2, 2, 4].contains([1, 4]) returnerer true, mens

[1, 2, 4].contains([2, 2]) returnerer false.

[1, 2, 2, 4].isSame([1, 2, 2, 4]) returnerer true, mens

[1, 2, 2, 4].isSame([1, 2, 4]) returnerer false

[1, 2].add([1, 4]) returnerer [1, 1, 2, 4]

[1, 1, 2].remove([1, 4]) returnerer [1, 2]

Merk at removei kke har samme logikk som Collectionsin removeAll-metode.

Expand
titleLF

Disse metodene kan forsåvidt skrives kun vha. getDieValue-metoden og konstruktørene (som de fleste gjorde på den ordinære eksamenen), men det er mye enklere å utnytte at vi representerer terningene med tellere. Her utnytter vi også at vi kan lage tomme Dice-instanser, og så etterpå justere tellerne i valueCounters.

Code Block
// Et Dice-objekt inneholder et annet hvis det er minst like mange av hver terning-verdi
public boolean contains(final Dice dice) {
	for (int dieValue = 1; dieValue <= 6; dieValue++) {
		if (this.valueCounters[dieValue - 1] < dice.getValueCount(dieValue)) {
			return false;
		}
	}
	return true;
}


// To Dice-objekter er like hvis det ene inneholder det andre og omvendt!
// Evt. kan kan sjekke at alle valueCounters-verdiene er like
public boolean isSame(final Dice dice) {
	return contains(dice) && dice.contains(this);
}


// To Dice-objekter kan slås sammen ved å legge sammen tellerne
public Dice add(final Dice dice) {
	Dice result = new Dice(Arrays.asList());
	for (int dieValue = 1; dieValue <= 6; dieValue++) {
		result.valueCounters[dieValue - 1] += this.getValueCount(dieValue);
		result.valueCounters[dieValue - 1] += dice.getValueCount(dieValue);
	}
	return result;
}


// En kan trekke et Dice-objekt fra et annet ved å trekke den enes tellere fra den andres.
// En må huske å unngå negative tellere.
public Dice remove(final Dice dice) {
	Dice result = new Dice(Arrays.asList());
	for (int dieValue = 1; dieValue <= 6; dieValue++) {
		result.valueCounters[dieValue - 1] = Math.max(0, this.valueCounters[dieValue - 1] - dice.getValueCount(dieValue));
	}
	return result;
}
Expand
titleLF
Code Block
 

Vanlige feil:

 

Oppgave d) - DiceIterator (6 poeng)

Lag en implementasjon av Iterator<Integer>kalt DiceIterator, slik at den kan brukes slik det er vist i Dice sin iterator()-metode. Du kan anta at valueCounters-feltet i Dice er synlig i DiceIterator-klassen.

Expand
titleLF
Code Block
 

Vanlige feil:

 

...