<repo_name>napo5/connect4CLI<file_sep>/README.md
# connect4CLI
Java implementation of Connect Four game
<file_sep>/test/com/unicam/cs/pa/player/RandomPlayerTest.java
package com.unicam.cs.pa.player;

import com.unicam.cs.pa.core.Disc;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

class RandomPlayerTest {

    @Test
    void getMove() {
        RandomPlayer  rp = new RandomPlayer("user", Disc.RED);
        assertTrue(rp.getMove()>=1);
        assertTrue(rp.getMove()<=7);
    }


}<file_sep>/src/com/unicam/cs/pa/player/notExistentColumnException.java
package com.unicam.cs.pa.player;

public class notExistentColumnException extends Exception {
    @Override
    public String getMessage() {
        return "The number must be between 1 and 7! Try again.";
    }
}
<file_sep>/src/com/unicam/cs/pa/player/RandomPlayer.java
package com.unicam.cs.pa.player;

import com.unicam.cs.pa.core.Disc;

public class RandomPlayer extends COMPlayer {


    public RandomPlayer(String username, Disc color) {
        super(username, color);
    }

    @Override
    public int getMove() {
        return randomMove();
    }


}
<file_sep>/src/com/unicam/cs/pa/match/COMVsCOM.java
package com.unicam.cs.pa.match;

import com.unicam.cs.pa.core.Disc;
import com.unicam.cs.pa.core.Utils;
import com.unicam.cs.pa.player.COMFactory;
import com.unicam.cs.pa.player.COMPlayer;
import com.unicam.cs.pa.player.Player;

/*
RESPONSABILITÀ : Gestisce una partita tra due giocatori virtuali.

 */
public class COMVsCOM extends Match {

    private boolean fastMode;

    public COMVsCOM(COMPlayer p1, COMPlayer p2) {
        super(p1, p2);
    }

    public COMVsCOM(COMPlayer p1, COMPlayer p2, boolean fastMode) {
        super(p1, p2);
        this.fastMode = true;
    }

    public COMVsCOM() {
        COMFactory comFactory = new COMFactory();
        players[0] = comFactory.createPlayer(Disc.RED);
        Utils.blankLine();
        players[1] = comFactory.createPlayer(Disc.YELLOW);
    }

    @Override
    protected void notifyTurn(Player currentPlayer) {
        if (fastMode) {// does not print
        } else super.notifyTurn(currentPlayer);

    }

    @Override
    protected void updateBoard() {
        if (fastMode) {// does not print
        } else super.updateBoard();

    }

    @Override
    protected void notifyWin(Player winner) {
        super.notifyWin(winner);
        if (fastMode) Utils.printBoard(gameBoard);
    }
}

<file_sep>/src/com/unicam/cs/pa/player/COMFactory.java
package com.unicam.cs.pa.player;

import com.unicam.cs.pa.core.Disc;

import java.util.InputMismatchException;
import java.util.Scanner;
/*
RESPONSABILITÀ : Gestisce l'input utente per creare istanza di COMPlayer desiderata.
 */

public class COMFactory implements PlayerFactory {
    @Override
    public COMPlayer createPlayer(Disc color) {

        printCOMInstructions();
        Scanner comInput = new Scanner(System.in);
        int comType = 0;
        try {
            comType = comInput.nextInt();
        } catch (InputMismatchException ex) {
            System.out.println("Wrong Input! Please try again.");
            return createPlayer(color);
        }


        COMPlayer com = null;

        switch (comType) {
            case 1:
                com = new RandomPlayer("EasyCOM", color);
                break;
            case 2:
                com = new GoofPlayer("GoofCOM", color);
                break;
            case 3:
                com = new SmartPlayer("SmartCOM", color);
                break;

            default:
                System.out.println("Invalid option");
                createPlayer(color);
        }
        return com;

    }

    @Override
    public Player getPlayer() {
        return null;
    }

    private void printCOMInstructions() {
        System.out.println("COM Player setup :");
        System.out.println("Select type of COM player");
        System.out.println("[1] (Easy) Random COM");
        System.out.println("[2] (Medium) Goof COM");
        System.out.println("[3] (Hard) Smart COM");
    }
}
<file_sep>/src/com/unicam/cs/pa/player/SmartPlayer.java
package com.unicam.cs.pa.player;

import com.unicam.cs.pa.core.Disc;

public class SmartPlayer extends COMPlayer {
    public SmartPlayer(String username, Disc color) {
        super(username, color);
    }

    /*

    SmartCOM move checks if there is a row of three discs with same color:
    if he can close a four-in-a-row and win he wins
    if the opponent can close a four-in-a-row he denies it.

*/
    @Override
    public int getMove() {
        return fourthInARow();
    }

    private int fourthInARow() {
        for (int i = 1; i <= 7; i++) {

            if (gameBoardCopy.winCheck(Disc.RED, gameBoardCopy.getColumnCounter(i)+1, i)) {

                return i;
            }
        }

        for (int i = 1; i <= 7; i++) {
            if (gameBoardCopy.winCheck(Disc.YELLOW, gameBoardCopy.getColumnCounter(i)+1, i)) {

                return i;
            }
        }


        // if there are no winning moves
        return randomMove();
    }
}
<file_sep>/src/com/unicam/cs/pa/core/FilledColumnException.java
package com.unicam.cs.pa.core;

public class FilledColumnException extends Exception {
    @Override
    public String getMessage() {
        return "The column selected is full!";
    }
}
<file_sep>/src/com/unicam/cs/pa/match/MatchBuilder.java
package com.unicam.cs.pa.match;

import com.unicam.cs.pa.player.Player;

import java.util.Scanner;

/*
RESPONSABILITÀ : Gestisce l'input utente per creare istanza di Match desiderata.
 */


public class MatchBuilder {

    protected boolean rematch;
    protected Match match;

    public Match getMatch() {
        createNewMatch();
        return match;

    }

    public void playAndRematch() {
        boolean rematch = true;
        while (rematch) {
            getMatch();
            match.executeMatch();
            rematch = askRematch();
        }
    }


    public void createNewMatch() {

        Player[] players = new Player[2];

        printInstructions();
        Scanner matchInput = new Scanner(System.in);
        int matchType = matchInput.nextInt();

        switch (matchType) {
            case 1:
                match = new HumanVsCOM();
                break;
            case 2:
                match = new HumanVsHuman();
                break;
            case 3:
                match = new COMVsCOM();
                break;

            default:
                System.out.println("Invalid option");
                createNewMatch();
        }

    }


    private void printInstructions() {
        System.out.print("Select type of match \n" +
                "[1] 1P vs COM \n" +
                "[2] 1P VS 2P \n" +
                "[3] COM VS COM \n");
    }


    public boolean askRematch() {
        boolean rematch = false;
        System.out.println("Play Again ? (Y/n)");
        Scanner rematchInputSC = new Scanner(System.in);
        char rematchInput = rematchInputSC.next().charAt(0);


        switch (rematchInput) {
            case 'Y':
                rematch = true;
                break;
            case 'N':
                rematch = false;
                System.exit(0);
                break;
            default:
                System.out.println("Wrong Input");
                return askRematch();

        }

        return rematch;

    }

}

<file_sep>/src/com/unicam/cs/pa/core/Main.java
package com.unicam.cs.pa.core;

import com.unicam.cs.pa.match.MatchBuilder;

/*
RESPONSABILITÀ : esecuzione del programma
 */
public class Main {
    public static void main(String[] args) {

        MatchBuilder matchBuilder = new MatchBuilder();
        matchBuilder.playAndRematch();
    }

}
<file_sep>/test/com/unicam/cs/pa/core/GameBoardTest.java
package com.unicam.cs.pa.core;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class GameBoardTest {

    @Test
    void verticalStreak() {
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);

        int streak =  gb.directionCheck(Disc.RED,Direction.DOWN,4,1);
        assertTrue(streak==4);
        assertTrue(gb.winCheck(Disc.RED,4,1));
    }

    @Test
    void verticalWin(){

    }

    @Test
    void horizontalStreak() {
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.RED,2);
        gb.dropDisc(Disc.RED,4);

        int streak =  gb.directionCheck(Disc.RED,Direction.RIGHT,1,1);
        assertTrue(streak==4);
    }

    @Test
    void shouldNotWin() {
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.RED,2);



        assertFalse(gb.winCheck(Disc.RED,1,1));
    }

    @Test
    void horizontalReverseStreak(){
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.RED,2);
        gb.dropDisc(Disc.RED,4);

        int streak =  gb.directionCheck(Disc.RED,Direction.LEFT,1,4);
        assertTrue(streak==4);
    }

    @Test
    void diagonalStreak() {
        GameBoard gb = new GameBoard();

        gb.dropDisc(Disc.YELLOW,1);
        gb.dropDisc(Disc.RED,2);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.RED,4);

        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.YELLOW,2);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.RED,4);

        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,2);
        gb.dropDisc(Disc.YELLOW,3);
        gb.dropDisc(Disc.RED,4);

        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,2);
        gb.dropDisc(Disc.RED,3);
        gb.dropDisc(Disc.YELLOW,4);

        int streak =  gb.directionCheck(Disc.YELLOW,Direction.UPRIGHT,1,1);
        assertTrue(streak==4);
        assertTrue(gb.winCheck(Disc.YELLOW,2,2));
    }

    @Test
    void latestDisc(){
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.YELLOW,1);

        assertTrue(gb.getLatestDisc()==Disc.YELLOW);
        assertTrue(gb.getLatestDiscCol()==1);
        assertTrue(gb.getLatestDiscRow()==1);
    }

    @Test
    void isLegit(){
        GameBoard gb = new GameBoard();
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);
        gb.dropDisc(Disc.RED,1);

        assertFalse(gb.isLegit(1));
        assertFalse(gb.isLegit(0));
        assertFalse(gb.isLegit(9));
    }

    @Test
    void isDraw() {
        GameBoard gb = new GameBoard();
        for (int i = 1; i <= 6; i++) {

            gb.dropDisc(Disc.RED, 1);
            gb.dropDisc(Disc.RED, 2);
            gb.dropDisc(Disc.RED, 3);
            gb.dropDisc(Disc.RED, 4);
            gb.dropDisc(Disc.RED, 5);
            gb.dropDisc(Disc.RED, 6);
            gb.dropDisc(Disc.RED, 7);
        }

        assertTrue(gb.isDraw());
    }
}<file_sep>/src/com/unicam/cs/pa/player/COMPlayer.java
package com.unicam.cs.pa.player;

import com.unicam.cs.pa.core.Disc;

import java.util.Random;
/*
RESPONSABILITÀ : Rappresenta giocatore artificiale.
 */

public abstract class COMPlayer extends Player {

    public COMPlayer(String username, Disc color) {
        super(username, color);
    }

    /**
     * @return integer between 1 and 7
     * useful for returning a random column number
     */

    protected int randomMove() {

        int move = new Random().nextInt(7) + 1;
        while (!gameBoardCopy.isLegit(move))
            move = new Random().nextInt(7) + 1;
        return move;
    }

}
<file_sep>/src/com/unicam/cs/pa/match/HumanVsCOM.java
package com.unicam.cs.pa.match;

import com.unicam.cs.pa.core.Disc;
import com.unicam.cs.pa.core.Utils;
import com.unicam.cs.pa.player.COMFactory;
import com.unicam.cs.pa.player.COMPlayer;
import com.unicam.cs.pa.player.HumanPlayer;
import com.unicam.cs.pa.player.Player;
/*
RESPONSABILITÀ : Gestisce una partita tra utente e giocatore artificiale.
 */

public class HumanVsCOM extends Match {

    public HumanVsCOM(HumanPlayer p1, COMPlayer p2) {
        super(p1, p2);
    }

    public HumanVsCOM() {
        players[0] = new HumanPlayer(Disc.RED);
        Utils.blankLine();
        COMFactory comFactory = new COMFactory();
        players[1] = comFactory.createPlayer(Disc.YELLOW);
    }

    @Override
    public void randomStart() {
        super.randomStart();
        System.out.println(currentPlayer.getUsername() + " starting!");
    }


    @Override
    protected void notifyWin(Player winner) {
        if (winner.equals(players[0]))
            System.out.println("You WIN! ");
        else System.out.println("You LOSE! ");
    }
}
