├── .DS_Store
├── src
└── main
│ ├── resources
│ ├── style
│ │ ├── CreatePlayer.css
│ │ ├── Style.css
│ │ └── Board.css
│ ├── asset
│ │ ├── info.png
│ │ ├── error.png
│ │ ├── warning.png
│ │ └── connect-four.png
│ └── view
│ │ ├── CreatePlayer.fxml
│ │ └── Board.fxml
│ └── java
│ └── lk
│ └── ijse
│ └── dep
│ ├── service
│ ├── Piece.java
│ ├── BoardUi.java
│ ├── Player.java
│ ├── Board.java
│ ├── HumanPlayer.java
│ ├── Winner.java
│ ├── BoardImpl.java
│ └── AiPlayer.java
│ ├── Launcher.java
│ ├── AppInitializer.java
│ ├── util
│ └── DEPAlert.java
│ └── controller
│ ├── CreatePlayerController.java
│ └── BoardController.java
├── target
├── classes
│ ├── asset
│ │ ├── error.png
│ │ ├── info.png
│ │ ├── warning.png
│ │ └── connect-four.png
│ ├── style
│ │ ├── CreatePlayer.css
│ │ ├── Style.css
│ │ └── Board.css
│ ├── lk
│ │ └── ijse
│ │ │ └── dep
│ │ │ ├── Launcher.class
│ │ │ ├── service
│ │ │ ├── Board.class
│ │ │ ├── Piece.class
│ │ │ ├── BoardUi.class
│ │ │ ├── Player.class
│ │ │ ├── Winner.class
│ │ │ ├── AiPlayer.class
│ │ │ ├── BoardImpl.class
│ │ │ └── HumanPlayer.class
│ │ │ ├── util
│ │ │ ├── DEPAlert.class
│ │ │ └── DEPAlert$1.class
│ │ │ ├── AppInitializer.class
│ │ │ └── controller
│ │ │ ├── BoardController$1.class
│ │ │ ├── BoardController.class
│ │ │ └── CreatePlayerController.class
│ └── view
│ │ ├── CreatePlayer.fxml
│ │ └── Board.fxml
└── maven-status
│ └── maven-compiler-plugin
│ └── compile
│ └── default-compile
│ ├── createdFiles.lst
│ └── inputFiles.lst
├── LICENSE.txt
├── connect-four-assignment.iml
├── README.md
└── pom.xml
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/.DS_Store
--------------------------------------------------------------------------------
/src/main/resources/style/CreatePlayer.css:
--------------------------------------------------------------------------------
1 | .jfx-text-field{
2 | -fx-font-size: 24px;
3 | -fx-alignment: center;
4 | }
5 |
--------------------------------------------------------------------------------
/target/classes/asset/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/asset/error.png
--------------------------------------------------------------------------------
/target/classes/asset/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/asset/info.png
--------------------------------------------------------------------------------
/target/classes/style/CreatePlayer.css:
--------------------------------------------------------------------------------
1 | .jfx-text-field{
2 | -fx-font-size: 24px;
3 | -fx-alignment: center;
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/resources/asset/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/src/main/resources/asset/info.png
--------------------------------------------------------------------------------
/target/classes/asset/warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/asset/warning.png
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/Piece.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | public enum Piece {
4 | GREEN,BLUE,EMPTY;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/resources/asset/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/src/main/resources/asset/error.png
--------------------------------------------------------------------------------
/src/main/resources/asset/warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/src/main/resources/asset/warning.png
--------------------------------------------------------------------------------
/target/classes/asset/connect-four.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/asset/connect-four.png
--------------------------------------------------------------------------------
/src/main/resources/asset/connect-four.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/src/main/resources/asset/connect-four.png
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/Launcher.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/Launcher.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/Board.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/Board.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/Piece.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/Piece.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/util/DEPAlert.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/util/DEPAlert.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/AppInitializer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/AppInitializer.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/BoardUi.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/BoardUi.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/Player.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/Player.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/Winner.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/Winner.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/util/DEPAlert$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/util/DEPAlert$1.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/AiPlayer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/AiPlayer.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/BoardImpl.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/BoardImpl.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/service/HumanPlayer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/service/HumanPlayer.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/controller/BoardController$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/controller/BoardController$1.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/controller/BoardController.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/controller/BoardController.class
--------------------------------------------------------------------------------
/target/classes/lk/ijse/dep/controller/CreatePlayerController.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DewmithMihisara/connect-4-game/HEAD/target/classes/lk/ijse/dep/controller/CreatePlayerController.class
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/Launcher.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep;
2 |
3 | public class Launcher {
4 |
5 | public static void main(String[] args) {
6 | AppInitializer.main(args);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/BoardUi.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | public interface BoardUi {
4 | void update(int col, boolean isHuman);
5 |
6 | void notifyWinner(Winner winner);
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/Player.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | public class Player {
4 | protected Board board;
5 | public Player(Board board){
6 | this.board=board;
7 | }
8 | public void movePiece(int col1) {}
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/Board.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 | public interface Board {
3 | final int NUM_OF_ROWS =5;
4 | final int NUM_OF_COLS =6;
5 | public BoardUi getBoardUi();
6 | public int findNextAvailableSpot(int col);
7 | public boolean isLegalMoves(int col);
8 | public boolean exitLegalMoves();
9 | public void updateMove(int col, Piece move);
10 | public void updateMove(int col, int row, Piece move);
11 | public Winner findWinner();
12 | }
13 |
--------------------------------------------------------------------------------
/target/classes/style/Style.css:
--------------------------------------------------------------------------------
1 | *{
2 | -fx-font-family: Ubuntu Serif;
3 | }
4 |
5 | .label{
6 | -fx-font-size: 14px;
7 | }
8 |
9 | .title{
10 | -fx-font-size: 28px;
11 | -fx-font-weight: 700;
12 | }
13 |
14 | .pane{
15 | -fx-background-color: white;
16 | }
17 |
18 | .jfx-button{
19 | -fx-font-size: 20px;
20 | -fx-font-weight: bold;
21 | -fx-background-color: #00b2ff;
22 | -fx-text-fill: #ffffff;
23 | -fx-cursor: hand;
24 | }
25 |
26 |
27 |
28 | .small{
29 | -fx-font-size: 10px;
30 | }
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/main/resources/style/Style.css:
--------------------------------------------------------------------------------
1 | *{
2 | -fx-font-family: Ubuntu Serif;
3 | }
4 |
5 | .label{
6 | -fx-font-size: 14px;
7 | }
8 |
9 | .title{
10 | -fx-font-size: 28px;
11 | -fx-font-weight: 700;
12 | }
13 |
14 | .pane{
15 | -fx-background-color: white;
16 | }
17 |
18 | .jfx-button{
19 | -fx-font-size: 20px;
20 | -fx-font-weight: bold;
21 | -fx-background-color: #00b2ff;
22 | -fx-text-fill: #ffffff;
23 | -fx-cursor: hand;
24 | }
25 |
26 |
27 |
28 | .small{
29 | -fx-font-size: 10px;
30 | }
31 |
32 |
33 |
--------------------------------------------------------------------------------
/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst:
--------------------------------------------------------------------------------
1 | lk/ijse/dep/service/BoardUi.class
2 | lk/ijse/dep/service/AiPlayer.class
3 | lk/ijse/dep/service/Winner.class
4 | lk/ijse/dep/util/DEPAlert.class
5 | lk/ijse/dep/util/DEPAlert$1.class
6 | lk/ijse/dep/service/HumanPlayer.class
7 | lk/ijse/dep/controller/BoardController.class
8 | lk/ijse/dep/service/BoardController.class
9 | lk/ijse/dep/service/Board.class
10 | lk/ijse/dep/Launcher.class
11 | lk/ijse/dep/controller/CreatePlayerController.class
12 | lk/ijse/dep/controller/BoardController$1.class
13 | lk/ijse/dep/service/Piece.class
14 | lk/ijse/dep/AppInitializer.class
15 | lk/ijse/dep/service/BoardImpl.class
16 | lk/ijse/dep/service/Player.class
17 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/AppInitializer.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep;
2 |
3 | import javafx.application.Application;
4 | import javafx.fxml.FXMLLoader;
5 | import javafx.scene.Scene;
6 | import javafx.stage.Stage;
7 |
8 | import java.io.IOException;
9 |
10 | public class AppInitializer extends Application {
11 |
12 | public static void main(String[] args) {
13 | launch(args);
14 | }
15 |
16 | @Override
17 | public void start(Stage primaryStage) throws IOException {
18 | primaryStage.setScene(new Scene(FXMLLoader.load(getClass().getResource("/view/CreatePlayer.fxml"))));
19 | primaryStage.setResizable(false);
20 | primaryStage.setTitle("Connect 4 Game - Create Player");
21 | primaryStage.show();
22 | primaryStage.centerOnScreen();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/HumanPlayer.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 | public class HumanPlayer extends Player{
3 | boolean isTrue;
4 | public HumanPlayer(Board newBoard) {
5 | super(newBoard);
6 | }
7 | @Override
8 | public void movePiece(int col1) {
9 | isTrue=board.isLegalMoves(col1);
10 | if(isTrue){
11 | board.updateMove(col1,Piece.BLUE);
12 | board.getBoardUi().update(col1,isTrue);
13 | Winner winner=board.findWinner();
14 | if (winner.getWinningPiece()!=Piece.EMPTY){
15 | board.getBoardUi().notifyWinner(winner);
16 | }else {
17 | if (!board.exitLegalMoves()){
18 | board.getBoardUi().notifyWinner(new Winner(Piece.EMPTY));
19 | }
20 | }
21 |
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 DEP. All Rights Reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/util/DEPAlert.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.util;
2 |
3 | import javafx.scene.control.Alert;
4 | import javafx.scene.control.ButtonType;
5 | import javafx.scene.image.Image;
6 | import javafx.scene.image.ImageView;
7 |
8 | public class DEPAlert extends Alert {
9 |
10 | public DEPAlert(AlertType alertType, String title, String header, String message, ButtonType... buttonTypes) {
11 | super(alertType, message, buttonTypes);
12 | setTitle(title);
13 | setHeaderText(header);
14 |
15 | String image = null;
16 | switch (alertType){
17 | case ERROR:
18 | image = "/asset/error.png";
19 | break;
20 | case INFORMATION:
21 | image = "/asset/info.png";
22 | break;
23 | case WARNING:
24 | image = "/asset/warning.png";
25 | break;
26 | }
27 |
28 | if (image !=null){
29 | ImageView imgView = new ImageView(new Image(image));
30 | imgView.setFitWidth(32);
31 | imgView.setFitHeight(32);
32 | setGraphic(imgView);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/Winner.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | public class Winner {
4 | private Piece winningPice;
5 | private int col1;
6 | private int row1;
7 | private int col2;
8 | private int row2;
9 |
10 | public Winner(Piece winningPice, int col1,int row1, int col2,int row2){
11 | this.winningPice=winningPice;
12 | this.col1=col1;
13 | this.row1=row1;
14 | this.col2=col2;
15 | this.row2=row2;
16 | }
17 |
18 | public Winner(Piece winningPice){
19 | this.winningPice=winningPice;
20 | this.col1=-1;
21 | this.col2=-1;
22 | this.row1=-1;
23 | this.row2=-1;
24 | }
25 | public Piece getWinningPiece() {
26 | return winningPice;
27 | }
28 | public int getCol1() {
29 | return col1;
30 | }
31 | public int getCol2() {
32 | return col2;
33 | }
34 | public int getRow1() {
35 | return row1;
36 | }
37 | public int getRow2() {
38 | return row2;
39 | }
40 | @Override
41 | public String toString(){
42 | return "Winner{" +
43 | "winningPiece=" + winningPice +
44 | ", col1=" + col1 +
45 | ", row1=" + row1 +
46 | ", col2=" + col2 +
47 | ", row2=" + row2 +
48 | '}';
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/connect-four-assignment.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst:
--------------------------------------------------------------------------------
1 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/Board.java
2 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/Player.java
3 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/controller/CreatePlayerController.java
4 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/Launcher.java
5 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/util/DEPAlert.java
6 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/AppInitializer.java
7 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/HumanPlayer.java
8 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/controller/BoardController.java
9 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/BoardController.java
10 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/Piece.java
11 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/Winner.java
12 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/AiPlayer.java
13 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/BoardUi.java
14 | /Users/dewmithmihisara/OOP Course work (Game)/connect-four-game-assignment/src/main/java/lk/ijse/dep/service/BoardImpl.java
15 |
--------------------------------------------------------------------------------
/target/classes/style/Board.css:
--------------------------------------------------------------------------------
1 | .col{
2 | -fx-border-width: 1 1 2 1;
3 | -fx-border-color: #dcdcdc;
4 | -fx-border-radius: 5px;
5 | -fx-background-radius: 5px;
6 | -fx-border-style: dashed solid solid solid;
7 | }
8 |
9 | .col-first{
10 | -fx-border-width: 1 1 2 2;
11 | }
12 |
13 | .col-last{
14 | -fx-border-width: 1 2 2 1;
15 | }
16 |
17 | .col-ai{
18 | -fx-background-color: #e0ffcc;
19 | -fx-border-width: 2;
20 | -fx-border-color: #a6a6a6;
21 | -fx-border-radius: 5px;
22 | }
23 |
24 | .col-filled:hover{
25 | -fx-background-color: #ffbfbf !important;
26 | -fx-border-color: #ff4f4f !important;
27 | }
28 |
29 | .col-human:hover{
30 | -fx-cursor: hand;
31 | -fx-background-color: #d7f7ff;
32 | -fx-border-width: 2;
33 | -fx-border-color: #a6a6a6;
34 | -fx-border-radius: 5px;
35 | }
36 |
37 | .four{
38 | -fx-font-size: 42px;
39 | }
40 |
41 | #lblStatus{
42 | -fx-font-size: 24px;
43 | -fx-background-color: #f1f1f1;
44 | -fx-font-weight: bold;
45 | -fx-background-radius: 10px;
46 | }
47 |
48 | .circle-ai{
49 | -fx-stroke-width: 0;
50 | -fx-fill: #00f504;
51 | }
52 |
53 | .circle-human{
54 | -fx-stroke-width: 0;
55 | -fx-fill: #1e90ff;
56 | }
57 |
58 | .human{
59 | -fx-text-fill: #1e90ff;
60 | -fx-background-color: #eafffc !important;
61 | }
62 |
63 | .ai{
64 | -fx-text-fill: #00f531;
65 | -fx-background-color: #eaffe4 !important;
66 | }
67 |
68 | .final{
69 | -fx-text-fill: #ff0089;
70 | }
71 |
72 | .winning-rect{
73 | -fx-fill: rgb(255, 184, 0);
74 | -fx-opacity: 0.5;
75 | -fx-stroke-width: 1;
76 | -fx-stroke: #ff0089;
77 | -fx-arc-height: 10px;
78 | -fx-arc-width: 10px;
79 | }
80 |
81 | #pneOver{
82 | -fx-background-color: rgba(100, 98, 98, 0.43);
83 | -fx-background-radius: 10px;
84 | }
85 |
86 | .jfx-button:hover{
87 | -fx-text-fill: black !important;
88 | }
--------------------------------------------------------------------------------
/src/main/resources/style/Board.css:
--------------------------------------------------------------------------------
1 | .col{
2 | -fx-border-width: 1 1 2 1;
3 | -fx-border-color: #dcdcdc;
4 | -fx-border-radius: 5px;
5 | -fx-background-radius: 5px;
6 | -fx-border-style: dashed solid solid solid;
7 | }
8 |
9 | .col-first{
10 | -fx-border-width: 1 1 2 2;
11 | }
12 |
13 | .col-last{
14 | -fx-border-width: 1 2 2 1;
15 | }
16 |
17 | .col-ai{
18 | -fx-background-color: #e0ffcc;
19 | -fx-border-width: 2;
20 | -fx-border-color: #a6a6a6;
21 | -fx-border-radius: 5px;
22 | }
23 |
24 | .col-filled:hover{
25 | -fx-background-color: #ffbfbf !important;
26 | -fx-border-color: #ff4f4f !important;
27 | }
28 |
29 | .col-human:hover{
30 | -fx-cursor: hand;
31 | -fx-background-color: #d7f7ff;
32 | -fx-border-width: 2;
33 | -fx-border-color: #a6a6a6;
34 | -fx-border-radius: 5px;
35 | }
36 |
37 | .four{
38 | -fx-font-size: 42px;
39 | }
40 |
41 | #lblStatus{
42 | -fx-font-size: 24px;
43 | -fx-background-color: #f1f1f1;
44 | -fx-font-weight: bold;
45 | -fx-background-radius: 10px;
46 | }
47 |
48 | .circle-ai{
49 | -fx-stroke-width: 0;
50 | -fx-fill: #00f504;
51 | }
52 |
53 | .circle-human{
54 | -fx-stroke-width: 0;
55 | -fx-fill: #1e90ff;
56 | }
57 |
58 | .human{
59 | -fx-text-fill: #1e90ff;
60 | -fx-background-color: #eafffc !important;
61 | }
62 |
63 | .ai{
64 | -fx-text-fill: #00f531;
65 | -fx-background-color: #eaffe4 !important;
66 | }
67 |
68 | .final{
69 | -fx-text-fill: #ff0089;
70 | }
71 |
72 | .winning-rect{
73 | -fx-fill: rgb(255, 184, 0);
74 | -fx-opacity: 0.5;
75 | -fx-stroke-width: 1;
76 | -fx-stroke: #ff0089;
77 | -fx-arc-height: 10px;
78 | -fx-arc-width: 10px;
79 | }
80 |
81 | #pneOver{
82 | -fx-background-color: rgba(100, 98, 98, 0.43);
83 | -fx-background-radius: 10px;
84 | }
85 |
86 | .jfx-button:hover{
87 | -fx-text-fill: black !important;
88 | }
--------------------------------------------------------------------------------
/target/classes/view/CreatePlayer.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/main/resources/view/CreatePlayer.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/controller/CreatePlayerController.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.controller;
2 |
3 | import com.jfoenix.controls.JFXButton;
4 | import com.jfoenix.controls.JFXTextField;
5 | import javafx.application.Platform;
6 | import javafx.event.ActionEvent;
7 | import javafx.event.Event;
8 | import javafx.fxml.FXMLLoader;
9 | import javafx.scene.Scene;
10 | import javafx.scene.control.Alert;
11 | import javafx.scene.input.MouseEvent;
12 | import javafx.scene.shape.CubicCurve;
13 | import javafx.stage.Stage;
14 | import lk.ijse.dep.util.DEPAlert;
15 |
16 | import java.io.IOException;
17 |
18 | public class CreatePlayerController {
19 | public JFXTextField txtName;
20 | public JFXButton btnPlay;
21 | public CubicCurve curve;
22 |
23 | public void btnPlayOnAction(ActionEvent actionEvent) throws IOException {
24 | String name = txtName.getText();
25 | if (name.isBlank()){
26 | new DEPAlert(Alert.AlertType.ERROR, "Error", "Empty Name", "Name can't be empty").show();
27 | txtName.requestFocus();
28 | txtName.selectAll();
29 | return;
30 | }else if (!name.matches("[A-Za-z ]+")){
31 | new DEPAlert(Alert.AlertType.WARNING, "Error", "Invalid Name", "Please enter a valid name").show();
32 | txtName.requestFocus();
33 | txtName.selectAll();
34 | return;
35 | }
36 | Stage stage = new Stage();
37 | FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/view/Board.fxml"));
38 | stage.setScene(new Scene(fxmlLoader.load()));
39 | ((BoardController)(fxmlLoader.getController())).initData(name);
40 | stage.setResizable(false);
41 | stage.setTitle("Connect 4 Game - Player: " + name);
42 | stage.show();
43 | stage.centerOnScreen();
44 | // stage.setOnCloseRequest(Event::consume);
45 | btnPlay.getScene().getWindow().hide();
46 | Platform.runLater(stage::sizeToScene);
47 | }
48 |
49 | public void rootOnMouseExited(MouseEvent mouseEvent) {
50 | curve.setControlX2(451.8468017578125);
51 | curve.setControlY2(-36);
52 | }
53 |
54 | public void rootOnMouseMove(MouseEvent mouseEvent) {
55 | curve.setControlX2(mouseEvent.getX());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
The Connect-4 Game Assignment
2 | In this assignment, you will implement the complete logic behind the "Connect 4 Game" including the artificial Intelligence part of the computer player.
3 | Please read the assignment carefully before proceeding. You can find the assignment [here](https://drive.google.com/file/d/1qlqLBfI3Xu0p_BXRNbRneMWtyLlakXGp/view?usp=sharing).
4 | In case if you have any doubts regarding the assignment please make sure to clarify them upfront.
5 |
6 | ### How to use this repo
7 | * `git clone https://github.com/Ranjith-Suranga/connect-four-game-assignment.git`
8 | * Open the `pom.xml` via IntelliJ IDEA
9 | * Make sure to the open it as a project, if prompt
10 | * Reload the `pom.xml` file via **Maven Tool Window**
11 | * Create a run configuration for Maven via `Run > Edit Configuration`
12 | * Add `javafx:run` as the `Run` command
13 | * That's it.
14 | * **But do not try to run or compile the application yet**
15 | * **Follow the instructions in the assignment**
16 |
17 | ### FAQ
18 |
19 | **Q: Can I delete the `.gitkeep` file in `lk.ijse.dep.service` package?**
20 | Yes, you can
21 |
22 | **Q: Why can't I run any games that are in the release page?**
23 | Open a terminal window and type `java -version` to find out the java version. You should have JDK 11 installed on your system to run these games. If you have JDK 11 installed on your system and still unable to run the games, then seek your course instructor's help to get it work.
24 |
25 | **Q: I have found some broken links and spelling mistakes in the assignment. How can I inform?**
26 | Please open a [new issue](https://github.com/Ranjith-Suranga/connect-four-game-assignment/issues/new) mentioning the broken link or spelling mistake. Thank you for informing!
27 |
28 | **Q: I have doubts to clarify regarding the assignment, what should I do?**
29 | Please contact your course instructor 😉
30 |
31 | ### Game
32 | If you want to find out how the game looks like at the end of each step, check out the [release page](https://github.com/Ranjith-Suranga/connect-four-game-assignment/releases) and follow the instructions there.
33 |
34 | ### Version
35 | 0.0.5
36 |
37 | ### License
38 | Copyright © 2022 DEP. All rights reserved
39 | This project is licensed under the [MIT](LICENSE.txt) License.
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | lk.ijse.dep
8 | connect-four-assignment
9 | 0.1.0
10 |
11 |
12 | 11
13 | 11
14 |
15 |
16 |
17 |
18 | org.openjfx
19 | javafx-fxml
20 | 18.0.2
21 |
22 |
23 |
24 | com.jfoenix
25 | jfoenix
26 | 9.0.1
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.apache.maven.plugins
34 | maven-compiler-plugin
35 | 3.8.1
36 |
37 | 11
38 |
39 |
40 |
41 | org.openjfx
42 | javafx-maven-plugin
43 | 0.0.8
44 |
45 | lk.ijse.dep.AppInitializer
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-shade-plugin
51 | 3.2.0
52 |
53 |
54 | package
55 |
56 | shade
57 |
58 |
59 | true
60 | project-classifier
61 | shade\${project.artifactId}.jar
62 |
63 |
65 | lk.ijse.dep.Launcher
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/BoardImpl.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | public class BoardImpl implements Board {
4 | Piece winningPiece = Piece.EMPTY;
5 | int col1, col2, row1, row2;
6 | private final Piece[][] pices;
7 | private final BoardUi boardController;
8 | public BoardImpl(BoardUi boardController) {
9 | pices = new Piece[NUM_OF_COLS][NUM_OF_ROWS];
10 | this.boardController = boardController;
11 |
12 | for (int i = 0; i < NUM_OF_COLS; i++) {
13 | for (int j = 0; j < NUM_OF_ROWS; j++) {
14 | pices[i][j] = Piece.EMPTY;
15 | }
16 | }
17 | }
18 | @Override
19 | public BoardUi getBoardUi() {
20 | return boardController;
21 | }
22 |
23 | @Override
24 | public int findNextAvailableSpot(int col) {
25 | int temp = -1;
26 | for (int i = 0; i < NUM_OF_ROWS; i++) {
27 | if (pices[col][i] == Piece.EMPTY) {
28 | temp = i;
29 | break;
30 | }
31 | }
32 | return temp;
33 | }
34 | @Override
35 | public boolean isLegalMoves(int col) {
36 | int isLegal = findNextAvailableSpot(col);
37 | return isLegal != (-1);
38 | }
39 | @Override
40 | public boolean exitLegalMoves() {
41 | boolean temp = false;
42 | for (int i = 0; i < NUM_OF_COLS; i++) {
43 | for (int j = 0; j < NUM_OF_ROWS; j++) {
44 | if (pices[i][j] == Piece.EMPTY) {
45 | temp = true;
46 | break;
47 | }
48 | }
49 | }
50 | return temp;
51 | }
52 | @Override
53 | public void updateMove(int col, Piece move) {
54 | for (int i = 0; i < NUM_OF_ROWS; i++) {
55 | if (pices[col][i] == Piece.EMPTY) {
56 | pices[col][i] = move;
57 | break;
58 | }
59 | }
60 | }
61 | @Override
62 | public void updateMove(int col, int row, Piece move){
63 | pices[col][row]=move;
64 | }
65 | @Override
66 | public Winner findWinner() {
67 | Piece winningPiece ;
68 |
69 | for (int i = 0; i < NUM_OF_COLS; i++) {
70 | for (int k = 0; k < 2; k++) {
71 | if (pices[i][k] == pices[i][k + 1] && pices[i][k + 1] == pices[i][k + 2] && pices[i][k + 2] == pices[i][k + 3]) {
72 | if(pices[i][k] !=Piece.EMPTY) {
73 | winningPiece = pices[i][k];
74 | col1 = i;
75 | col2 = i;
76 | row1 = k;
77 | row2 = k + 3;
78 | return new Winner(winningPiece, col1, row1, col2, row2);
79 | }
80 | }
81 | }
82 | }
83 | for (int i = 0; i < NUM_OF_ROWS; i++) {
84 | for (int k = 0; k < 3; k++) {
85 | if (pices[k][i] == pices[k + 1][i] && pices[k + 1][i] == pices[k + 2][i] && pices[k + 2][i] == pices[k + 3][i]) {
86 | if(pices[k][i] !=Piece.EMPTY) {
87 | winningPiece = pices[k][i];
88 | col1 = k;
89 | col2 = k + 3;
90 | row1 = i;
91 | row2 = i;
92 | return new Winner(winningPiece, col1, row1, col2, row2);
93 | }
94 | }
95 | }
96 | }
97 | return new Winner(Piece.EMPTY);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/service/AiPlayer.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.service;
2 |
3 | import static java.lang.Math.max;
4 | import static java.lang.Math.min;
5 |
6 | public class AiPlayer extends Player {
7 | Winner winner;
8 | int randomNum;
9 | boolean isTrue;
10 | public AiPlayer(Board newBoard) {
11 | super(newBoard);
12 | }
13 |
14 | @Override
15 | public void movePiece(int col1) {
16 | randomNum = bestMove();
17 | board.updateMove(randomNum, Piece.GREEN);
18 | board.getBoardUi().update(randomNum, isTrue);
19 | winner = board.findWinner();
20 | if (winner.getWinningPiece() != Piece.EMPTY) {
21 | board.getBoardUi().notifyWinner(winner);
22 | } else {
23 | if (!board.exitLegalMoves()) {
24 | board.getBoardUi().notifyWinner(new Winner(Piece.EMPTY));
25 | }
26 | }
27 | }
28 | private int bestMove() {
29 | boolean isUserWinning = false;
30 | int winningCol = 0;
31 | for (int i = 0; i < 6; ++i) {
32 | if (board.isLegalMoves(i)) {
33 | int row = board.findNextAvailableSpot(i);
34 | board.updateMove(i, Piece.GREEN);
35 | int heuristicVal = minimax(0, false);
36 | board.updateMove(i, row, Piece.EMPTY);
37 | if (heuristicVal == 1) {
38 | return i;
39 | } else if (heuristicVal == -1) {
40 | isUserWinning = true;
41 | } else {
42 | winningCol = i;
43 | }
44 | }
45 | }
46 | if (isUserWinning && board.isLegalMoves(winningCol)) {
47 | return winningCol;
48 | } else {
49 | int j;
50 | do {
51 | j = (int) ((Math.random() * ((5 - 0) + 1)) + 0);
52 | } while (!board.isLegalMoves(j));
53 |
54 | return j;
55 | }
56 | }
57 | private int minimax(int depth, boolean maximizingPlayer) {
58 | Winner winner = board.findWinner();
59 | if (winner.getWinningPiece() == Piece.GREEN) {
60 | return 1;
61 | } else if (winner.getWinningPiece() == Piece.BLUE) {//
62 | return -1;
63 | } else if (board.exitLegalMoves() && depth != 5) {
64 | int heuristicVal;
65 | if (!maximizingPlayer) {
66 | int minEva= 1000;
67 | for (int i = 0; i < 6; ++i) {
68 | if (board.isLegalMoves(i)) {
69 | int row = board.findNextAvailableSpot(i);
70 | board.updateMove(i, Piece.BLUE);
71 | heuristicVal = minimax(depth + 1, true);
72 | minEva= min(minEva,heuristicVal);
73 | board.updateMove(i, row, Piece.EMPTY);
74 | if (heuristicVal == -1) {
75 | return minEva;
76 | }
77 | }
78 | }
79 | } else {
80 | int maxEvA = -1000;
81 | for (int i = 0; i < 6; ++i) {
82 | if (board.isLegalMoves(i)) {
83 | int row = board.findNextAvailableSpot(i);
84 | board.updateMove(i, Piece.GREEN);
85 | heuristicVal = minimax(depth + 1, false);
86 | maxEvA = max(maxEvA,heuristicVal);
87 | board.updateMove(i, row, Piece.EMPTY);
88 | if (heuristicVal == 1) {
89 | return maxEvA;
90 | }
91 | }
92 | }
93 | }
94 | return 0;
95 | } else {
96 | return 0;
97 | }
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/target/classes/view/Board.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/src/main/resources/view/Board.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/src/main/java/lk/ijse/dep/controller/BoardController.java:
--------------------------------------------------------------------------------
1 | package lk.ijse.dep.controller;
2 |
3 | import com.jfoenix.controls.JFXButton;
4 | import javafx.animation.KeyFrame;
5 | import javafx.animation.Timeline;
6 | import javafx.animation.TranslateTransition;
7 | import javafx.application.Platform;
8 | import javafx.event.ActionEvent;
9 | import javafx.scene.Group;
10 | import javafx.scene.control.Label;
11 | import javafx.scene.layout.AnchorPane;
12 | import javafx.scene.layout.Pane;
13 | import javafx.scene.layout.VBox;
14 | import javafx.scene.shape.Circle;
15 | import javafx.scene.shape.Rectangle;
16 | import javafx.util.Duration;
17 | import lk.ijse.dep.service.*;
18 |
19 | public class BoardController implements BoardUi{
20 |
21 | private static final int RADIUS = 42;
22 |
23 | public Label lblStatus;
24 | public Group grpCols;
25 | public AnchorPane root;
26 | public Pane pneOver;
27 | public JFXButton btnPlayAgain;
28 |
29 | private String playerName;
30 | private boolean isAiPlaying;
31 | private boolean isGameOver;
32 |
33 | private Player humanPlayer;
34 | private Player aiPlayer;
35 |
36 | private void initializeGame() {
37 | Board newBoard = new BoardImpl(this);
38 | humanPlayer = new HumanPlayer(newBoard);
39 | aiPlayer = new AiPlayer(newBoard);
40 | }
41 |
42 | public void initialize() {
43 | initializeGame();
44 | grpCols.getChildren().stream().map(n -> (VBox) n).forEach(vbox -> vbox.setOnMouseClicked(mouseEvent -> colOnClick(vbox)));
45 | }
46 |
47 | private void colOnClick(VBox col) {
48 | if (!isAiPlaying && !isGameOver) humanPlayer.movePiece(grpCols.getChildren().indexOf(col));
49 | }
50 |
51 | public void initData(String playerName) {
52 | this.playerName = playerName;
53 | }
54 |
55 | @Override
56 | public void update(int col, boolean isHuman) {
57 | if (isGameOver) return;
58 | VBox vCol = (VBox) grpCols.lookup("#col" + col);
59 | if (vCol.getChildren().size() == 5)
60 | throw new RuntimeException("Double check your logic, no space available within the column: " + col);
61 | if (!isHuman) {
62 | vCol.getStyleClass().add("col-ai");
63 | }
64 | Circle circle = new Circle(RADIUS);
65 | circle.getStyleClass().add(isHuman ? "circle-human" : "circle-ai");
66 | vCol.getChildren().add(0, circle);
67 | if (vCol.getChildren().size() == 5) vCol.getStyleClass().add("col-filled");
68 | TranslateTransition tt = new TranslateTransition(Duration.millis(250), circle);
69 | tt.setFromY(-50);
70 | tt.setToY(circle.getLayoutY());
71 | tt.playFromStart();
72 | lblStatus.getStyleClass().clear();
73 | lblStatus.getStyleClass().add(isHuman ? "ai" : "human");
74 | if (isHuman) {
75 | isAiPlaying = true;
76 | grpCols.getChildren().stream().map(n -> (VBox) n).forEach(vbox -> vbox.getStyleClass().remove("col-human"));
77 | KeyFrame delayFrame = new KeyFrame(Duration.millis(300), actionEvent -> {
78 | if (!isGameOver) lblStatus.setText("Wait, AI is playing");
79 | });
80 | KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.5), actionEvent -> {
81 | if (!isGameOver) aiPlayer.movePiece(-1);
82 | });
83 | new Timeline(delayFrame, keyFrame).playFromStart();
84 | } else {
85 | KeyFrame delayFrame = new KeyFrame(Duration.millis(300), actionEvent -> {
86 | grpCols.getChildren().stream().map(n -> (VBox) n).forEach(vbox -> {
87 | vbox.getStyleClass().remove("col-ai");
88 | vbox.getStyleClass().add("col-human");
89 | });
90 | });
91 | new Timeline(delayFrame).playFromStart();
92 | isAiPlaying = false;
93 | lblStatus.setText(playerName + ", it is your turn now!");
94 | }
95 | }
96 |
97 | @Override
98 | public void notifyWinner(Winner winner){
99 | isGameOver = true;
100 | lblStatus.getStyleClass().clear();
101 | lblStatus.getStyleClass().add("final");
102 | switch (winner.getWinningPiece()) {
103 | case BLUE:
104 | lblStatus.setText(String.format("%s, you have won the game !", playerName));
105 | break;
106 | case GREEN:
107 | lblStatus.setText("Game is over, AI has won the game !");
108 | break;
109 | case EMPTY:
110 | lblStatus.setText("Game is tied !");
111 | }
112 | if (winner.getWinningPiece() != Piece.EMPTY) {
113 | VBox vCol = (VBox) grpCols.lookup("#col" + winner.getCol1());
114 | Rectangle rect = new Rectangle((winner.getCol2() - winner.getCol1() + 1) * vCol.getWidth(),
115 | (winner.getRow2() - winner.getRow1() + 1) * (((RADIUS + 2) * 2)));
116 | rect.setId("rectOverlay");
117 | root.getChildren().add(rect);
118 | rect.setLayoutX(vCol.localToScene(0, 0).getX());
119 | rect.setLayoutY(vCol.localToScene(0, 0).getY() + (4 - winner.getRow2()) * ((RADIUS + 2) * 2));
120 | rect.getStyleClass().add("winning-rect");
121 | }
122 | pneOver.setVisible(true);
123 | pneOver.toFront();
124 | Platform.runLater(btnPlayAgain::requestFocus);
125 | }
126 |
127 | public void btnPlayAgainOnAction(ActionEvent actionEvent) {
128 | initializeGame();
129 | isAiPlaying = false;
130 | isGameOver = false;
131 | pneOver.setVisible(false);
132 | lblStatus.getStyleClass().clear();
133 | lblStatus.setText("LET'S PLAY !");
134 | grpCols.getChildren().stream().map(n -> (VBox) n).forEach(vbox -> {
135 | vbox.getChildren().clear();
136 | vbox.getStyleClass().remove("col-ai");
137 | vbox.getStyleClass().remove("col-filled");
138 | vbox.getStyleClass().add("col-human");
139 | });
140 | root.getChildren().remove(root.lookup("#rectOverlay"));
141 | }
142 | }
143 |
--------------------------------------------------------------------------------