Commit b00def1f authored by Anna Maria Eilertsen's avatar Anna Maria Eilertsen
Browse files

Merge branch 'master' into 'patch-2'

# Conflicts:
#   SEM-2.md
parents fa057a56 f6bff0d7
......@@ -11,7 +11,7 @@
## Intro
Denne oppgaven går ut på å lage et program som lar en og to spillere spille [Fire på rad](https://en.wikipedia.org/wiki/Connect_Four) og [Tripp-trapp-tresko](https://en.wikipedia.org/wiki/Tic-tac-toe). To spillere skal kunne spille mot hverandre, og én spiller skal kunne spille mot en AI.
Denne oppgaven går ut på å lage et program for å spille [Fire på rad](https://en.wikipedia.org/wiki/Connect_Four) og [Tripp-trapp-tresko](https://en.wikipedia.org/wiki/Tic-tac-toe).
**Fire på Rad** spilles tradisjonelt ved at to personer slipper brikker av forskjellige farger ned i en tom, stående plastramme. Adskilte kolonner gjør at brikkene legger seg oppå hverandre og fargene danner rader loddrett, vannrett og diagonalt. Den første spilleren som klarer å få få fire på rad av sin egen farge vinner spillet.
......@@ -21,26 +21,27 @@ Denne oppgaven går ut på å lage et program som lar en og to spillere spille [
![](img/TicTacToe.gif)
## Krav til programmet
*Her beskriver vi funksjonelle krav til programmet og essensielle krav for å bestå.*
**Ditt program** skal støtte begge spillene. To spillere skal kunne spille mot hverandre, og én spiller skal kunne spille mot en AI.
## Krav til programmet
***Her beskriver vi funksjonelle krav til programmet og essensielle krav for å bestå.***
**Du må utvikle koden din selv.**
Du får kun utlevert et tomt Java-prosjekt og må lage klasser, pakker og tester selv. Løsningen blir vurdert på funksjonalitet, kodekvalitet, dokumentasjon og testing og at den viser forståelse av INF101-konsepter.
**Programmet må støtte både Tripp-trapp-tresko og Fire på rad.**
For eksempel kan man ved oppstart bli spurt om hvilket spill man ønsker å spille. Begge spillene skal oppføre seg i henhold til sine regler.
For eksempel kan man ved oppstart bli spurt om hvilket spill man ønsker å spille. *Begge spillene skal oppføre seg i henhold til sine regler.*
**Programmet må støtte både én og to spillere.** To spillere må kunne spille mot hverandre på samme maskin, for eksempel ved å ha hver sin tur til å gi input. Én spiller må kunne spille mot datamaskinen: du må altså implementere en eller annen form for AI for begge spillene.
**Programmet må støtte både én og to spillere.** To spillere må kunne spille mot hverandre på samme maskin, for eksempel ved å ha hver sin tur til å gi input. Én spiller må kunne spille mot datamaskinen: du må altså implementere en enkel AI for begge spillene. *Du kan få maks uttelling selv om AIen din gjør dumme valg.* Du kan få ekstrapoeng for smart AI.
**Programmet må ha brukergrensesnitt.**
Vi aksepterer program som spilles via terminalen ved hjelp av tekst-input og program som spilles med grafisk, klikk-bart grensesnitt. Du kan få maks uttelling selv om du har tekst-basert grensesnitt. *Du trenger kun implementere én av delene.*
Vi aksepterer program som spilles via terminalen ved hjelp av tekst-input og program som spilles med grafisk, klikkbart grensesnitt. Du kan få maks uttelling selv om du har tekst-basert grensesnitt. *Du trenger kun implementere én av delene.*
**Programmet må være velskrevet, forståelig, testet og dokumentert i henhold til INF101-pensum.** Et program som kjører perfekt, men som mangler tester, dokumentasjon, objekt-orientert design og [README.md](README.md) risikerer stryk.
**Du må fortelle oss hvordan vi skal rette programmet ditt.** Filen [README.md](README.md) skal inneholde din beskrivelse av hvordan man kjører programmet ditt, hva slags funksjonalitet du støtter, hvordan koden er organisert, kjente bugs og work-arounds, samt alle designvalg du har tatt. *Vi bruker din beskrivelse av programmet ditt for å gi deg poeng og vil kun rette kode og funksjonalitet som du beskriver i [README.md](README.md).*
**Programmet ditt må ligge i prosjektet du har fått utdelt av oss.** For at vi skal kunne enkelt kjøre og teste koden din har vi gitt deg et tomt Java prosjekt. Du må levere progreammet ved hjelp av dette prosjektet: program-koden skal ligge i `main` og test-kode i `test`. Ressurser som bilder og liknende legges i `resources`. *Alle kodefiler, resurser og dokumentasjon må være levert til ditt online GitLab repositorie for at vi skal rette det.*
**Programmet ditt må ligge i prosjektet du har fått utdelt av oss.** For at vi skal kunne enkelt kjøre og teste koden din har vi gitt deg et tomt Java prosjekt. Du må levere programmet ved hjelp av dette prosjektet: program-koden skal ligge i `main` og test-kode i `test`. Resurser som bilder og liknende legges i `resources`. *Alle kodefiler, resurser og dokumentasjon må være levert til ditt online GitLab repositorie for at vi skal rette det.*
### Innlevering
Du finner koden din i repositoriet med URIen:
......@@ -52,8 +53,7 @@ Oppgaven leveres inn ved å pushe til retting.ii.uib.no, [slik du har gjort med
**VIKTIG:** *Sjekk kvitteringssiden som kommer opp når du pusher, i tilfelle det skjer feil!*
Vi anbefaler at du gjør commit hver dag, eller hver gang du er ferdig med en
deloppgave, i tilfelle du mister det du jobber med på din egen maskin. Du kan levere inn så mye og ofte du vil. Versjonen som teller er den **siste du
pushet før innleveringsfristen**.
deloppgave, i tilfelle du mister det du jobber med på din egen maskin. Du kan levere inn så mye og ofte du vil. Versjonen som teller er den **siste du pushet før innleveringsfristen**.
### Poeng/karakter
Hvor mange poeng du får på oppgaven kommer an på hvor god løsningen din er. Både Fire på rad og Tripp-trapp-tresko er relativt enkele spill å implementere, og *kan* skrives i én fil uten klasser og metoder (i INF100-stil). ***Et program skrevet på denne måten vil score cirka 0 poeng selv om det støtter all funksjonalitet.***
......@@ -70,5 +70,7 @@ Dersom du har mangler eller bugs, eller dårlig organisert kode, vil du få trek
Du må gjerne diskutere oppgaven med andre, men dere må skrive individuell kode. Dersom du samarbeider tett med noen så beskriv det i README.md-filen. Se også om code review i [Tips og Triks](Tips.md#code-review-feedback-p%C3%A5-hverandres-kode)
**Ekstrapoeng.** Som på forige oppgave kan du få ekstrapoeng ved å implementere ekstra funksjonalitet. Forslag til dette ligger i [Tips og Triks](Tips.md).
**Ekstrapoeng.** Som på forige oppgave kan du få ekstrapoeng ved å implementere ekstra funksjonalitet. Dette kan inkludere fancy grafikk, super-smart AI, Facebook-integrasjon eller flere varianter av spillene. Flere forslag finner du i [Tips og Triks](Tips.md).
**Hjelp - hvor starter jeg?** Se [Tips og Triks](Tips.md).
......@@ -7,32 +7,46 @@
*Her ligger noen tips til oppgaven. Hvis du sitter fast kan denne lista hjelpe deg i gang.*
**Spør om hjelp og tips underveis.** Gruppelederne hjelper deg gjerne om du lurer på noe, er usikker på om det du har gjort er lurt, eller om du blir stående fast.
**NB: Spør gruppeleerne om hjelp og tips underveis.** Gruppelederne hjelper deg gjerne om du lurer på noe, er usikker på om det du har gjort er lurt, eller om du blir stående fast.
Sjekk timeplanen for interaktive grupper på [Mattermost](https://mattermost.ii.uib.no/inf101v20/) eller ta kontakt med din gruppeleder på epost.
## Hvordan komme i gang
Vi har to forslag til hvordan du kan angripe oppgaven.
Vi har to forslag til hvordan du kan angripe oppgaven. Du kan også gjøre en miks av disse to tilnærmingene.
**1. Start med å skrive et program som "funker".** Det kan være vanskelig å forutsi hvilket design koden din må ha. Du kan starte med å lage et program som *funker*, men som ikke oppfyller krav for design. Etter hvert som du når mål for funksjonalitet, kan du begynne å dele programmet opp i flere klasser og pakker.
For å jobbe på denne måten kan du velge *low-hanging fruit* - hva er den aller enkleste funksjonaliteten du kan tenke deg at programmet ditt har - og implementere det. Kanskje vil du kunne opprette, og skrive ut, et brett? I denne approachen trenger du ikke tenke på kompliserte ting som regler, grafikk og win-conditions enda: bare implementer den ene tingen. Deretter velger du neste *low-hanging fruit* og implementerer det.
**Start med å skrive et program som funker.** Det kan være vanskelig å forutsi hvilket design koden din må ha. Du kan starte med å lage et program som *funker*, men som ikke oppfyller krav for design. Etter hvert som du når mål for funksjonalitet, kan du begynne å dele programmet opp i flere klasser og pakker.
Etter hvert som kodebasen din blir større og mer unhåndterlig kan du *refaktorere* den til klasser, metoder og interface.
**Start med å designe en model.**
Hvis du liker å tenke abstrakt, kan det være du vil foretrekke å starte med å *modellere* problemet. Tenk over hva som er essensielle egenskaper ved de to spillene, hvordan du kan representere dem abstrakt og hvordan abstrakt funksjonalitet kan deles mellom dem. Beskriv hvilke interfaces og klasser du tror du trenger, hvilke metoder og feltvariabler de må ha, og start å tenke på hvordan du vil skrive tester for dem. Deretter kan du implementere abstraksjonen ("modellen") din. Se [modellerings-delen](https://retting.ii.uib.no/inf101.v20.oppgaver/inf101.v20.sem1/-/blob/master/information/modellering.md) av Sem1 for et eksempel til hvordan du kan gjøre og beskrive dette.
**2. Start med å designe en model.**
Hvis du liker å tenke abstrakt, kan det være du vil foretrekke å starte med å *modellere* problemet. Tenk over hva som er essensielle egenskaper ved de to spillene, hvordan du kan representere dem abstrakt og hvordan funksjonalitet kan deles mellom dem.
Du kan også gjøre en miks av disse to tilnærmingene. Andre nyttige teknikker du kan bruke er:
For eksempel kan du tegne opp et diagram av interfaces og klasser du tror du trenger, hvilke metoder og feltvariabler du tror de må ha. Tenk på hvordan du vil skrive tester for dem.
Deretter kan du implementere abstraksjonen ("modellen") din. Se [modellerings-delen](https://retting.ii.uib.no/inf101.v20.oppgaver/inf101.v20.sem1/-/blob/master/information/rogue.md) av Sem1 for et eksempel til hvordan du kan gjøre og beskrive dette.
**Andre nyttige teknikker du kan bruke er:**
**TDD.** Test Driven Development er et prinsipp for å utvikle kode der du *først* skriver testene, *deretter* koden. Fordelen med dette er at for å skrive tester må du tenke gjennom hvordan koden skal oppføre seg, og du får dermed sjansen til å skrive den riktig første gangen.
**TDD + Refactoring = <3.** Hvis du utvikler solide tester, så kan du skrive koden din i sykler: Deklarer en type; lag tester som beskriver funksjonaliteten du vil ha; implementer funksjonaliteten så testene passerer; forbedre koden slik at den oppfyller godt OO-design; len deg tilbake og nyt følelsen av å jobbe organisert.
**TDD + Refactoring = <3.** Hvis du utvikler solide tester, så kan du skrive koden din i sykler:
**Penn og papir.** Bruk egne diagrammer flittig: hvis det blir mye å holde styr på, tegn opp klassene og hvordan de kaller hverandre. Diagrammer er også en god plass å starte utviklingen: tegn opp typene du tror du vil trenge, og hvordan du tror de vil interagere. Utvid og endre på diagrammet etter hvert. Hvis du tror vi vil ha nytte av det til slutt så legg det gjerne ved innleveringen.
1. Deklarer en type (et interface eller klasse)
2. lag tester som beskriver funksjonaliteten du vil ha
3. implementer funksjonaliteten så testene passerer
4. forbedre koden slik at den oppfyller godt OO-design
5. len deg tilbake og nyt følelsen av å jobbe organisert.
## Brukergrensesnitt
Brukergrensesnittet er den delen av programmet som tar imot input fra "ekte" spillere (f.eks. du og gruppelederen din) og viser et output fra programmet. Typiske input er klikk-events eller streng-kommandoer; typiske output er å tegne brettet på i et grafikk-vindu eller ved hjelp av tegn og bokstaver i en terminal. Programmet må typisk outputte status på spillet og fortelle spillerne hvem sin tur det er og om noen har vunnet eller spillet er over.
**Penn og papir.** Bruk egne diagrammer flittig: hvis det blir mye å holde styr på, tegn opp klassene og hvordan de kaller hverandre. Utvid og endre på diagrammet etter hvert. Hvis du tror vi vil ha nytte av det til slutt så legg det gjerne ved innleveringen.
Du trenger ikke å lage et grafisk brukergrensesnitt, det holder med tekst-interaksjon. Det viktige er at denne delen av koden din er klart skilt ut fra resten og godt dokumentert.
**Rubberduck debugging.** Et klassisk programmerer-triks når du sitter fast er å forklare koden din. En gruppeleder er alltid et godt valg, men du kan også forklare den til samboeren din, bestemor, naboens hund, en potteplante eller gummiand. For mer info og en virtuell gummiand, sjekk ut [https://rubberduckdebugging.com/](https://rubberduckdebugging.com/).
Hvis du vil sjekke om du har klart å skille koden for brukergrensesnittet klart fra resten (vi kaller det "modulær" kode) så kan du prøve å bytte ut brukergrensesnittet ditt med noen annens: dersom du har et fornuftig API til resten av programmet ditt bør det være relativt enkelt å koble noen andres brukergrensesnitt til resten av koden din, og på den måten endre én del av programmet uten å måtte endre kode som ikke har med input/output å gjøre. Du kan nok ikke bytte ut klassene direkte, men det bør gå an med litt jobb, og hvis dere blir enig om en lur måte å skrive interfacene på som dere har felles, kan dere bytte moduler uten å endre øvrig kode.
## Brukergrensesnitt
Brukergrensesnittet er den delen av programmet som tar imot input fra "ekte" spillere (f.eks. du og gruppelederen din) og viser et output fra programmet. Typiske input er klikk-events eller streng-kommandoer; typiske output er å tegne brettet på i et grafikk-vindu eller ved hjelp av tegn og bokstaver i en terminal. Programmet må typisk kommunisere status på spillet, fortelle spillerne hvem sin tur det er og om noen har vunnet eller spillet er over.
*Det er ikke et krav for oppgaven å bytte kode med andre studenter, men hvis du får det til uten særlig mye arbeid ligger du sannsynligvis godt an.*
**Du trenger ikke å lage et grafisk brukergrensesnitt, det holder med tekst-interaksjon. Det viktige er at denne delen av koden din er klart skilt ut fra resten og godt dokumentert.**
### Forslag til brukergrensesnitt
Du kan f.eks.
......@@ -41,6 +55,10 @@ Du kan f.eks.
* ...kopiere grafikkbiblioteket vi har brukt i INF101, f.eks. fra [Semesteroppgave 1](https://retting.ii.uib.no/inf101.v20.oppgaver/inf101.v20.sem1/-/tree/master/src%2Fmain%2Fjava%2Finf101%2Fv20%2Fgfx).
* ...kopiere grid-GUIen fra [lab 3/4](https://retting.ii.uib.no/inf101.v20.oppgaver/inf101.v20.lab4.losning).
### Grafikk-modul
Hvis du vil sjekke om du har klart å skille koden for brukergrensesnittet klart fra resten (vi kaller det "modulær" kode) så kan du prøve å bytte ut brukergrensesnittet ditt med noen annens: dersom du har et fornuftig API til resten av programmet ditt bør det være relativt enkelt å koble noen andres brukergrensesnitt til resten av koden din, og på den måten endre én del av programmet uten å måtte endre kode som ikke har med input/output å gjøre. Du kan nok ikke bytte ut klassene direkte, men det bør gå an med litt jobb, og hvis dere blir enig om en lur måte å skrive interfacene på som dere har felles, kan dere bytte moduler uten å endre øvrig kode.
*Det er ikke et krav for oppgaven å bytte kode med andre studenter, men hvis du får det til uten særlig mye arbeid ligger du sannsynligvis godt an.*
## Code Review / Feedback på hverandres kode
......
This diff is collapsed.
package inf101.v20.lab4.grid;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
* A Grid contains a set of elements
*
*/
public class Grid<T> implements IGrid<T>, Iterable<T>{
private List<T> cells;
private int height;
private int width;
/**
*
* Construct a grid with the given dimensions.
*
* @param width
* @param height
* @param initElement
* What the cells should initially hold (possibly null)
*/
public Grid(int width, int height, T initElement) {
if(width <= 0 || height <= 0)
throw new IllegalArgumentException();
this.height = height;
this.width = width;
cells = new ArrayList<>(height * width);
for (int i = 0; i < height * width; ++i) {
cells.add(initElement);
}
}
@Override
public int getHeight() {
return height; // TODO: fyll inn
}
@Override
public int getWidth() {
return width; // TODO: fyll inn
}
@Override
public void set(int x, int y, T elem) {
if(x < 0 || x >= width)
throw new IndexOutOfBoundsException();
if(y < 0 || y >= height)
throw new IndexOutOfBoundsException();
// TODO: fyll inn
cells.set(coordinateToIndex(x, y), elem);
}
private int coordinateToIndex(int x, int y) {
return x + y*width;
}
@Override
public T get(int x, int y) {
if(x < 0 || x >= width)
throw new IndexOutOfBoundsException();
if(y < 0 || y >= height)
throw new IndexOutOfBoundsException();
return cells.get(coordinateToIndex(x, y)); // TODO: fyll inn
}
@Override
public IGrid<T> copy() {
Grid<T> newGrid = new Grid<>(getWidth(), getHeight(), null);
for (int x = 0; x < width; x++)
for(int y = 0; y < height; y++)
newGrid.set(x, y, get(x, y));
return newGrid;
}
@Override
public Iterator<T> iterator() {
return cells.iterator();
}
}
package inf101.v20.lab4.grid;
/**
* IGrid is a generic grid
*
* @author Anna Eilertsen - anna.eilertsen@uib.no
*
*/
public interface IGrid<T> {
/**
* @return The height of the grid.
*/
int getHeight();
/**
* @return The width of the grid.
*/
int getWidth();
/**
*
* Set the contents of the cell in the given x,y location.
*
* y must be greater than or equal to 0 and less than getHeight().
* x must be greater than or equal to 0 and less than getWidth().
*
* @param x The column of the cell to change the contents of.
* @param y The row of the cell to change the contents of.
* @param element The contents the cell is to have.
*/
void set(int x, int y, T element);
/**
*
* Get the contents of the cell in the given x,y location.
*
* y must be greater than or equal to 0 and less than getHeight().
* x must be greater than or equal to 0 and less than getWidth().
*
* @param x The column of the cell to get the contents of.
* @param y The row of the cell to get contents of.
*/
T get(int x, int y);
/**
* Make a copy
*
* @return A shallow copy of the grid, with the same elements
*/
IGrid<T> copy();
}
\ No newline at end of file
package inf101.v20.sem2.mnkgames;
public class ConnectFour extends MNKGame{
public ConnectFour() {
super(7, 6, 4);
}
@Override
public void putPieceAt(int x, int y) {
putPieceAt(x);
}
/**
* Special rules for the Connect Four
*
* Players can only drop pieces into column, they cannot decide which
* row they should land in.
*
* Pieces will stop at the first available row
*
* @param x the column to which the piece is added
*/
public void putPieceAt(int x) {
assert x >= 0 && x < getWidth();
int firstAvailableRow = -1;
for(int y=0; y<getHeight(); y++, firstAvailableRow = y-1) {
if(getPieceAt(x, y) != Piece.NONE) {
break;
}
}
//precondition check
if(firstAvailableRow == -1)
throw new IllegalStateException("There were no available spots in column " + x);
//add the current piece
super.putPieceAt(x, firstAvailableRow);
}
}
\ No newline at end of file
package inf101.v20.sem2.mnkgames.GUI;
import java.util.function.Supplier;
import inf101.v20.sem2.mnkgames.ConnectFour;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.TicTacToe;
public class GUIMain {
public static void main(String[] args) {
MNKGameGUI.run(new GameSupplier());
}
}
class GameSupplier implements Supplier<MNKGame>{
@Override
public MNKGame get() {
return null;
}
public MNKGame getConnectFourGame() {
return new ConnectFour();
}
public MNKGame getTicTacToeGame() {
return new TicTacToe();
}
}
package inf101.v20.sem2.mnkgames.GUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import inf101.v20.lab4.grid.Grid;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.MNKGame.Piece;
import inf101.v20.sem2.twoPlayerGame.TwoPlayerGame;
/**
*
* @author Anna Eilertsen
*/
public class MNKGameGUI extends JPanel implements ActionListener{
private static final long serialVersionUID = 8755882090377973497L;
/**
s * Initializes a JFrame in which we place the game
* @param gameSupplier A lambda function that provides new games
*/
public static void run(GameSupplier gameSupplier) {
JFrame f = new JFrame("mnkGame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MNKGameGUI ap = new MNKGameGUI(gameSupplier);
ap.collectPlayerInfo();
ap.initialize();
f.add("Center", ap);
f.pack();
f.setVisible(true);
}
// Fields
private JButton playConnectFourButton;
private JButton playTicTacToeButton;
private JLabel statusMessage;
private Grid<GamePanel> clickablePanels;
private GameSupplier gameSupplier;
private TwoPlayerGame<MNKGame> game;
public MNKGameGUI(GameSupplier gameSupplier) {
this.gameSupplier = gameSupplier;
//initialize to default values
game = new TwoPlayerGame<>(gameSupplier.getTicTacToeGame());
}
/*
* (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
* Called whenever a button is pressed
*/
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == playConnectFourButton) {
reset(gameSupplier.getConnectFourGame());
}
if(e.getSource() == playTicTacToeButton) {
reset(gameSupplier.getTicTacToeGame());
}
}
private void reset(MNKGame newGame) {
this.game = game.newGame(newGame);
updateMessage();
removeAll();
initialize();
this.updateUI();
}
/**
* Should be called after a click to update the UI to reflect the current game state
*/
private void endOfTurn() {
clickablePanels.forEach(item -> item.updateToGame());
updateMessage();
MNKGameGUI.super.updateUI();
if(!game.hasPossibleMoves()) {
stop();
}
}
/**
* Helper method to control the status message
*/
private void updateMessage() {
if (game.hasWinner())
statusMessage.setText("The game is over! The winner is " + game.winner());
else if(game.hasPossibleMoves()) {
statusMessage.setText("Next move from " + game.currentPlayer());
}else{
statusMessage.setText("The game is over! No one won.");
}
}
/**
* Should be called once a game stops
*/
private void stop() {
clickablePanels.forEach(item -> item.removeMouseListeners());
}
//Class that defines what happens (i.e: the color changes) when a panel is clicked
class BoxListener extends MouseAdapter{
public void mousePressed(MouseEvent me){
GamePanel clickedPanel =(GamePanel)me.getSource(); // get the reference to the box that was clicked
clickedPanel.click();
}
}
/**
* Maps from Piece values to colors
*
* @param pieceAt The piece to be drawn
* @return The color that this GUI implementation associates with the provided piece
*/
protected Color pieceToColor(Piece pieceAt) {
switch(pieceAt) {
case BLACK : return Color.getHSBColor(90, 65, 20.3f);
case WHITE : return Color.getHSBColor(308, 26, 34);
default: return Color.WHITE;
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(100*game.height(), 100*game.width());
}
/**
* A class for clickable panels with x,y-coordinates
*
* @author anna
*
*/
private class GamePanel extends JPanel{
private int x, y;
private static final long serialVersionUID = 1L;
public GamePanel(int x, int y) {
this.x = x;
this.y = y;
}
private void removeMouseListeners() {
MouseListener[] mouseListeners = getMouseListeners();
for (int i = 0; i < mouseListeners.length; i++) {
this.removeMouseListener(mouseListeners[i]);
}
}
private void updateToGame() {
if(filled()) {
makeUnClickable();
}
}
private void makeUnClickable() {
removeMouseListeners();
}
private boolean filled() {
return game.hasPieceAt(x, y);
}
public void click() {
game.takeTurnforHumanPlayer(x, y);
endOfTurn();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(3, 3);
}
@Override
public Color getBackground() {
return pieceToColor(game.pieceAt(x, y));
}
}
/**
* Sets up the GUI.
*/
public void initialize() {
setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(game.height(), game.width()));
p.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
this.clickablePanels = new Grid<GamePanel>(game.width(), game.height(), null);
for(int y = 0; y<game.height(); y++) {
for (int x=0; x<game.width(); x++) {
GamePanel pan = new GamePanel(x, y);
pan.setEnabled(true);
pan.setBorder(BorderFactory.createLineBorder(Color.GRAY));
pan.addMouseListener(new BoxListener()); // add a mouse listener to make the panels clickable
p.add(pan);
clickablePanels.set(x, y, pan);
}
}
p.setRequestFocusEnabled(true);
p.requestFocus();
add(p);
JPanel buttons = createButtonPanel();
add(buttons, BorderLayout.SOUTH);
add(statusMessage, BorderLayout.NORTH);
validate();
}
/**
* Helper method that creates the button panel
*/
private JPanel createButtonPanel() {
playTicTacToeButton = new JButton();
playTicTacToeButton.addActionListener(this);
playTicTacToeButton.setText("Tic-Tac-Toe");
playConnectFourButton = new JButton();
playConnectFourButton.addActionListener(this);
playConnectFourButton.setText("Connect Four");
statusMessage = new JLabel();
statusMessage.setText("Welcome to this game! " + game.player1() + " begins.");
JPanel buttons = new JPanel();