Merge
This commit is contained in:
commit
e619971762
11
.idea/artifacts/Four_In_A_Row.xml
Normal file
11
.idea/artifacts/Four_In_A_Row.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ArtifactManager">
|
||||||
|
<artifact type="jar" name="Four-In-A-Row">
|
||||||
|
<output-path>$PROJECT_DIR$/out/artifacts/Four_In_A_Row</output-path>
|
||||||
|
<root id="archive" name="Four-In-A-Row.jar">
|
||||||
|
<element id="directory" name="META-INF">
|
||||||
|
<element id="file-copy" path="$PROJECT_DIR$/META-INF/MANIFEST.MF" />
|
||||||
|
</element>
|
||||||
|
<element id="module-output" name="Four-In-A-Row" />
|
||||||
|
</root>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
11
.idea/libraries/junit_junit_5_0_SNAPSHOT.xml
Normal file
11
.idea/libraries/junit_junit_5_0_SNAPSHOT.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="junit:junit:5.0-SNAPSHOT" type="repository">
|
||||||
|
<properties maven-id="junit:junit:5.0-SNAPSHOT" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/5.0-SNAPSHOT/junit-5.0-SNAPSHOT.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/Four-In-A-Row.iml" filepath="$PROJECT_DIR$/Four-In-A-Row.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
1038
.idea/workspace.xml
Normal file
1038
.idea/workspace.xml
Normal file
File diff suppressed because it is too large
Load Diff
13
Four-In-A-Row.iml
Normal file
13
Four-In-A-Row.iml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="junit:junit:5.0-SNAPSHOT" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
3
META-INF/MANIFEST.MF
Normal file
3
META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: Main
|
||||||
|
|
BIN
out/artifacts/Four_In_A_Row/Four-In-A-Row.jar
Normal file
BIN
out/artifacts/Four_In_A_Row/Four-In-A-Row.jar
Normal file
Binary file not shown.
BIN
out/artifacts/Four_In_A_Row/Four-In-A-Row.zip
Normal file
BIN
out/artifacts/Four_In_A_Row/Four-In-A-Row.zip
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/Main$1.class
Normal file
BIN
out/production/Four-In-A-Row/Main$1.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/Main$Gamemode.class
Normal file
BIN
out/production/Four-In-A-Row/Main$Gamemode.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/Main.class
Normal file
BIN
out/production/Four-In-A-Row/Main.class
Normal file
Binary file not shown.
70
out/production/Four-In-A-Row/Plan.txt
Normal file
70
out/production/Four-In-A-Row/Plan.txt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
Two dimensional array.
|
||||||
|
Render each subarray from bottom to top.
|
||||||
|
Place each piece in the start of the array.
|
||||||
|
|
||||||
|
Let user choose from a button above each row where to place a chip.
|
||||||
|
|
||||||
|
Keep count of player names and colors, maybe with some text input.
|
||||||
|
objects.Player has name and color.
|
||||||
|
|
||||||
|
Turn + Events
|
||||||
|
|
||||||
|
Width = 7, Height = 6
|
||||||
|
|
||||||
|
Check from each block of a color (maybe keep track of blocked pieces for effectiveness).
|
||||||
|
Maybe allow for custom combinations required to win.
|
||||||
|
|
||||||
|
Game
|
||||||
|
- Winning Conditions
|
||||||
|
- board.Board
|
||||||
|
- GameObjects
|
||||||
|
- Random events
|
||||||
|
- Input/Output
|
||||||
|
- Players
|
||||||
|
|
||||||
|
Players
|
||||||
|
Class with info about player <- passive
|
||||||
|
- name
|
||||||
|
- color (of token)
|
||||||
|
|
||||||
|
Interface for a player's actions <- active
|
||||||
|
- Methods for throwing token into column.
|
||||||
|
- +Info
|
||||||
|
|
||||||
|
Input/Output
|
||||||
|
- Input interface
|
||||||
|
* int getNextColumn(objects.Player p); //Retrieve user input
|
||||||
|
- Output interface
|
||||||
|
* void displayBoard(board.IBoard b);
|
||||||
|
* void displayMessage(String s);
|
||||||
|
|
||||||
|
Random Events
|
||||||
|
- Interface events.IRandomEvent
|
||||||
|
* void act(board.IBoard b);
|
||||||
|
* String announcement();
|
||||||
|
|
||||||
|
events.IRandomEvent
|
||||||
|
Abstract events.RandomEvent implements events.IRandomEvent (void flipCoin // Does something if heads)
|
||||||
|
Shuffle extends events.RandomEvent
|
||||||
|
|
||||||
|
objects.GameObject
|
||||||
|
objects.Token
|
||||||
|
Owner instanceof objects.Player
|
||||||
|
|
||||||
|
GameObjects(objects.Token, empty)
|
||||||
|
* One class
|
||||||
|
* getColor();
|
||||||
|
|
||||||
|
Winning Conditions
|
||||||
|
- Interface events.IWinCondition
|
||||||
|
* boolean hasWon(objects.Player p, board.IBoard board);
|
||||||
|
|
||||||
|
|
||||||
|
"Main" method (Game)
|
||||||
|
- Outer loop: "While the game has not been finished"
|
||||||
|
1) Determine who's turn
|
||||||
|
2) Get next input: int j = input.getNextColumn(p);
|
||||||
|
3) Execute move: p throws in column j.
|
||||||
|
4) Check if p has won.
|
||||||
|
5) Update view (output.displayBoard())
|
||||||
|
6) events.RandomEvent.act();
|
BIN
out/production/Four-In-A-Row/board/Board.class
Normal file
BIN
out/production/Four-In-A-Row/board/Board.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/board/Grid.class
Normal file
BIN
out/production/Four-In-A-Row/board/Grid.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/board/IBoard.class
Normal file
BIN
out/production/Four-In-A-Row/board/IBoard.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/board/IGrid.class
Normal file
BIN
out/production/Four-In-A-Row/board/IGrid.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/Block.class
Normal file
BIN
out/production/Four-In-A-Row/events/Block.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/Bomb.class
Normal file
BIN
out/production/Four-In-A-Row/events/Bomb.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/FourInARow.class
Normal file
BIN
out/production/Four-In-A-Row/events/FourInARow.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/IRandomEvent.class
Normal file
BIN
out/production/Four-In-A-Row/events/IRandomEvent.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/IWinCondition.class
Normal file
BIN
out/production/Four-In-A-Row/events/IWinCondition.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/InARow.class
Normal file
BIN
out/production/Four-In-A-Row/events/InARow.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/RandomEvent.class
Normal file
BIN
out/production/Four-In-A-Row/events/RandomEvent.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/events/ThreeInARow.class
Normal file
BIN
out/production/Four-In-A-Row/events/ThreeInARow.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/FourInARowGUI$1.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/FourInARowGUI$1.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/FourInARowGUI.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/FourInARowGUI.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/GUI.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/GUI.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/IGameInterface.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/IGameInterface.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/NInARowGUI$1.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/NInARowGUI$1.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/NInARowGUI.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/NInARowGUI.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/TicTacToeGUI$1.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/TicTacToeGUI$1.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/interfaces/TicTacToeGUI.class
Normal file
BIN
out/production/Four-In-A-Row/interfaces/TicTacToeGUI.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/objects/Empty.class
Normal file
BIN
out/production/Four-In-A-Row/objects/Empty.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/objects/GameObject.class
Normal file
BIN
out/production/Four-In-A-Row/objects/GameObject.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/objects/Immovable.class
Normal file
BIN
out/production/Four-In-A-Row/objects/Immovable.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/objects/Player.class
Normal file
BIN
out/production/Four-In-A-Row/objects/Player.class
Normal file
Binary file not shown.
BIN
out/production/Four-In-A-Row/objects/Token.class
Normal file
BIN
out/production/Four-In-A-Row/objects/Token.class
Normal file
Binary file not shown.
BIN
out/test/Four-In-A-Row/FourInARowTest.class
Normal file
BIN
out/test/Four-In-A-Row/FourInARowTest.class
Normal file
Binary file not shown.
BIN
out/test/Four-In-A-Row/GridTest.class
Normal file
BIN
out/test/Four-In-A-Row/GridTest.class
Normal file
Binary file not shown.
BIN
out/test/Four-In-A-Row/TicTacToeTest.class
Normal file
BIN
out/test/Four-In-A-Row/TicTacToeTest.class
Normal file
Binary file not shown.
47
src/Main.java
Normal file
47
src/Main.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import board.Board;
|
||||||
|
import events.FourInARow;
|
||||||
|
import events.IWinCondition;
|
||||||
|
import interfaces.FourInARowGUI;
|
||||||
|
import interfaces.NInARowGUI;
|
||||||
|
import interfaces.TicTacToeGUI;
|
||||||
|
import objects.Empty;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class Main {
|
||||||
|
private static final int BOARD_WIDTH = 7;
|
||||||
|
private static final int BOARD_HEIGHT = 6;
|
||||||
|
private enum Gamemode {TICTACTOE, FOURINAROWCLASSIC, FOURINAROW}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
HashMap<String, Gamemode> modeList = new HashMap<>();
|
||||||
|
modeList.put("Tic-Tac-Toe", Gamemode.TICTACTOE);
|
||||||
|
modeList.put("Four in a row classic", Gamemode.FOURINAROWCLASSIC);
|
||||||
|
modeList.put("Four in a row", Gamemode.FOURINAROW);
|
||||||
|
Object[] keys = modeList.keySet().toArray();
|
||||||
|
|
||||||
|
String selectedValue = (String)JOptionPane.showInputDialog(null, "Select a game from the list below:", "Car model...", JOptionPane.QUESTION_MESSAGE,null, keys, keys[0]);
|
||||||
|
if (selectedValue == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
List<IWinCondition> con = new ArrayList<>();
|
||||||
|
con.add(new FourInARow());
|
||||||
|
switch (modeList.get(selectedValue)) {
|
||||||
|
case TICTACTOE:
|
||||||
|
new TicTacToeGUI();
|
||||||
|
break;
|
||||||
|
case FOURINAROWCLASSIC:
|
||||||
|
new FourInARowGUI(BOARD_WIDTH, BOARD_HEIGHT, new Board(BOARD_WIDTH, BOARD_HEIGHT, new Empty(), con));
|
||||||
|
break;
|
||||||
|
case FOURINAROW:
|
||||||
|
new NInARowGUI(BOARD_WIDTH, BOARD_HEIGHT, new Board(BOARD_WIDTH, BOARD_HEIGHT, new Empty(), con));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
70
src/Plan.txt
Normal file
70
src/Plan.txt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
Two dimensional array.
|
||||||
|
Render each subarray from bottom to top.
|
||||||
|
Place each piece in the start of the array.
|
||||||
|
|
||||||
|
Let user choose from a button above each row where to place a chip.
|
||||||
|
|
||||||
|
Keep count of player names and colors, maybe with some text input.
|
||||||
|
objects.Player has name and color.
|
||||||
|
|
||||||
|
Turn + Events
|
||||||
|
|
||||||
|
Width = 7, Height = 6
|
||||||
|
|
||||||
|
Check from each block of a color (maybe keep track of blocked pieces for effectiveness).
|
||||||
|
Maybe allow for custom combinations required to win.
|
||||||
|
|
||||||
|
Game
|
||||||
|
- Winning Conditions
|
||||||
|
- board.Board
|
||||||
|
- GameObjects
|
||||||
|
- Random events
|
||||||
|
- Input/Output
|
||||||
|
- Players
|
||||||
|
|
||||||
|
Players
|
||||||
|
Class with info about player <- passive
|
||||||
|
- name
|
||||||
|
- color (of token)
|
||||||
|
|
||||||
|
Interface for a player's actions <- active
|
||||||
|
- Methods for throwing token into column.
|
||||||
|
- +Info
|
||||||
|
|
||||||
|
Input/Output
|
||||||
|
- Input interface
|
||||||
|
* int getNextColumn(objects.Player p); //Retrieve user input
|
||||||
|
- Output interface
|
||||||
|
* void displayBoard(board.IBoard b);
|
||||||
|
* void displayMessage(String s);
|
||||||
|
|
||||||
|
Random Events
|
||||||
|
- Interface events.IRandomEvent
|
||||||
|
* void act(board.IBoard b);
|
||||||
|
* String announcement();
|
||||||
|
|
||||||
|
events.IRandomEvent
|
||||||
|
Abstract events.RandomEvent implements events.IRandomEvent (void flipCoin // Does something if heads)
|
||||||
|
Shuffle extends events.RandomEvent
|
||||||
|
|
||||||
|
objects.GameObject
|
||||||
|
objects.Token
|
||||||
|
Owner instanceof objects.Player
|
||||||
|
|
||||||
|
GameObjects(objects.Token, empty)
|
||||||
|
* One class
|
||||||
|
* getColor();
|
||||||
|
|
||||||
|
Winning Conditions
|
||||||
|
- Interface events.IWinCondition
|
||||||
|
* boolean hasWon(objects.Player p, board.IBoard board);
|
||||||
|
|
||||||
|
|
||||||
|
"Main" method (Game)
|
||||||
|
- Outer loop: "While the game has not been finished"
|
||||||
|
1) Determine who's turn
|
||||||
|
2) Get next input: int j = input.getNextColumn(p);
|
||||||
|
3) Execute move: p throws in column j.
|
||||||
|
4) Check if p has won.
|
||||||
|
5) Update view (output.displayBoard())
|
||||||
|
6) events.RandomEvent.act();
|
149
src/board/Board.java
Normal file
149
src/board/Board.java
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package board;
|
||||||
|
|
||||||
|
import events.IWinCondition;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class Board implements IBoard{
|
||||||
|
private final Grid<GameObject> grid;
|
||||||
|
private final List<Player> players;
|
||||||
|
private int playersTurn = 0;
|
||||||
|
private final List<IWinCondition> conditionList;
|
||||||
|
private boolean won = false;
|
||||||
|
|
||||||
|
public Board(int width, int height, GameObject obj, List<IWinCondition> conditions) {
|
||||||
|
grid = new Grid<>(width, height, obj);
|
||||||
|
players = new ArrayList<>();
|
||||||
|
conditionList = conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addPlayer(Player p) {
|
||||||
|
if (!playerExists(p)) {
|
||||||
|
players.add(p);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayList<Player> getPlayers() {
|
||||||
|
return new ArrayList<>(players);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next player.
|
||||||
|
*
|
||||||
|
* @return A Player
|
||||||
|
*/
|
||||||
|
public Player nextPlayer() {
|
||||||
|
Player p = players.get(playersTurn);
|
||||||
|
this.playersTurn = this.playersTurn + 2 > this.players.size() ? 0 : this.playersTurn + 1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure we don't have two equal players.
|
||||||
|
*
|
||||||
|
* @param player The new player to test
|
||||||
|
* @return True if the player is non-unique
|
||||||
|
*/
|
||||||
|
private boolean playerExists(Player player) {
|
||||||
|
for (Player p : players) {
|
||||||
|
if (player.equals(p)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFull() {
|
||||||
|
return grid.isFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if anyone has won.
|
||||||
|
*
|
||||||
|
* @param i The column of the last dropped object
|
||||||
|
*/
|
||||||
|
private void checkWin(int i) {
|
||||||
|
for (IWinCondition con : conditionList) {
|
||||||
|
if (con.hasWon(i, getTopObject(i), this)) {
|
||||||
|
won = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if anyone has won.
|
||||||
|
*
|
||||||
|
* @param x The x-coordinate of the last dropped object
|
||||||
|
* @param y The y-coordinate of the last dropped object
|
||||||
|
*/
|
||||||
|
private void checkWin(int x, int y) {
|
||||||
|
for (IWinCondition con : conditionList) {
|
||||||
|
if (con.hasWon(x, y, this)) {
|
||||||
|
won = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean won() {
|
||||||
|
return won;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
grid.flush();
|
||||||
|
playersTurn = 0;
|
||||||
|
won = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopObject(int column) {
|
||||||
|
return grid.getTopObject(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return grid.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return grid.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int x, int y, GameObject element) {
|
||||||
|
grid.set(x, y, element);
|
||||||
|
if (element instanceof Token) {
|
||||||
|
checkWin(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drop(int i, GameObject element) {
|
||||||
|
boolean dropped = grid.drop(i, element);
|
||||||
|
if (element instanceof Token) {
|
||||||
|
checkWin(i);
|
||||||
|
}
|
||||||
|
return dropped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameObject get(int x, int y) { return grid.get(x, y); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGrid<GameObject> copy() {
|
||||||
|
return grid.copy();
|
||||||
|
}
|
||||||
|
}
|
100
src/board/Grid.java
Normal file
100
src/board/Grid.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package board;
|
||||||
|
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
public class Grid<T> implements IGrid<T> {
|
||||||
|
private final T[][] grid;
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
private final T empty;
|
||||||
|
|
||||||
|
public Grid(int width, int height, T object) {
|
||||||
|
T[][] list = (T[][])new Object[width][height];
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
list[i][j] = object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grid = list;
|
||||||
|
this.empty = object;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
grid[i][j] = empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFull() {
|
||||||
|
int empty = 0;
|
||||||
|
for (T[] list : grid) {
|
||||||
|
for (T item : list) {
|
||||||
|
if (this.empty.getClass().isInstance(item)) {
|
||||||
|
empty++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return empty < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopObject(int column) {
|
||||||
|
for (int j = this.height - 1; j > -1; j--) {
|
||||||
|
if (grid[column][j] instanceof Token) {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drop(int i, T element) {
|
||||||
|
if (i > width || i < 0) {
|
||||||
|
throw new IllegalArgumentException("Index out of bounds.");
|
||||||
|
}
|
||||||
|
for (int j = 0; j < this.height; j++) {
|
||||||
|
if (this.empty.getClass().isInstance(grid[i][j])) {
|
||||||
|
grid[i][j] = element;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int x, int y, T element) {
|
||||||
|
if (x > width || y > height || x < 0 || y < 0) {
|
||||||
|
throw new IllegalArgumentException("Index out of bounds.");
|
||||||
|
}
|
||||||
|
grid[x][y] = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get(int x, int y) {
|
||||||
|
if (y >= height || x >= width || x < 0 || y < 0) {
|
||||||
|
throw new IllegalArgumentException("Index out of bound.");
|
||||||
|
}
|
||||||
|
return grid[x][y];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGrid<T> copy() {
|
||||||
|
Grid<T> newGrid = new Grid<>(width, height, empty);
|
||||||
|
System.arraycopy(grid, 0, newGrid.grid, 0, width);
|
||||||
|
return newGrid;
|
||||||
|
}
|
||||||
|
}
|
50
src/board/IBoard.java
Normal file
50
src/board/IBoard.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package board;
|
||||||
|
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IBoard extends IGrid<GameObject> {
|
||||||
|
/**
|
||||||
|
* Adds a new player to the board.
|
||||||
|
*
|
||||||
|
* @param p The player to add
|
||||||
|
* @return True if the player is valid
|
||||||
|
*/
|
||||||
|
boolean addPlayer(Player p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next player from the board.
|
||||||
|
*
|
||||||
|
* @return A player
|
||||||
|
*/
|
||||||
|
Player nextPlayer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out if someone has won.
|
||||||
|
*
|
||||||
|
* @return True if someone won
|
||||||
|
*/
|
||||||
|
boolean won();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes all values in the board.
|
||||||
|
*/
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the position of the topmost object in the board's grid.
|
||||||
|
*
|
||||||
|
* @param column The target column
|
||||||
|
* @return A position or -1 if all rows are empty
|
||||||
|
*/
|
||||||
|
int getTopObject(int column);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a copy of the players list.
|
||||||
|
*
|
||||||
|
* @return A list of players
|
||||||
|
*/
|
||||||
|
List<Player> getPlayers();
|
||||||
|
}
|
70
src/board/IGrid.java
Normal file
70
src/board/IGrid.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package board;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drops an element into column i.
|
||||||
|
*
|
||||||
|
* @param i The target column
|
||||||
|
* @param element The element to be dropped
|
||||||
|
* @return True if the column had space for the element
|
||||||
|
*/
|
||||||
|
boolean drop(int i, 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 fresh copy of the grid, with the same elements
|
||||||
|
*/
|
||||||
|
IGrid<T> copy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the grid is absolutely full.
|
||||||
|
*
|
||||||
|
* @return True if it is full
|
||||||
|
*/
|
||||||
|
boolean isFull();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the position of the topmost element from a column.
|
||||||
|
*
|
||||||
|
* @param column The target column
|
||||||
|
* @return The y-position of the top element
|
||||||
|
*/
|
||||||
|
int getTopObject(int column);
|
||||||
|
}
|
17
src/events/Block.java
Normal file
17
src/events/Block.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
import objects.Immovable;
|
||||||
|
|
||||||
|
public class Block extends RandomEvent {
|
||||||
|
@Override
|
||||||
|
public void act(IBoard b) {
|
||||||
|
int x = random.nextInt(b.getWidth());
|
||||||
|
b.drop(x, new Immovable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String announcement() {
|
||||||
|
return "An immovable object was placed.";
|
||||||
|
}
|
||||||
|
}
|
47
src/events/Bomb.java
Normal file
47
src/events/Bomb.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
import objects.Empty;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Bomb extends RandomEvent {
|
||||||
|
@Override
|
||||||
|
public void act(IBoard b) {
|
||||||
|
int x = random.nextInt(b.getWidth());
|
||||||
|
int y = b.getTopObject(x);
|
||||||
|
for (ArrayList<Integer> list : generateSquare(b, x, y, random.nextInt(2) + 1)) {
|
||||||
|
b.set(list.get(0), list.get(1), new Empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all locations in a square a range from a point.
|
||||||
|
*
|
||||||
|
* @param b A board
|
||||||
|
* @param x The x index of the starting point
|
||||||
|
* @param y The y index of the starting point
|
||||||
|
* @param range The range of the square
|
||||||
|
* @return A list of lists of integers
|
||||||
|
*/
|
||||||
|
private ArrayList<ArrayList<Integer>> generateSquare(IBoard b, int x, int y, int range) {
|
||||||
|
ArrayList<ArrayList<Integer>> locations = new ArrayList<>();
|
||||||
|
for (int i = x - range; i <= x + range; i++) {
|
||||||
|
for (int j = y - range; j <= y + range; j++) {
|
||||||
|
if (i >= 0 && i < b.getWidth() && j >= 0 && j < b.getHeight() && b.get(i, j) instanceof Token) {
|
||||||
|
ArrayList<Integer> coords = new ArrayList<>();
|
||||||
|
coords.add(i);
|
||||||
|
coords.add(j);
|
||||||
|
locations.add(coords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String announcement() {
|
||||||
|
return "A bomb just exploded!";
|
||||||
|
}
|
||||||
|
}
|
10
src/events/FourInARow.java
Normal file
10
src/events/FourInARow.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
public class FourInARow extends InARow {
|
||||||
|
@Override
|
||||||
|
public boolean hasWon(int x, int y, IBoard board) {
|
||||||
|
return hasWon(x, y, board, 3);
|
||||||
|
}
|
||||||
|
}
|
8
src/events/IRandomEvent.java
Normal file
8
src/events/IRandomEvent.java
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
public interface IRandomEvent {
|
||||||
|
void act(IBoard b);
|
||||||
|
String announcement();
|
||||||
|
}
|
18
src/events/IWinCondition.java
Normal file
18
src/events/IWinCondition.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A condition for winning the game.
|
||||||
|
*/
|
||||||
|
public interface IWinCondition {
|
||||||
|
/**
|
||||||
|
* Checks if someone has won according to the custom conditions.
|
||||||
|
*
|
||||||
|
* @param x The x-coordinate of the last placed element
|
||||||
|
* @param y The y-coordinate of the last placed element
|
||||||
|
* @param board The board to check
|
||||||
|
* @return True if someone has won
|
||||||
|
*/
|
||||||
|
boolean hasWon(int x, int y, IBoard board);
|
||||||
|
}
|
47
src/events/InARow.java
Normal file
47
src/events/InARow.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains methods for implementing any n in a row rules.
|
||||||
|
*/
|
||||||
|
abstract class InARow implements IWinCondition {
|
||||||
|
/**
|
||||||
|
* Checks if the supplied position has enough neighbours in a straight line of the same type
|
||||||
|
*
|
||||||
|
* @param x The x-coordinate of the start position
|
||||||
|
* @param y The y-coordinate of the start position
|
||||||
|
* @param board The board on which to perform the task
|
||||||
|
* @param t The number of elements in a row, which constitutes a win (excluding start position)
|
||||||
|
* @return True if x, y was a winning move
|
||||||
|
*/
|
||||||
|
static boolean hasWon(int x, int y, IBoard board, int t) {
|
||||||
|
return count(x, y, 1, 0, board) + count(x, y, -1, 0, board) >= t ||
|
||||||
|
count(x, y, 0, -1, board) + count(x, y, 0, 1, board) >= t ||
|
||||||
|
count(x, y, 1, 1, board) + count(x, y, -1, -1, board) >= t ||
|
||||||
|
count(x, y, 1, -1, board) + count(x, y, -1, 1, board) >= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts all elements from a start position in a set direction with a matching color.
|
||||||
|
*
|
||||||
|
* @param x The x-coordinate of the start position
|
||||||
|
* @param y The y-coordinate of the start position
|
||||||
|
* @param iX Step amount in x-direction
|
||||||
|
* @param iY Step amount in y-direction
|
||||||
|
* @param b The board on which to perform the task
|
||||||
|
* @return The number of elements found
|
||||||
|
*/
|
||||||
|
private static int count(int x, int y, int iX, int iY, IBoard b) {
|
||||||
|
int count = 0;
|
||||||
|
Color target = b.get(x, y).getColor();
|
||||||
|
while ((y + iY >= 0 && y + iY < b.getHeight()) && (x + iX >= 0 && x + iX < b.getWidth()) && b.get(x + iX, y + iY).getColor() == target) {
|
||||||
|
x += iX;
|
||||||
|
y += iY;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
43
src/events/RandomEvent.java
Normal file
43
src/events/RandomEvent.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains basic probability methods usable by all random events.
|
||||||
|
*/
|
||||||
|
public abstract class RandomEvent implements IRandomEvent {
|
||||||
|
final Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips a coin, and acts if it comes out as head.
|
||||||
|
*
|
||||||
|
* @param b The board to act on
|
||||||
|
* @return True if somehting happened. False otherwise
|
||||||
|
*/
|
||||||
|
public boolean flipCoin(IBoard b) {
|
||||||
|
if (random.nextInt(2) > 0) {
|
||||||
|
act(b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rolls n die, and acts if all die got a "6".
|
||||||
|
*
|
||||||
|
* @param b The board to act on
|
||||||
|
* @param n The number of die
|
||||||
|
* @return True if something happened. False otherwise
|
||||||
|
*/
|
||||||
|
public boolean rollDie(IBoard b, int n) {
|
||||||
|
if (random.nextInt((int)Math.pow(6, n)) < 1) {
|
||||||
|
act(b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void act(IBoard b);
|
||||||
|
}
|
10
src/events/ThreeInARow.java
Normal file
10
src/events/ThreeInARow.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package events;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
|
||||||
|
public class ThreeInARow extends InARow {
|
||||||
|
@Override
|
||||||
|
public boolean hasWon(int x, int y, IBoard board) {
|
||||||
|
return hasWon(x, y, board, 2);
|
||||||
|
}
|
||||||
|
}
|
136
src/interfaces/FourInARowGUI.java
Normal file
136
src/interfaces/FourInARowGUI.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package interfaces;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
public class FourInARowGUI extends GUI {
|
||||||
|
|
||||||
|
public FourInARowGUI(int width, int height, IBoard board) {
|
||||||
|
if (width < 3 || height < 3 || height > 50 || width > 50) {
|
||||||
|
throw new IllegalArgumentException("Invalid game size.");
|
||||||
|
}
|
||||||
|
if (width != board.getWidth() || height != board.getHeight()) {
|
||||||
|
throw new IllegalArgumentException("The board does not match the gui.");
|
||||||
|
}
|
||||||
|
this.board = board;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
String playerName = "";
|
||||||
|
while (playerName.equals("")) {
|
||||||
|
playerName = JOptionPane.showInputDialog(String.format("Name of player %d: ", i+1));
|
||||||
|
if (playerName == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Color color;
|
||||||
|
if (i == 0) {
|
||||||
|
color = Color.green;
|
||||||
|
} else {
|
||||||
|
color = Color.red;
|
||||||
|
}
|
||||||
|
Player player = new Player(playerName, color);
|
||||||
|
if (!this.board.addPlayer(player)) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Player is not unique. Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize(int width, int height) {
|
||||||
|
JFrame frame = new JFrame("Four in a row");
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int fullWidth = BUTTON_WIDTH * width + (WIDTH_GAP + 1) * width;
|
||||||
|
int fullHeight = BUTTON_HEIGHT + (TILE_HEIGHT * height) + HEIGHT_GAP * (height) + TILE_HEIGHT;
|
||||||
|
|
||||||
|
this.frame = frame;
|
||||||
|
JPanel container = new JPanel();
|
||||||
|
container.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||||
|
container.setPreferredSize(new Dimension(fullWidth, fullHeight + TILE_HEIGHT + BUTTON_HEIGHT));
|
||||||
|
frame.add(container);
|
||||||
|
|
||||||
|
JPanel panel3 = new JPanel();
|
||||||
|
this.resetButton = new JButton("Reset");
|
||||||
|
this.resetButton.addActionListener(this);
|
||||||
|
panel3.add(this.resetButton);
|
||||||
|
for (Player player : board.getPlayers()) {
|
||||||
|
JLabel playerLabel = new JLabel(player.toString());
|
||||||
|
playerLabel.setForeground(player.getColor());
|
||||||
|
panel3.add(playerLabel);
|
||||||
|
}
|
||||||
|
container.add(panel3);
|
||||||
|
|
||||||
|
JPanel panel2 = new JPanel();
|
||||||
|
this.mainPanel = panel2;
|
||||||
|
panel2.setBackground(Color.BLUE);
|
||||||
|
panel2.setLayout(new FlowLayout(FlowLayout.CENTER, HEIGHT_GAP, WIDTH_GAP));
|
||||||
|
panel2.setPreferredSize(new Dimension(fullWidth, fullHeight));
|
||||||
|
dropButtons = new JButton[width];
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
JButton button = new JButton();
|
||||||
|
button.addActionListener(this);
|
||||||
|
button.setPreferredSize(new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||||
|
dropButtons[i] = button;
|
||||||
|
panel2.add(button, BorderLayout.PAGE_START);
|
||||||
|
}
|
||||||
|
tiles = new JTextPane[width * height];
|
||||||
|
readTiles();
|
||||||
|
container.add(panel2);
|
||||||
|
|
||||||
|
infoLabel = new JLabel();
|
||||||
|
infoLabel.setPreferredSize(new Dimension(fullWidth, BUTTON_HEIGHT));
|
||||||
|
infoLabel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||||
|
container.add(infoLabel);
|
||||||
|
|
||||||
|
frame.validate();
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
this.currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (e.getSource() == this.resetButton) {
|
||||||
|
this.board.flush();
|
||||||
|
displayBoard();
|
||||||
|
this.currentPlayer = this.board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
if (!(this.board.won() || this.board.isFull())) {
|
||||||
|
for (int i = 0; i < this.dropButtons.length; i++) {
|
||||||
|
if (e.getSource() == this.dropButtons[i]) {
|
||||||
|
if (dropObject(i)) {
|
||||||
|
displayBoard();
|
||||||
|
if (!this.board.won()) {
|
||||||
|
if (board.isFull()) {
|
||||||
|
displayMessage("It's a draw");
|
||||||
|
} else {
|
||||||
|
this.currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GameObject winnerObject = this.board.get(i, this.board.getTopObject(i));
|
||||||
|
displayMessage(((Token)winnerObject).getOwner() + " won.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayMessage("That column is full.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
src/interfaces/GUI.java
Normal file
61
src/interfaces/GUI.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package interfaces;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
public abstract class GUI implements ActionListener, IGameInterface {
|
||||||
|
final int BUTTON_HEIGHT = 25;
|
||||||
|
final int BUTTON_WIDTH = 50;
|
||||||
|
final int TILE_HEIGHT = 50;
|
||||||
|
final int HEIGHT_GAP = 10;
|
||||||
|
final int WIDTH_GAP = 10;
|
||||||
|
|
||||||
|
JButton[] dropButtons;
|
||||||
|
JButton resetButton;
|
||||||
|
JTextPane[] tiles;
|
||||||
|
JLabel infoLabel;
|
||||||
|
IBoard board;
|
||||||
|
JPanel mainPanel;
|
||||||
|
JFrame frame;
|
||||||
|
|
||||||
|
Player currentPlayer;
|
||||||
|
|
||||||
|
public void displayBoard() {
|
||||||
|
for (JTextPane pane : this.tiles) {
|
||||||
|
this.mainPanel.remove(pane);
|
||||||
|
}
|
||||||
|
this.tiles = new JTextPane[this.board.getWidth() * this.board.getHeight()];
|
||||||
|
readTiles();
|
||||||
|
this.frame.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readTiles() {
|
||||||
|
int k = 0;
|
||||||
|
for (int i = board.getHeight() - 1; i > -1; i--) {
|
||||||
|
for (int j = 0; j < board.getWidth(); j++) {
|
||||||
|
JTextPane textPane = new JTextPane();
|
||||||
|
this.tiles[k++] = textPane;
|
||||||
|
textPane.setEditable(false);
|
||||||
|
textPane.setBackground(Color.BLUE);
|
||||||
|
GameObject obj = board.get(j,i);
|
||||||
|
textPane.setBorder(BorderFactory.createLineBorder(obj.getColor(), 50, true));
|
||||||
|
textPane.setPreferredSize(new Dimension(BUTTON_WIDTH, TILE_HEIGHT));
|
||||||
|
mainPanel.add(textPane, BorderLayout.PAGE_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean dropObject(int i) {
|
||||||
|
return this.board.drop(i, new Token(currentPlayer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayMessage(String s) {
|
||||||
|
infoLabel.setText(s);
|
||||||
|
}
|
||||||
|
}
|
6
src/interfaces/IGameInterface.java
Normal file
6
src/interfaces/IGameInterface.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package interfaces;
|
||||||
|
|
||||||
|
interface IGameInterface {
|
||||||
|
void displayMessage(String s);
|
||||||
|
void displayBoard();
|
||||||
|
}
|
181
src/interfaces/NInARowGUI.java
Normal file
181
src/interfaces/NInARowGUI.java
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package interfaces;
|
||||||
|
|
||||||
|
import board.IBoard;
|
||||||
|
import events.Block;
|
||||||
|
import events.Bomb;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
public class NInARowGUI extends GUI {
|
||||||
|
private Bomb bomb = new Bomb();
|
||||||
|
private Block block = new Block();
|
||||||
|
private JLabel eventLabel;
|
||||||
|
|
||||||
|
public NInARowGUI(int width, int height, IBoard board) {
|
||||||
|
if (width < 3 || height < 3 || height > 50 || width > 50) {
|
||||||
|
throw new IllegalArgumentException("Invalid game size.");
|
||||||
|
}
|
||||||
|
if (width != board.getWidth() || height != board.getHeight()) {
|
||||||
|
throw new IllegalArgumentException("The board does not match the gui.");
|
||||||
|
}
|
||||||
|
this.board = board;
|
||||||
|
int playerNum = 0;
|
||||||
|
while (playerNum == 0) {
|
||||||
|
try {
|
||||||
|
String num = JOptionPane.showInputDialog("Number of players: ");
|
||||||
|
if (num == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
playerNum = Integer.parseInt(num);
|
||||||
|
if (playerNum > width) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Number of players can't be higher than " + width, "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
playerNum = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Invalid input.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < playerNum; i++) {
|
||||||
|
String playerName = "";
|
||||||
|
while (playerName.equals("")) {
|
||||||
|
playerName = JOptionPane.showInputDialog(String.format("Name of player %d: ", i+1));
|
||||||
|
if (playerName == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Color color = null;
|
||||||
|
while (color == null) {
|
||||||
|
color = JColorChooser.showDialog(null, "Choose a color", Color.RED);
|
||||||
|
if (color == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
if (color == Color.lightGray || color == Color.blue || color == Color.black) {
|
||||||
|
JOptionPane.showMessageDialog(null, "The chosen color is reserved. Please choose another color.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
color = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Player player = new Player(playerName, color);
|
||||||
|
if (!this.board.addPlayer(player)) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Player is not unique. Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize(int width, int height) {
|
||||||
|
JFrame frame = new JFrame("Four in a row");
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int fullWidth = BUTTON_WIDTH * width + (WIDTH_GAP + 1) * width;
|
||||||
|
int fullHeight = BUTTON_HEIGHT + (TILE_HEIGHT * height) + HEIGHT_GAP * (height) + TILE_HEIGHT;
|
||||||
|
|
||||||
|
this.frame = frame;
|
||||||
|
JPanel container = new JPanel();
|
||||||
|
container.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||||
|
container.setPreferredSize(new Dimension(fullWidth, fullHeight + TILE_HEIGHT + 2 * BUTTON_HEIGHT));
|
||||||
|
frame.add(container);
|
||||||
|
|
||||||
|
JPanel panel3 = new JPanel();
|
||||||
|
this.resetButton = new JButton("Reset");
|
||||||
|
this.resetButton.addActionListener(this);
|
||||||
|
panel3.add(this.resetButton);
|
||||||
|
for (Player player : board.getPlayers()) {
|
||||||
|
JLabel playerLabel = new JLabel(player.toString());
|
||||||
|
playerLabel.setForeground(player.getColor());
|
||||||
|
panel3.add(playerLabel);
|
||||||
|
}
|
||||||
|
container.add(panel3);
|
||||||
|
|
||||||
|
JPanel panel2 = new JPanel();
|
||||||
|
this.mainPanel = panel2;
|
||||||
|
panel2.setBackground(Color.BLUE);
|
||||||
|
panel2.setLayout(new FlowLayout(FlowLayout.CENTER, HEIGHT_GAP, WIDTH_GAP));
|
||||||
|
panel2.setPreferredSize(new Dimension(fullWidth, fullHeight));
|
||||||
|
dropButtons = new JButton[width];
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
JButton button = new JButton();
|
||||||
|
button.addActionListener(this);
|
||||||
|
button.setPreferredSize(new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||||
|
dropButtons[i] = button;
|
||||||
|
panel2.add(button, BorderLayout.PAGE_START);
|
||||||
|
}
|
||||||
|
tiles = new JTextPane[width * height];
|
||||||
|
readTiles();
|
||||||
|
container.add(panel2);
|
||||||
|
|
||||||
|
infoLabel = new JLabel();
|
||||||
|
infoLabel.setPreferredSize(new Dimension(fullWidth, BUTTON_HEIGHT));
|
||||||
|
infoLabel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||||
|
container.add(infoLabel);
|
||||||
|
|
||||||
|
eventLabel = new JLabel();
|
||||||
|
eventLabel.setPreferredSize(new Dimension(fullWidth, BUTTON_HEIGHT));
|
||||||
|
eventLabel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||||
|
container.add(eventLabel);
|
||||||
|
|
||||||
|
frame.validate();
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
this.currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (e.getSource() == this.resetButton) {
|
||||||
|
this.board.flush();
|
||||||
|
displayBoard();
|
||||||
|
this.currentPlayer = this.board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
if (!(this.board.won() || this.board.isFull())) {
|
||||||
|
for (int i = 0; i < this.dropButtons.length; i++) {
|
||||||
|
if (e.getSource() == this.dropButtons[i]) {
|
||||||
|
if (dropObject(i)) {
|
||||||
|
displayBoard();
|
||||||
|
if (this.board.won()) {
|
||||||
|
GameObject winnerObject = this.board.get(i, this.board.getTopObject(i));
|
||||||
|
displayMessage(((Token)winnerObject).getOwner() + " won.");
|
||||||
|
} else {
|
||||||
|
triggerEvents();
|
||||||
|
if (board.isFull()) {
|
||||||
|
displayMessage("It's a draw");
|
||||||
|
} else {
|
||||||
|
this.currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayMessage("That column is full.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerEvents() {
|
||||||
|
if (bomb.rollDie(this.board, 2)) {
|
||||||
|
eventLabel.setText(bomb.announcement());
|
||||||
|
displayBoard();
|
||||||
|
} else if (block.rollDie(this.board, 1)) {
|
||||||
|
eventLabel.setText(block.announcement());
|
||||||
|
displayBoard();
|
||||||
|
} else {
|
||||||
|
eventLabel.setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
151
src/interfaces/TicTacToeGUI.java
Normal file
151
src/interfaces/TicTacToeGUI.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package interfaces;
|
||||||
|
|
||||||
|
import board.Board;
|
||||||
|
import events.IWinCondition;
|
||||||
|
import events.ThreeInARow;
|
||||||
|
import objects.Empty;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TicTacToeGUI extends GUI {
|
||||||
|
private JButton[] gameGrid = new JButton[9];
|
||||||
|
|
||||||
|
public TicTacToeGUI() {
|
||||||
|
List<IWinCondition> conditions = new ArrayList<>();
|
||||||
|
conditions.add(new ThreeInARow());
|
||||||
|
this.board = new Board(3,3, new Empty(), conditions);
|
||||||
|
int playerNum = 2;
|
||||||
|
for (int i = 0; i < playerNum; i++) {
|
||||||
|
String playerName = "";
|
||||||
|
while (playerName.equals("")) {
|
||||||
|
playerName = JOptionPane.showInputDialog(String.format("Name of player %d: ", i+1));
|
||||||
|
if (playerName == null) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
if (playerName.length() > 10) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Player name can't be longer than 10 characters.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
playerName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Player player;
|
||||||
|
if (i == 1) {
|
||||||
|
player = new Player(playerName, Color.BLACK);
|
||||||
|
} else {
|
||||||
|
player = new Player(playerName, Color.WHITE);
|
||||||
|
}
|
||||||
|
if (!this.board.addPlayer(player)) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Player is not unique. Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
JFrame frame = new JFrame("Four in a row");
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int fullWidth = (BUTTON_WIDTH) * 3;
|
||||||
|
int fullHeight = (TILE_HEIGHT) * 3;
|
||||||
|
|
||||||
|
this.frame = frame;
|
||||||
|
JPanel container = new JPanel();
|
||||||
|
container.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||||
|
container.setPreferredSize(new Dimension(fullWidth, fullHeight + 2 * BUTTON_HEIGHT));
|
||||||
|
frame.add(container);
|
||||||
|
|
||||||
|
JPanel panel2 = new JPanel();
|
||||||
|
this.mainPanel = panel2;
|
||||||
|
panel2.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||||
|
panel2.setPreferredSize(new Dimension(fullWidth, fullHeight));
|
||||||
|
readTiles();
|
||||||
|
container.add(panel2);
|
||||||
|
|
||||||
|
infoLabel = new JLabel();
|
||||||
|
infoLabel.setPreferredSize(new Dimension(fullWidth, 15));
|
||||||
|
infoLabel.setBorder(new EmptyBorder(10, 10, 15, 10));
|
||||||
|
container.add(infoLabel);
|
||||||
|
this.resetButton = new JButton("Reset");
|
||||||
|
this.resetButton.addActionListener(this);
|
||||||
|
container.add(this.resetButton);
|
||||||
|
|
||||||
|
frame.validate();
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayBoard() {
|
||||||
|
for (JButton button : this.gameGrid) {
|
||||||
|
this.mainPanel.remove(button);
|
||||||
|
}
|
||||||
|
this.gameGrid = new JButton[this.board.getWidth() * this.board.getHeight()];
|
||||||
|
readTiles();
|
||||||
|
this.frame.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readTiles() {
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < board.getHeight(); i++) {
|
||||||
|
for (int j = 0; j < board.getWidth(); j++) {
|
||||||
|
JButton button = new JButton();
|
||||||
|
button.addActionListener(this);
|
||||||
|
GameObject obj = board.get(j,i);
|
||||||
|
if (obj.getColor() == Color.black) {
|
||||||
|
button.setText("X");
|
||||||
|
} else if (obj.getColor() == Color.white) {
|
||||||
|
button.setText("O");
|
||||||
|
}
|
||||||
|
button.setPreferredSize(new Dimension(BUTTON_WIDTH, TILE_HEIGHT));
|
||||||
|
this.gameGrid[k++] = button;
|
||||||
|
mainPanel.add(button, BorderLayout.PAGE_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (e.getSource() == this.resetButton) {
|
||||||
|
this.board.flush();
|
||||||
|
displayBoard();
|
||||||
|
this.currentPlayer = this.board.nextPlayer();
|
||||||
|
displayMessage("It's " + this.currentPlayer + "'s turn.");
|
||||||
|
}
|
||||||
|
if (!(board.won() || board.isFull())) {
|
||||||
|
for (int i = 0; i < this.gameGrid.length; i++) {
|
||||||
|
if (e.getSource() == this.gameGrid[i]) {
|
||||||
|
if (this.gameGrid[i].getText().equals("")) {
|
||||||
|
int x = i % 3;
|
||||||
|
int y = i / 3;
|
||||||
|
this.board.set(x, y, new Token(currentPlayer));
|
||||||
|
displayBoard();
|
||||||
|
if (!board.won()) {
|
||||||
|
currentPlayer = board.nextPlayer();
|
||||||
|
displayMessage("It's " + currentPlayer + "'s turn.");
|
||||||
|
} else {
|
||||||
|
GameObject winnerObject = board.get(x, board.getTopObject(x));
|
||||||
|
displayMessage(((Token)winnerObject).getOwner() + " won.");
|
||||||
|
}
|
||||||
|
if (board.isFull()) {
|
||||||
|
displayMessage("It's a draw");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/objects/Empty.java
Normal file
3
src/objects/Empty.java
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package objects;
|
||||||
|
|
||||||
|
public class Empty extends GameObject {}
|
11
src/objects/GameObject.java
Normal file
11
src/objects/GameObject.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package objects;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public abstract class GameObject {
|
||||||
|
Color color = Color.LIGHT_GRAY;
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
9
src/objects/Immovable.java
Normal file
9
src/objects/Immovable.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package objects;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class Immovable extends GameObject {
|
||||||
|
public Immovable() {
|
||||||
|
this.color = Color.BLACK;
|
||||||
|
}
|
||||||
|
}
|
38
src/objects/Player.java
Normal file
38
src/objects/Player.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package objects;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Player {
|
||||||
|
private final String name;
|
||||||
|
private final Color color;
|
||||||
|
|
||||||
|
public Player(String name, Color color) {
|
||||||
|
this.name = name;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Player player = (Player) o;
|
||||||
|
return Objects.equals(name, player.name) ||
|
||||||
|
Objects.equals(color, player.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
|
||||||
|
return Objects.hash(name, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
14
src/objects/Token.java
Normal file
14
src/objects/Token.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package objects;
|
||||||
|
|
||||||
|
public class Token extends GameObject {
|
||||||
|
private final Player owner;
|
||||||
|
|
||||||
|
public Token(Player owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.color = owner.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getOwner() {
|
||||||
|
return this.owner;
|
||||||
|
}
|
||||||
|
}
|
63
test/FourInARowTest.java
Normal file
63
test/FourInARowTest.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import board.Board;
|
||||||
|
import events.FourInARow;
|
||||||
|
import events.IWinCondition;
|
||||||
|
import objects.Empty;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class FourInARowTest {
|
||||||
|
private final List<IWinCondition> conditions = new ArrayList<>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void horisontalTest() {
|
||||||
|
conditions.add(new FourInARow());
|
||||||
|
Board board = new Board(4, 1, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.RED));
|
||||||
|
assertTrue(board.drop(0, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(1, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(2, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(3, token));
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verticalTest() {
|
||||||
|
conditions.add(new FourInARow());
|
||||||
|
Board board = new Board(1, 4, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.RED));
|
||||||
|
assertTrue(board.drop(0, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(0, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(0, token));
|
||||||
|
assertFalse(board.won());
|
||||||
|
assertTrue(board.drop(0, token));
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void diagonalTest() {
|
||||||
|
conditions.add(new FourInARow());
|
||||||
|
Board board = new Board(10, 10, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.RED));
|
||||||
|
board.set(0, 0, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(1, 1, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(2, 2, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(3, 3, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
}
|
34
test/GridTest.java
Normal file
34
test/GridTest.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import board.Grid;
|
||||||
|
import objects.Empty;
|
||||||
|
import objects.GameObject;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class GridTest {
|
||||||
|
@Test
|
||||||
|
public void gridWidthTest() {
|
||||||
|
GameObject empty = new Empty();
|
||||||
|
Grid<GameObject> grid = new Grid<>(10, 11, empty);
|
||||||
|
assertEquals(10, grid.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void gridHeightTest() {
|
||||||
|
GameObject empty = new Empty();
|
||||||
|
Grid<GameObject> grid = new Grid<>(10, 11, empty);
|
||||||
|
assertEquals(11, grid.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void gridSetGetTest() {
|
||||||
|
GameObject empty = new Empty();
|
||||||
|
Grid<GameObject> grid = new Grid<>(10, 11, empty);
|
||||||
|
Token token = new Token(new Player("Naem", Color.green));
|
||||||
|
grid.set(7, 3, token);
|
||||||
|
assertEquals(token, grid.get(7, 3));
|
||||||
|
}}
|
82
test/TicTacToeTest.java
Normal file
82
test/TicTacToeTest.java
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import board.Board;
|
||||||
|
import events.IWinCondition;
|
||||||
|
import events.ThreeInARow;
|
||||||
|
import objects.Empty;
|
||||||
|
import objects.Player;
|
||||||
|
import objects.Token;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class TicTacToeTest {
|
||||||
|
private final List<IWinCondition> conditions = new ArrayList<>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void horisontalTest() {
|
||||||
|
conditions.add(new ThreeInARow());
|
||||||
|
Board board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.WHITE));
|
||||||
|
board.set(0, 0, token);
|
||||||
|
board.set(1, 0, token);
|
||||||
|
board.set(2, 0, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
board.set(0, 1, token);
|
||||||
|
board.set(1, 1, token);
|
||||||
|
board.set(2, 1, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
board.set(0, 2, token);
|
||||||
|
board.set(1, 2, token);
|
||||||
|
board.set(2, 2, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verticalTest() {
|
||||||
|
conditions.add(new ThreeInARow());
|
||||||
|
Board board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.WHITE));
|
||||||
|
board.set(0, 0, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(0, 1, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(0, 2, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
board.set(1, 0, token);
|
||||||
|
board.set(1, 1, token);
|
||||||
|
board.set(1, 2, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
board.set(2, 0, token);
|
||||||
|
board.set(2, 1, token);
|
||||||
|
board.set(2, 2, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void diagonalTest() {
|
||||||
|
conditions.add(new ThreeInARow());
|
||||||
|
Board board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
Token token = new Token(new Player("Naem", Color.WHITE));
|
||||||
|
board.set(0, 0, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(1, 1, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(2, 2, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
board = new Board(3, 3, new Empty(), conditions);
|
||||||
|
board.set(0, 2, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(1, 1, token);
|
||||||
|
assertFalse(board.won());
|
||||||
|
board.set(2, 0, token);
|
||||||
|
assertTrue(board.won());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user