Versions Compared

Key

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

NB: WORK IN PROGRESS

 

Excerpt

Dette eksemplet handler om ConnectFour-spillet med en tydelig oppdeling i klasser for brikke, brett og spill-logikk.

Oppgavebeskrivelse

I spillet ConnectFour skal to spillere legge hver sine brikker i et rutenett på 7x7 ruter og prøve å få fire på rad før brettet er fullt. Oppgaven fokuserer på å realisere dette ved bruk av tre klasser, med en tydelig rollefordering: Piece-klassen inneholder verdien til en brikke på brettet, ConnectFour-klassen håndterer selve brettet og hvem sin tur det er, mens ConnectFourProgram-klassen håndterer tekst-basert interaksjon med spillerne gjennom konsollet. Denne tydelige oppdelingen i logikk og interaksjon (også kalt brukergrensesnitt) vil gjøre det lettere å senere lage et grafisk brukergrensesnitt uten å måtte programmere alt på nytt, siden logikk-klassen vil kunne gjenbrukes. For å gjøre klassene noenlunde uavhengig av hverandre brukes prinsippet om Innkapsling.

...

Piece-klassen trenger et felt for å holde en verdi (' ' for tom, 'x' for spiller x og 'o' for spiller o). Denne Dette feltet er innkapslet , men ikke validert for å holde koden så enkel som muligog validert; bare brikker med verdi ' ', 'x' eller 'o' kan opprettes og kun brikker med verdi ' ' kan endres.

Code Block
package connectfour;

public class Piece {

	private char value;

	public Piece(char value) {
		this.value = valuesetValue(value);
	}

	public char getValue() {
		return value;
	}

	public void setValue(char value) {
		if (" xo".indexOf(value) < 0) {
			throw new IllegalArgumentException("Illegal piece!");
		}
		if (this.value != ' ' && this.value != '\0') {
			throw new IllegalStateException("Cannot alter a non-blank piece!");		
		}
		this.value = value;
	}

	public String toString() {
		return "" + getValue();
	}
}

...

ConnectFour-klassen representerer brettet med ArrayLists ArrayLists av Piece-objekter inni en ArrayList. Her svarer den ytterste ArrayListen ArrayListen til radene og de innerste til kolonnene i spillet. I konstruktøren instansieres board-feltet og player-feltet. Videre har klassen metoder for å returnere Piece-objekt på posisjon rad, kolonne i brettet samt å sette en posisjon rad, kolonne til et nytt slikt objekt. Disse er private da de kun skal kunne brukes av klassen selv for å sørge for konsistent spilloppførsel (skal f.eks. ikke være lov å la en brikke "henge i løse luften"). Metoden drop(int) legger en ny brikke på brettet og hasWon() sjekker hvorvidt en spiller har vunnet (oppnådd fire på rad). Metodene getPlayer() og changePlayer() håndterer hvilken spiller som står for tur. toString()-metoden returnerer en streng-representasjon av brettet.

Code Block
package connectfour;


import java.util.ArrayList;

public class ConnectFour {
	private ArrayList<ArrayList<Piece>> board;
	private char player;

	public ConnectFour() {
		board = new ArrayList<ArrayList<Piece>>();
		for (int r = 0; r < 7; r++) {
			board.add(new ArrayList<Piece>());
			for (int c = 0; c < 7; c++) {
				board.get(r).add(new Piece(' '));
			}
		}
		player = 'o';
	}


	private Piece getPiece(int r, int c) {
		return board.get(r).get(c);
	}


	private void setPiece(int r, int c, Piece piece) {
		board.get(r).set(c, piece);
	}

	public boolean drop(int c) {
		if (getPiece(0, c).getValue() != ' ') {
			return false;
		} else {
			for (int r = 6; r >= 0; r--) {
				if (getPiece(r, c).getValue() == ' ') {
					setPiece(r, c, new Piece(player));
					return true;
				}
			}
			return true;
		}
	}

	public boolean hasWon() {
		for (int r = 0; r < 7; r++) {
			for (int c = 0; c < 7; c++) {
				if (getPiece(r,c).getValue() != ' ' && hasWonFromPosition(r,c)) {
					return true;
				}
			}
		}
		return false;
	}

	private boolean hasWonFromPosition(int r, int c) {
		for (int dr = -1; dr <= 1; dr++) {
			for (int dc = -1; dc <= 1; dc++) {
				if (dr != 0 || dc != 0) {
					if (hasWonFromPositionWithDirection(r,c,getPiece(r,c), dr, dc)) {
						return true;
					}
				}
			}
		}
		return false;
	}

	private boolean hasWonFromPositionWithDirection(int r, int c, Piece piece, int dr, int dc) {
		int counter = 0;
		while (0 <= r && r < 7 && 0 <= c && c < 7 && getPiece(r, c).getValue() == piece.getValue()) {
			r += dr;
			c += dc;
			counter++;
		}
		return counter >= 4;
	}


	public char getPlayer() {
		return player;
	}

	public void changePlayer() {
		if (player == 'o') {
			player = 'x';
		} else {
			player = 'o';
		}
	}

	public String toString() {
		String str = "";
		for (int r = 0; r < 7; r++) {
			str += "| ";
			for (int c = 0; c < 7; c++) {
				str += getPiece(r, c) + " ";
			}
			str += "|\n";
		}
		return str;
	}
}

...

Code Block
package connectfour;


import java.util.Scanner;

public class ConnectFourProgram {

	ConnectFour cf;


	public void init() {
		cf = new ConnectFour();
	}

	public void run() {
		Scanner scanner = new Scanner(System.in);
		while (! cf.hasWon()) {
			System.out.println(cf);
			System.out.println("Player " + cf.getPlayer() + ", enter index of column to drop next piece: ");
			int c = scanner.nextInt();
			if (cf.drop(c) && ! cf.hasWon()) {
				cf.changePlayer();
			}
		}
		System.out.println(cf);
		System.out.println("Congratulations player " + cf.getPlayer() + "! You have won the game.");
	}

	public static void main(String[] args) {
		ConnectFourProgram cfp = new ConnectFourProgram();
		cfp.init();
		cfp.run();
	}
}