commit 43e236fda93cf8b0b2cb20b492482c85a04eb8b3 Author: Jan Philipp Timme Date: Sun Dec 6 19:52:11 2015 +0100 [TASK] Import. diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..0cfaf14 --- /dev/null +++ b/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab31b20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.class + diff --git a/.project b/.project new file mode 100644 index 0000000..3f45730 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + TicTacToe + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..e577825 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Sat Sep 03 13:48:41 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000..e86f2ca --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: tictactoe.jar +Main-Class: org.jpt.tictactoe.Game diff --git a/TicTacToeGui.launch b/TicTacToeGui.launch new file mode 100644 index 0000000..6379f16 --- /dev/null +++ b/TicTacToeGui.launch @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/forms-1.3.0-src.zip b/forms-1.3.0-src.zip new file mode 100644 index 0000000..b7673af Binary files /dev/null and b/forms-1.3.0-src.zip differ diff --git a/forms-1.3.0.jar b/forms-1.3.0.jar new file mode 100644 index 0000000..1291057 Binary files /dev/null and b/forms-1.3.0.jar differ diff --git a/miglayout-src.zip b/miglayout-src.zip new file mode 100644 index 0000000..9c51c32 Binary files /dev/null and b/miglayout-src.zip differ diff --git a/miglayout15-swing.jar b/miglayout15-swing.jar new file mode 100644 index 0000000..1396b24 Binary files /dev/null and b/miglayout15-swing.jar differ diff --git a/src/org/jpt/tictactoe/AbstractKi.java b/src/org/jpt/tictactoe/AbstractKi.java new file mode 100644 index 0000000..8c7d8fd --- /dev/null +++ b/src/org/jpt/tictactoe/AbstractKi.java @@ -0,0 +1,33 @@ +package org.jpt.tictactoe; + +import java.util.ArrayList; + +public abstract class AbstractKi extends AbstractPlayer { + + /** + * @param name + */ + public AbstractKi(String name) { + super(name); + } + + /** + * @param Game + */ + public abstract boolean takeTurn(Game game); + + /** + * @param fieldSet + * @return ArrayList + */ + protected ArrayList getEmptyFieldsFromFieldSet(int[][] fields) { + ArrayList emptyFields = new ArrayList (); + for(int x = 0; x < 3; x++){ + for(int y = 0; y < 3; y++){ + if(fields[x][y] == 0) emptyFields.add(new int[]{x,y}); + } + } + return emptyFields; + } + +} diff --git a/src/org/jpt/tictactoe/AbstractPlayer.java b/src/org/jpt/tictactoe/AbstractPlayer.java new file mode 100644 index 0000000..f9b97ec --- /dev/null +++ b/src/org/jpt/tictactoe/AbstractPlayer.java @@ -0,0 +1,74 @@ +package org.jpt.tictactoe; + +public abstract class AbstractPlayer { + + /** + * contains the next turn of the human player + * @var int[] + */ + protected int[] nextField = new int[2]; + + /** + * @var String + */ + protected String name; + + /** + * @var int + */ + protected int playerNumber; + + + /** + * constructor + * @param playerNumber + * @param name + */ + public AbstractPlayer(String name) { + this.name = name; + } + + /** + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return String + */ + public String getName() { + return this.name; + } + + /** + * @param playerNumber + */ + public void setPlayerNumber(int playerNumber) { + this.playerNumber = playerNumber; + } + + /** + * @return int + */ + public int getPlayerNumber() { + return this.playerNumber; + } + + /** + * This method will be called by stuff. + * It will call a similar method on the game - this is legit. + */ + abstract public boolean takeTurn(Game game); + + /** + * Sets the next field the player can use to make a turn. + * This is in use for HumanPlayers only! + * @param nextField + */ + public void setNextTurn(int[] nextField) { + this.nextField = nextField; + } + +} diff --git a/src/org/jpt/tictactoe/AbstractView.java b/src/org/jpt/tictactoe/AbstractView.java new file mode 100644 index 0000000..36ebb86 --- /dev/null +++ b/src/org/jpt/tictactoe/AbstractView.java @@ -0,0 +1,35 @@ +package org.jpt.tictactoe; + +public interface AbstractView { + + /** + * @param FieldSet fieldSet + * draws the field - however this will happen + */ + public abstract void drawField(FieldSet fieldSet); + + /** + * @param player + * @return int[] containing the coordinates + */ + public abstract int[] askPlayerForField(); + + /** + * @param player + * @return String the Name + */ + public abstract String askPlayerForName(); + + /** + * have the view display the given message. + * @param msg + */ + public abstract void message(String msg); + + /** + * I need this for gui stuff. Sorry :( + * @param game + */ + public abstract void setGame(Game game); + +} diff --git a/src/org/jpt/tictactoe/DumbKi.java b/src/org/jpt/tictactoe/DumbKi.java new file mode 100644 index 0000000..445bfd1 --- /dev/null +++ b/src/org/jpt/tictactoe/DumbKi.java @@ -0,0 +1,24 @@ +package org.jpt.tictactoe; + +public class DumbKi extends AbstractKi { + + /** + * constructor + * @param name + */ + public DumbKi(String name) { + super(name); + } + + /** + * @param Game game + */ + public boolean takeTurn(Game game) { + for(int i = 0; i<3; i++) { + for(int j = 0; j<3; j++) { + if(game.setFieldOnFieldSet(i, j, this)) return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/org/jpt/tictactoe/FieldSet.java b/src/org/jpt/tictactoe/FieldSet.java new file mode 100644 index 0000000..87f24cd --- /dev/null +++ b/src/org/jpt/tictactoe/FieldSet.java @@ -0,0 +1,65 @@ +package org.jpt.tictactoe; + +public class FieldSet { + + /** + * 2D-Array for the field + */ + protected int[][] fields = new int[3][3]; + + + /** + * Field constructor. + * Initializes field. + */ + public FieldSet(){ + for(int i = 0; i<3; i++) { + for(int j = 0; j<3; j++) { + fields[i][j] = 0; + } + } + } + + /** + * method to set a certain field to n. + * @param x + * @param y + * @param n + * @throws UsedFieldException + */ + public void setField(int x, int y, int n) throws UsedFieldException { + if(this.fields[x][y] != 0) throw new UsedFieldException(); + else this.fields[x][y] = n; + } + + /** + * method to retrieve the value of a certain field. + * @param x + * @param y + * @return int + */ + public int getField(int x, int y) { + return this.fields[x][y]; + } + + /** + * returns the whole fieldset + * @return int[][] + */ + public int[][] getFieldSet() { + return this.fields; + } + + /** + * Checks the fieldset. + * @return boolean + */ + public boolean isFull() { + for(int i = 0; i<3; i++) { + for(int j = 0; j<3; j++) { + if(fields[i][j] == 0) return false; + } + } + return true; + } +} diff --git a/src/org/jpt/tictactoe/Game.java b/src/org/jpt/tictactoe/Game.java new file mode 100644 index 0000000..3427733 --- /dev/null +++ b/src/org/jpt/tictactoe/Game.java @@ -0,0 +1,264 @@ +package org.jpt.tictactoe; + +public class Game { + + /** + * @var FieldSet + */ + protected FieldSet fieldSet; + + /** + * Index that points to the active player in the players-array + * @var int + */ + protected int activePlayer; + + /** + * @var boolean + */ + protected boolean gameOver; + + /** + * @var Array + */ + protected AbstractPlayer[] players = new AbstractPlayer[2]; + + /** + * @var int + */ + protected int playerCount = 0; + + /** + * @var AbstractView + */ + protected AbstractView view; + + /** + * @author JPT + * Contains representative values for the different kinds of players this game supports. + */ + public enum PlayerType { + HumanPlayer, DumbKI, MediumKI, RandomKI + } + + + /** + * constructor + */ + public Game() { + this.resetGame(); + } + + /** + * this method will process almost everything as long as there is no human interaction needed. + * also, it does NOT process human player turns. they do it on their own. + */ + public void processGame() { + this.gameOver = this.checkGameOver(); + if(this.isGameOver() == true) return; + //get active player + AbstractPlayer activePlayer = this.getActivePlayer(); + //as long as active player is NOT human, do it automatically + while(activePlayer instanceof HumanPlayer == false) { + activePlayer.takeTurn(this); + this.gameOver = this.checkGameOver(); + this.drawField(); + activePlayer = this.getActivePlayer(); + + //it's not thaat important... + if(this.isGameOver()) break; + } + } + + /** + * Adds a player to the game. hehehehe... the game... + * you just lost it. :P + * @param player + */ + public void addPlayer(AbstractPlayer player) { + player.setPlayerNumber(this.playerCount + 1); + this.players[this.playerCount] = player; + this.playerCount++; + } + + /** + * checks the field for a gameover condition. + * @return boolean + */ + protected boolean checkGameOver() { + int[][] fieldSetCopy = this.fieldSet.getFieldSet(); + int winnerId = 0; + + //check rows + for(int x = 0; x < 3; x++) { + if(fieldSetCopy[x][0] == fieldSetCopy[x][1] && fieldSetCopy[x][1] == fieldSetCopy[x][2]) { + if(winnerId == 0) winnerId = fieldSetCopy[x][0]; + } + } + + //check cols + for(int y = 0; y < 3; y++) { + if(fieldSetCopy[0][y] == fieldSetCopy[1][y] && fieldSetCopy[1][y] == fieldSetCopy[2][y]) { + if(winnerId == 0) winnerId = fieldSetCopy[0][y]; + } + } + + //check diags + if(fieldSetCopy[0][0] == fieldSetCopy[1][1] && fieldSetCopy[1][1] == fieldSetCopy[2][2]) { + if(winnerId == 0) winnerId = fieldSetCopy[1][1]; + } + + //other diags + if(fieldSetCopy[2][0] == fieldSetCopy[1][1] && fieldSetCopy[1][1] == fieldSetCopy[0][2]) { + if(winnerId == 0) winnerId = fieldSetCopy[1][1]; + } + + //if winner, announce winner + if(winnerId != 0) { + this.view.message(this.getPlayerByPlayerNumber(winnerId).getName() + " won the game!"); + return true; + } + + //else, if it's just full... + if(this.fieldSet.isFull() == true){ + this.view.message("Apparently, this is a draw. Congratulations :D"); + return true; + } + + return false; + } + + /** + * Checks whether the player is allowed to take its turn. + * Also manages the activePlayer attribute. + * + * @param x + * @param y + * @param player + * @return boolean + */ + public boolean setFieldOnFieldSet(int x, int y, AbstractPlayer player) { + if(player != this.getActivePlayer()) { + this.view.message(player.getName() + " took an illegal turn!"); + return false; + } + try { + //check whether coords are in range... + if(x < 0 || x > 2 || y < 0 || y > 2) { + return false; + } + this.fieldSet.setField(x, y, player.getPlayerNumber()); + this.view.message(player.getName() + " took his turn and marked on: ["+x+","+y+"]"); + this.changeActivePlayer(); + return true; + } catch (UsedFieldException e) { + return false; + } + } + + /** + * changes the active player. + */ + protected void changeActivePlayer() { + int activePlayerPointer = this.activePlayer; + activePlayerPointer++; + if(activePlayerPointer == this.players.length) activePlayerPointer = 0; + this.activePlayer = activePlayerPointer; + } + + /** + * @return AbstractPlayer active player + */ + public AbstractPlayer getActivePlayer() { + return this.players[this.activePlayer]; + } + + /** + * @return AbstractPlayer player + */ + protected AbstractPlayer getPlayerByPlayerNumber(int playerNumber) { + for(int i = 0; i < this.players.length; i++) { + if(this.players[i].getPlayerNumber() == playerNumber) return this.players[i]; + } + return null; + } + + /** + * @return FieldSet + */ + public FieldSet getFieldSet() { + return this.fieldSet; + } + + /** + * Sets the view. + * @param view + */ + public void setView(AbstractView view) { + view.message("Welcome to TicTacToe!"); + this.view = view; + } + + /** + * Gets the view. + * @return AbstractView view + */ + public AbstractView getView() { + return this.view; + } + + /** + * @return boolean + */ + public boolean isGameOver() { + return this.gameOver; + } + + /** + * Have the view draw the field. + */ + public void drawField() { + this.view.drawField(this.fieldSet); + } + + /** + * Creates a player based on a given PlayerType + * @param playerType + * @param name + * @return AbstractPlayer + */ + public AbstractPlayer createPlayerByEnum(PlayerType playerType, String name) { + switch(playerType) { + case HumanPlayer: + return new HumanPlayer(name); + case DumbKI: + return new DumbKi(name); + case MediumKI: + return new MediumKi(name); + case RandomKI: + return new RandomKi(name); + default: + System.out.println("Not implemented yet: " + playerType); + break; + } + return null; + } + + /** + * resets all game relevant variables except for the players. + */ + public void resetGame() { + this.fieldSet = new FieldSet(); + this.gameOver = false; + this.playerCount = 0; + this.activePlayer = 0; + } + + /** + * @return AbstractPlayer[] + */ + public AbstractPlayer[] getPlayers() { + return this.players; + } + +} diff --git a/src/org/jpt/tictactoe/HumanPlayer.java b/src/org/jpt/tictactoe/HumanPlayer.java new file mode 100644 index 0000000..4f1e2e0 --- /dev/null +++ b/src/org/jpt/tictactoe/HumanPlayer.java @@ -0,0 +1,42 @@ +package org.jpt.tictactoe; + +public class HumanPlayer extends AbstractPlayer { + + /** + * constructor + * @param name + */ + public HumanPlayer(String name) { + super(name); + } + + /** + * Sets the next turn the humanPlayer will do. + * @param nextField + */ + public void setNextTurn(int[] nextField) { + this.nextField = nextField; + } + + /** + * We take our turn here. + * @return boolean + */ + public boolean takeTurn(Game game) { + if(game.isGameOver()) return false; + boolean success = false; + int[] coordinates = this.nextField; + if(coordinates == null) { + game.getView().message("Ups."); + } + int x = coordinates[0]; + int y = coordinates[1]; + + success = game.setFieldOnFieldSet(x, y, this); + if(!success) { + game.getView().message("The field on ["+x+","+y+"] is already taken or invalid."); + } + return success; + } + +} diff --git a/src/org/jpt/tictactoe/MediumKi.java b/src/org/jpt/tictactoe/MediumKi.java new file mode 100644 index 0000000..f0200ee --- /dev/null +++ b/src/org/jpt/tictactoe/MediumKi.java @@ -0,0 +1,121 @@ +package org.jpt.tictactoe; + +import java.util.ArrayList; +import java.util.Random; + +public class MediumKi extends AbstractKi { + + /** + * constructor + * @param name + */ + public MediumKi(String name) { + super(name); + } + + /** + * @param Game game + * @return boolean + */ + public boolean takeTurn(Game game) { + Random randomGenerator = new Random(System.nanoTime()); + int[][] fields = game.getFieldSet().getFieldSet(); + AbstractPlayer[] players = game.getPlayers(); + int enemyNumber = 0; + for(int i = 0; i < players.length; i++) { + if(players[i].equals(this) == false) enemyNumber = players[i].getPlayerNumber(); + } + + ArrayList instantWinFields = this.getWinFieldsForNumber(this.getPlayerNumber(), fields, false); + if(instantWinFields.size() > 0) { + int randomInt = (instantWinFields.size() > 1) ? randomGenerator.nextInt(instantWinFields.size()) : 0; + int[] coord = instantWinFields.get(randomInt); + int x = coord[0]; + int y = coord[1]; + if(game.setFieldOnFieldSet(x, y, this)) return true; + } + + ArrayList enemyFields = this.getWinFieldsForNumber(enemyNumber, fields, false); + if(enemyFields.size() > 0) { + int randomInt = (enemyFields.size() > 1) ? randomGenerator.nextInt(enemyFields.size() - 1) : 0; + int[] coord = enemyFields.get(randomInt); + int x = coord[0]; + int y = coord[1]; + if(game.setFieldOnFieldSet(x, y, this)) return true; + } + + ArrayList possibleWinFields = this.getWinFieldsForNumber(this.getPlayerNumber(), fields, true); + if(possibleWinFields.size() > 0) { + int randomInt = (possibleWinFields.size() > 1) ? randomGenerator.nextInt(possibleWinFields.size()) : 0; + int[] coord = possibleWinFields.get(randomInt); + int x = coord[0]; + int y = coord[1]; + if(game.setFieldOnFieldSet(x, y, this)) return true; + } + + ArrayList emptyFields = this.getEmptyFieldsFromFieldSet(fields); + if(emptyFields.size() > 0) { + int randomInt = (emptyFields.size() > 1) ? randomGenerator.nextInt(emptyFields.size() - 1) : 0; + int[] coord = emptyFields.get(randomInt); + int x = coord[0]; + int y = coord[1]; + if(game.setFieldOnFieldSet(x, y, this)) return true; + } + + game.getView().message("I don't know what to do! O__o"); + return false; + } + + /** + * Finds the position of the empty field in case the the other two fields are equal + * @param int[] numbers + * @return int + */ + protected int getFreeFieldFor(int[] numbers, int playerNumber, boolean softResults) { + if(numbers[0] == numbers[1] || numbers[1] == numbers[2] || numbers[2] == numbers[0]) { + int[] counter = new int[]{0,0,0}; + int fieldPos = 0; + for(int i = 0; i < 3; i++) { + if(numbers[i] == 0) fieldPos = i; + counter[numbers[i]]++; + } + if(counter[0] == 1 && counter[playerNumber] == 2) return fieldPos; + if(softResults == true && counter[0] == 2 && counter[playerNumber] == 1) return fieldPos; + } + return -1; + } + + /** + * returns an ArrayList of possible winner-coords based on the game logic for the given playerNumber. + * [we search for a win condition and then add empty fields] + * @return ArrayList + */ + protected ArrayList getWinFieldsForNumber(int playerNumber, int[][] fields, boolean softResult) { + ArrayList relevantFields = new ArrayList (); + int fieldPos; + + //check rows + for(int x = 0; x < 3; x++) { + fieldPos = this.getFreeFieldFor(new int[]{fields[x][0],fields[x][1],fields[x][2]}, playerNumber, softResult); + if(fieldPos > -1) relevantFields.add(new int[]{x,fieldPos}); + } + + //check cols + for(int y = 0; y < 3; y++) { + fieldPos = this.getFreeFieldFor(new int[]{fields[0][y],fields[1][y],fields[2][y]}, playerNumber, softResult); + if(fieldPos > -1) relevantFields.add(new int[]{fieldPos, y}); + } + + //check diags + fieldPos = this.getFreeFieldFor(new int[]{fields[0][0],fields[1][1],fields[2][2]}, playerNumber, softResult); + if(fieldPos > -1) relevantFields.add(new int[]{fieldPos, fieldPos}); + + //check diags + fieldPos = this.getFreeFieldFor(new int[]{fields[2][0],fields[1][1],fields[0][2]}, playerNumber, softResult); + if(fieldPos > -1) relevantFields.add(new int[]{2 - fieldPos, fieldPos}); + + return relevantFields; + } + + +} \ No newline at end of file diff --git a/src/org/jpt/tictactoe/RandomKi.java b/src/org/jpt/tictactoe/RandomKi.java new file mode 100644 index 0000000..2e5edf4 --- /dev/null +++ b/src/org/jpt/tictactoe/RandomKi.java @@ -0,0 +1,34 @@ +package org.jpt.tictactoe; + +import java.util.ArrayList; +import java.util.Random; + +public class RandomKi extends AbstractKi { + + /** + * constructor + * @param name + */ + public RandomKi(String name) { + super(name); + } + + /** + * @param Game game + * @return boolean + */ + public boolean takeTurn(Game game) { + Random randomGenerator = new Random(System.nanoTime()); + int[][] fields = game.getFieldSet().getFieldSet(); + ArrayList emptyFields = this.getEmptyFieldsFromFieldSet(fields); + int i = emptyFields.size(); + i = (i > 1) ? i - 1 : i; + int randomInt = randomGenerator.nextInt(i); + int[] coord = emptyFields.get(randomInt); + int x = coord[0]; + int y = coord[1]; + + if(game.setFieldOnFieldSet(x, y, this)) return true; + return false; + } +} \ No newline at end of file diff --git a/src/org/jpt/tictactoe/UsedFieldException.java b/src/org/jpt/tictactoe/UsedFieldException.java new file mode 100644 index 0000000..ca30f17 --- /dev/null +++ b/src/org/jpt/tictactoe/UsedFieldException.java @@ -0,0 +1,10 @@ +package org.jpt.tictactoe; + +public class UsedFieldException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/src/org/jpt/tictactoe/gui/GuiView.java b/src/org/jpt/tictactoe/gui/GuiView.java new file mode 100644 index 0000000..bf2da1d --- /dev/null +++ b/src/org/jpt/tictactoe/gui/GuiView.java @@ -0,0 +1,401 @@ +package org.jpt.tictactoe.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; +import javax.swing.text.BadLocationException; + +import net.miginfocom.swing.MigLayout; + +import org.jpt.tictactoe.AbstractView; +import org.jpt.tictactoe.FieldSet; +import org.jpt.tictactoe.Game; + +import com.jgoodies.forms.factories.FormFactory; +import com.jgoodies.forms.layout.ColumnSpec; +import com.jgoodies.forms.layout.FormLayout; +import com.jgoodies.forms.layout.RowSpec; + +public class GuiView extends JFrame implements AbstractView, ActionListener, MouseListener { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * @var JLabel + */ + public JLabel player1NameLabel; + + /** + * @var JLabel + */ + public JLabel player2NameLabel; + + /** + * an array of buttons... + */ + protected JButton[][] buttons = new JButton[3][3]; + + /** + * @var JTextArea + */ + protected JTextArea textArea; + + /** + * @var NewGameDialog + */ + protected NewGameDialog newGameDialog; + + /** + * Contains the game. I need this to be consistent here. + * It's important for the Gui stuff. + * @var Game + */ + protected Game game; + + /** + * @var JScrollPane + */ + protected JScrollPane scrollPane; + + /** + * @var JButton + */ + protected JButton newGameButton; + + /** + * @var JButton + */ + protected JButton repeatGameButton; + + /** + * @param game + */ + public void setGame(Game game) { + this.game = game; + } + + /** + * Create the frame. + * And the stuff within. + * And even more weird configurations. + */ + public GuiView() { + setTitle("TicTacToe"); + setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + getContentPane().setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + getContentPane().setLayout(new BorderLayout(0, 0)); + + JPanel MidWestPanel = new JPanel(); + MidWestPanel.setPreferredSize(new Dimension(135, 10)); + MidWestPanel.setMinimumSize(new Dimension(125, 10)); + getContentPane().add(MidWestPanel, BorderLayout.WEST); + MidWestPanel.setLayout(new FormLayout(new ColumnSpec[] { + FormFactory.LABEL_COMPONENT_GAP_COLSPEC, + ColumnSpec.decode("125px"),}, + new RowSpec[] { + FormFactory.LINE_GAP_ROWSPEC, + RowSpec.decode("23px"), + FormFactory.LINE_GAP_ROWSPEC, + RowSpec.decode("23px"),})); + + JLabel player1Label = new JLabel("Spieler 1"); + player1Label.setFont(new Font("SansSerif", Font.BOLD, 12)); + MidWestPanel.add(player1Label, "2, 2, center, center"); + + JLabel player1NameLabel = new JLabel(""); + this.player1NameLabel = player1NameLabel; + MidWestPanel.add(player1NameLabel, "2, 4, center, center"); + + JPanel MidEastPanel = new JPanel(); + MidEastPanel.setPreferredSize(new Dimension(135, 10)); + MidEastPanel.setMinimumSize(new Dimension(100, 10)); + getContentPane().add(MidEastPanel, BorderLayout.EAST); + MidEastPanel.setLayout(new FormLayout(new ColumnSpec[] { + FormFactory.LABEL_COMPONENT_GAP_COLSPEC, + ColumnSpec.decode("125px"),}, + new RowSpec[] { + FormFactory.LINE_GAP_ROWSPEC, + RowSpec.decode("23px"), + FormFactory.LINE_GAP_ROWSPEC, + RowSpec.decode("23px"),}));; + + JLabel player2Label = new JLabel("Spieler 2"); + player2Label.setFont(new Font("SansSerif", Font.BOLD, 12)); + MidEastPanel.add(player2Label, "2, 2, center, center"); + + JLabel player2NameLabel = new JLabel(""); + this.player2NameLabel = player2NameLabel; + MidEastPanel.add(player2NameLabel, "2, 4, center, center"); + + JPanel TitlePanel = new JPanel(); + getContentPane().add(TitlePanel, BorderLayout.NORTH); + + JLabel TitleLabel = new JLabel("TicTacToe - Die Maschine gewinnt immer!"); + TitleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + TitlePanel.add(TitleLabel); + TitleLabel.setFont(new Font("Tahoma", Font.BOLD, 14)); + TitleLabel.setHorizontalTextPosition(SwingConstants.CENTER); + + JPanel TextPanel = new JPanel(); + TextPanel.setBounds(new Rectangle(50, 50, 0, 150)); + getContentPane().add(TextPanel, BorderLayout.SOUTH); + + JTextArea textArea = new JTextArea(7,46); + textArea.setLineWrap(true); + textArea.setEditable(false); + + JScrollPane scrollPane = new JScrollPane(textArea); + TextPanel.add(scrollPane); + + JPanel CenterPanel = new JPanel(); + getContentPane().add(CenterPanel, BorderLayout.CENTER); + CenterPanel.setLayout(new BorderLayout(0, 0)); + + JPanel GameLayoutContainer = new JPanel(); + CenterPanel.add(GameLayoutContainer); + GameLayoutContainer.setLayout(new BoxLayout(GameLayoutContainer, BoxLayout.X_AXIS)); + + JPanel GameAlignPanel = new JPanel(); + GameLayoutContainer.add(GameAlignPanel); + GameAlignPanel.setLayout(null); + + JPanel GameFieldPanel = new JPanel(); + GameFieldPanel.setBounds(50, 67, 172, 172); + GameAlignPanel.add(GameFieldPanel); + + JButton button1 = new JButton("1"); + button1.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.setLayout(new MigLayout("", "[50px][50px][]", "[50px][][]")); + + JButton button2 = new JButton("2"); + button2.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button2, "cell 1 0,grow"); + GameFieldPanel.add(button1, "cell 0 0,alignx left,aligny top"); + + JButton button3 = new JButton("3"); + button3.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button3, "cell 2 0"); + + JButton button4 = new JButton("4"); + button4.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button4, "cell 0 1"); + + JButton button5 = new JButton("5"); + button5.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button5, "cell 1 1"); + + JButton button6 = new JButton("6"); + button6.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button6, "cell 2 1"); + + JButton button7 = new JButton("7"); + button7.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button7, "cell 0 2"); + + JButton button8 = new JButton("8"); + button8.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button8, "cell 1 2"); + + JButton button9 = new JButton("9"); + button9.setMinimumSize(new Dimension(50, 50)); + GameFieldPanel.add(button9, "cell 2 2"); + + this.buttons[0][0] = button1; + this.buttons[0][1] = button2; + this.buttons[0][2] = button3; + this.buttons[1][0] = button4; + this.buttons[1][1] = button5; + this.buttons[1][2] = button6; + this.buttons[2][0] = button7; + this.buttons[2][1] = button8; + this.buttons[2][2] = button9; + + JPanel panel = new JPanel(); + panel.setBounds(0, 269, 272, 35); + GameAlignPanel.add(panel); + panel.setLayout(new FormLayout(new ColumnSpec[] { + ColumnSpec.decode("127px"), + FormFactory.RELATED_GAP_COLSPEC, + FormFactory.DEFAULT_COLSPEC, + FormFactory.RELATED_GAP_COLSPEC, + FormFactory.DEFAULT_COLSPEC,}, + new RowSpec[] { + RowSpec.decode("28px"),})); + + JButton btnNeuesSpiel = new JButton("Neues Spiel"); + btnNeuesSpiel.setPreferredSize(new Dimension(127, 28)); + panel.add(btnNeuesSpiel, "1, 1, left, top"); + btnNeuesSpiel.setFont(new Font("Tahoma", Font.PLAIN, 10)); + btnNeuesSpiel.addMouseListener(this); + this.newGameButton = btnNeuesSpiel; + + JButton btnSpielWiederholen = new JButton("Spiel wiederholen"); + btnSpielWiederholen.setPreferredSize(new Dimension(127, 28)); + panel.add(btnSpielWiederholen, "5, 1, left, top"); + btnSpielWiederholen.addMouseListener(this); + btnSpielWiederholen.setFont(new Font("Tahoma", Font.PLAIN, 10)); + this.repeatGameButton = btnSpielWiederholen; + setName("TicTacToeFrame"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 550, 500); + + this.textArea = textArea; + this.scrollPane = scrollPane; + + for(int x = 0; x < 3; x++) { + for(int y = 0; y < 3; y++) { + this.buttons[x][y].setText(""); + this.buttons[x][y].addMouseListener(this); + this.buttons[x][y].setEnabled(true); + } + } + + } + + /** + * handles turns based on incoming events. + * @param coords + */ + protected void handleTurn(int[] coords) { + //listen for event, then execute this + if(this.game.isGameOver() == false) { + this.game.getActivePlayer().setNextTurn(coords); + this.game.getActivePlayer().takeTurn(this.game); + this.game.drawField(); + this.game.processGame(); + } + } + + /** + * Uses the given fieldSet to "draw" the current state of the field. + * @param FieldSet fieldSet + */ + public void drawField(FieldSet fieldSet) { + String text = ""; + int[][] field = fieldSet.getFieldSet(); + for(int x = 0; x < 3; x++) { + for(int y = 0; y < 3; y++) { + text = Integer.toString(field[x][y]); + if(text.equals("0")) text = ""; + this.buttons[x][y].setText(text); + } + } + } + + /** + * @return int[] + */ + public int[] askPlayerForField() { + return null; + } + + /** + * @return String name + */ + public String askPlayerForName() { + return "JPT"; + } + + /** + * append the text to the textarea and scroll down ;) + */ + public void message(String msg) { + try { + this.textArea.getDocument().insertString(this.textArea.getDocument().getLength(), msg + "\r\n", null); + } catch (BadLocationException e) { + e.printStackTrace(); + } + //move the cursor down. + this.textArea.setCaretPosition(this.textArea.getText().length()); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + // TODO Auto-generated method stub + + } + + /** + * handle the mouseClick and the turn accordingly :) + */ + public void mouseClicked(MouseEvent arg0) { + Component button = arg0.getComponent(); + //if it was one of the 9 buttons, handle it... + for(int x = 0; x < 3; x++) { + for(int y = 0; y < 3; y++) { + if(this.buttons[x][y].equals(button)) { + this.handleTurn(new int[]{x,y}); + return; + } + } + } + + if(button.equals(this.newGameButton)) { + this.onNewGame(); + } + + if(button.equals(this.repeatGameButton)) { + this.game.resetGame(); + this.game.getView().drawField(this.game.getFieldSet()); + this.game.processGame(); + } + } + + /** + * @param newGameDialog + */ + public void setNewGameDialog(NewGameDialog dialog) { + this.newGameDialog = dialog; + } + + /** + * swap the windows - it should be that easy ;) + */ + private void onNewGame() { + this.setVisible(false); + this.newGameDialog.setVisible(true); + } + + @Override + public void mouseEntered(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseExited(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mousePressed(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseReleased(MouseEvent arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/org/jpt/tictactoe/gui/Main.java b/src/org/jpt/tictactoe/gui/Main.java new file mode 100644 index 0000000..7cd9d99 --- /dev/null +++ b/src/org/jpt/tictactoe/gui/Main.java @@ -0,0 +1,18 @@ +package org.jpt.tictactoe.gui; + +import javax.swing.JDialog; + +public class Main { + + /** + * Code entry point. + * @param args + */ + public static void main(String[] args) { + //show new game window... + NewGameDialog dialog = new NewGameDialog(); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + +} diff --git a/src/org/jpt/tictactoe/gui/NewGameDialog.java b/src/org/jpt/tictactoe/gui/NewGameDialog.java new file mode 100644 index 0000000..29d4466 --- /dev/null +++ b/src/org/jpt/tictactoe/gui/NewGameDialog.java @@ -0,0 +1,216 @@ +package org.jpt.tictactoe.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.EmptyBorder; + +import org.jpt.tictactoe.AbstractPlayer; +import org.jpt.tictactoe.Game; +import org.jpt.tictactoe.Game.PlayerType; + +import com.jgoodies.forms.factories.FormFactory; +import com.jgoodies.forms.layout.ColumnSpec; +import com.jgoodies.forms.layout.FormLayout; +import com.jgoodies.forms.layout.RowSpec; + +public class NewGameDialog extends JDialog implements MouseListener { + + private static final long serialVersionUID = 1L; + + private final JPanel contentPanel = new JPanel(); + private JTextField player1Name; + private JTextField player2Name; + + protected JTextField player1NameField; + protected JTextField player2NameField; + + protected JComboBox player1TypeField; + protected JComboBox player2TypeField; + + protected JButton okButton; + protected JButton cancelButton; + + /** + * Create the dialog. + */ + public NewGameDialog() { + setTitle("Neues Spiel"); + setBounds(100, 100, 450, 185); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + { + JPanel panel = new JPanel(); + contentPanel.add(panel, BorderLayout.NORTH); + { + JLabel lblEinNeuesTictactoe = new JLabel("Ein neues TicTacToe beginnen!"); + lblEinNeuesTictactoe.setFont(new Font("Tahoma", Font.PLAIN, 14)); + panel.add(lblEinNeuesTictactoe); + } + } + { + JPanel panel = new JPanel(); + contentPanel.add(panel, BorderLayout.CENTER); + FormLayout fl_panel = new FormLayout(new ColumnSpec[] { + FormFactory.RELATED_GAP_COLSPEC, + FormFactory.DEFAULT_COLSPEC, + FormFactory.RELATED_GAP_COLSPEC, + ColumnSpec.decode("default:grow"), + FormFactory.RELATED_GAP_COLSPEC, + FormFactory.DEFAULT_COLSPEC, + FormFactory.RELATED_GAP_COLSPEC, + ColumnSpec.decode("default:grow"), + FormFactory.RELATED_GAP_COLSPEC, + ColumnSpec.decode("default:grow"),}, + new RowSpec[] { + FormFactory.RELATED_GAP_ROWSPEC, + FormFactory.DEFAULT_ROWSPEC, + FormFactory.RELATED_GAP_ROWSPEC, + FormFactory.DEFAULT_ROWSPEC, + FormFactory.RELATED_GAP_ROWSPEC, + FormFactory.DEFAULT_ROWSPEC, + FormFactory.RELATED_GAP_ROWSPEC, + FormFactory.DEFAULT_ROWSPEC,}); + panel.setLayout(fl_panel); + { + JLabel lblDeinName = new JLabel("Spieler 1"); + panel.add(lblDeinName, "4, 2, right, default"); + } + { + JLabel lblSpieler = new JLabel("Spieler 2"); + panel.add(lblSpieler, "8, 2"); + } + { + JLabel lblName = new JLabel("Name"); + panel.add(lblName, "2, 4"); + } + { + player1Name = new JTextField(); + panel.add(player1Name, "4, 4, fill, fill"); + player1Name.setColumns(10); + this.player1NameField = player1Name; + } + { + player2Name = new JTextField(); + panel.add(player2Name, "8, 4, fill, default"); + player2Name.setColumns(10); + this.player2NameField = player2Name; + } + { + JLabel lblTyp = new JLabel("Spielertyp"); + panel.add(lblTyp, "2, 6, right, default"); + } + { + JComboBox player1Type = new JComboBox(); + player1Type.setModel(new DefaultComboBoxModel(PlayerType.values())); + panel.add(player1Type, "4, 6, fill, default"); + this.player1TypeField = player1Type; + } + { + JComboBox player2Type = new JComboBox(); + player2Type.setModel(new DefaultComboBoxModel(PlayerType.values())); + panel.add(player2Type, "8, 6, fill, default"); + this.player2TypeField = player2Type; + } + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("Los geht's!"); + this.okButton = okButton; + okButton.addMouseListener(this); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + } + { + JButton cancelButton = new JButton("Ach, doch keine Lust."); + this.cancelButton = cancelButton; + cancelButton.addMouseListener(this); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); + } + } + } + + private void createNewGame() { + Game game = new Game(); + + String player1Name = this.player1NameField.getText(); + String player2Name = this.player2NameField.getText(); + + PlayerType player1Type = (PlayerType) this.player1TypeField.getSelectedItem(); + PlayerType player2Type = (PlayerType) this.player2TypeField.getSelectedItem(); + + AbstractPlayer player1 = game.createPlayerByEnum(player1Type, player1Name); + game.addPlayer(player1); + AbstractPlayer player2 = game.createPlayerByEnum(player2Type, player2Name); + game.addPlayer(player2); + + //hide the other dialog. + this.setVisible(false); + + GuiView guiView = new GuiView(); + guiView.player1NameLabel.setText(player1Name); + guiView.player2NameLabel.setText(player2Name); + guiView.setNewGameDialog(this); + guiView.setVisible(true); + guiView.setGame(game); + game.setView(guiView); + game.processGame(); + } + + /** + * closes the window - exits the application. + */ + private void closeWindow() { + this.dispose(); + System.exit(0); + } + + public void mouseClicked(MouseEvent arg0) { + Component button = arg0.getComponent(); + if(button.equals(this.okButton)) this.createNewGame(); + if(button.equals(this.cancelButton)) this.closeWindow(); + } + + @Override + public void mouseEntered(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseExited(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mousePressed(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseReleased(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/org/jpt/tictactoe/text/Main.java b/src/org/jpt/tictactoe/text/Main.java new file mode 100644 index 0000000..dced555 --- /dev/null +++ b/src/org/jpt/tictactoe/text/Main.java @@ -0,0 +1,28 @@ +package org.jpt.tictactoe.text; + +import org.jpt.tictactoe.*; + +public class Main { + + /** + * Code entry point. + * @param args + */ + public static void main(String[] args) { + Game game = new Game(); + AbstractView textView = new TextView(); + textView.setGame(game); + game.setView(textView); + + game.addPlayer(new HumanPlayer(game.getView().askPlayerForName())); + game.addPlayer(new DumbKi("Steve")); + + //listen for event + while(game.isGameOver() == false) { + game.getActivePlayer().setNextTurn(game.getView().askPlayerForField()); + game.getActivePlayer().takeTurn(game); + game.drawField(); + game.processGame(); + } + } +} diff --git a/src/org/jpt/tictactoe/text/TextView.java b/src/org/jpt/tictactoe/text/TextView.java new file mode 100644 index 0000000..3833902 --- /dev/null +++ b/src/org/jpt/tictactoe/text/TextView.java @@ -0,0 +1,94 @@ +package org.jpt.tictactoe.text; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.jpt.tictactoe.*; + +public class TextView implements AbstractView{ + + /** + * Contains the game. I need this to be consistent here. + * It's important for the Gui stuff. + * @var Game + */ + protected Game game; + + + /** + * @param game + */ + public void setGame(Game game) { + this.game = game; + } + + /** + * uses system.out to print the field. + */ + public void drawField(FieldSet fieldSet) { + int[][] fields = fieldSet.getFieldSet(); + String output = ""; + String eol = "\r\n"; + String horizontalLine = "-------------" + eol; + + for(int i = 0; i<3; i++) { + output += horizontalLine; + for(int j = 0; j<3; j++) { + output += "| " + Integer.toString(fields[i][j]) + " "; + } + output += "|" + eol; + } + output += horizontalLine; + + System.out.println(output); + } + + /** + * @return int[] the coordinates. + */ + public int[] askPlayerForField() { + System.out.print("x,y >"); + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + try { + String result = in.readLine(); + String[] splitted = result.split(","); + int x = new Integer(splitted[0]); + int y = new Integer(splitted[1]); + int coords[] = new int[2]; + coords[0] = x; + coords[1] = y; + this.message("You entered: " + result.toString()); + return coords; + } catch (Exception e) { + this.message("Invalid turn - Please use the following format: [x,y] e.g. 2,1"); + return this.askPlayerForField(); + } + } + + /** + * @return String + */ + public String askPlayerForName() { + System.out.print("Please enter your name: "); + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + try { + String result = in.readLine(); + return result; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Outputs the message. + * @param String msg + */ + public void message(String msg) { + System.out.println(msg); + } + +}