Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
Excerpt

Et eksempel med gjennomgang på todimensjonale matriser laget ved å innkapsle en ArrayList.

Det hender ofte at man ønsker å holde på verdier i et rutenett. Mange av oppgavene som handler om spill på denne wikien omhandler nettopp et spill hvor man har et diskret todimensjonalt brett. Man har da mange ruter med to koordinater (x og y) som kan holde på en verdi. Men hvordan holder man på disse verdiene i programmet? Den typiske måten man holder mange verdier på er å putte dem i en ArrayList. Men elementene i en ArrayList har bare ett "koordinat", (kalt index). Du tenker kanskje at det hadde vært fint om det fantes en slags "ArrayList" som tok to koordinater i stedet for én. Du prøver å søke opp en slik klasse i Javas standardbibliotek. Dessverre finner du ingen ting.

Du blir altså nødt til å finne din egen løsning. Ideelt hadde vi hatt en klasse Grid som lar oss: 1. Grid(int sizeX, int sizeY): Lage et Grid-objekt av en spesifikk størrelse. 2. setCell(int x, int y, value): Sette verdien til en celle i nettet. 3. getCell(int x, int y): Få tilbake verdien til en celle i nettet.

En måte å implementere dette på, er å ta i bruk godt kjente for oss ArrayList, og oversette mellom 2- og 1-dimpensjonale koordinater. Vi tenker oss at vi deler opp listen i en del for hver rad. Delene må åpenbart være (minst) størelsen av en rad for å få plass til en rad. Dette koker ned til formelen: index = y*x_max + x. Eller på java:

Code Block
int calcIndex(int x, int y){
	return y*x_max + x;
}

Ved hjelp av denne metoden kan vi lage getCell og setCell:

Code Block
int getCell(int x, int y){
	int index = calcIndex(x, y);
	return grid.get(index);
}

void setCell(int x, int y, int value){
	int index = calcIndex(x, y);
	return grid.set(index);
}

En ting må legges merke til: Du kan ikke bruke set og get på ArrayList med indexer høyere enn antallet elementer du har add-et. Vi blir derfor nødt til å initialisere ArrayList-en med null-er:

Code Block
for(int i = 0; i < (x_max * y_max); i++){
	grid.add(null);
}

Satt sammen for vi kode som ser slik ut:

Code Block
class Grid {
	private ArrayList<Integer> grid = new ArrayList<Integer>();
	private int x_max;
	private int y_max;

	public Grid(int x_max, int y_max){
		this.x_max = x_max;
		this.y_max = y_max;

		for(int i = 0; i < (x_max * y_max); i++){
			grid.add(null);
		}
	}

	public int getCell(int x, int y){
		int index = calcIndex(x, y);
		return grid.get(index);
	}

	public void setCell(int x, int y, int value){
		int index = calcIndex(x, y);
		return grid.set(index);
	}

	private calcIndex(int x, int y){
		return y*x_max + x;
	}
}

Dette er en start, men tar med kun det mest vesentlige, og koden har mangler. Her er forslag til hvordan man kan forbedre koden hvis man tar den i bruk:

  • Bedre feilhåndtering:Siden vi ikke gjør en sjekk om x og y er innenfor gyldig område, vil det skje to uting:
    1. Det vil være mulig (ved et uhell) å komme seg ned til en lavere rad hvis x settes større enn max_x.
    2. Siden vi gjør omregning til et internt format, vil IndexOutOfBoundsException som kastes av ArrayList vise til index-verdien vi får fra calcIndex.
    Dette forbedres ved å kaste en egen IndexOutOfBoundsException når det gir mening.
  • Dokumentasjon: Hvis man putter javadocs på klasser og metoder, blir det lett for deg selv og andre å slå opp bruken av denne klassen. Da holder det i elipse å flytte musepekeren over en refereansen til koden for få oversikt.
  • Andre typer enn int: Koden over en begrenset til å bare kunne lagre int-er. Hvis man bruker generics (parametrisering av typer), er det mulig å gjøre klassen helt generell i hendhold til hvilken type verdier som lagres.