Skip to content
Snippets Groups Projects
Commit b418ca5a authored by KOUWENHOVEN Luca's avatar KOUWENHOVEN Luca
Browse files

Initial commit, project and tests

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 602 additions and 0 deletions
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34322.80
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Connect-X", "Connect-X\Connect-X.csproj", "{0BED3B50-8F72-4B8F-8C28-27B026516E1B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Connect-XTests", "Connect-XTests\Connect-XTests.csproj", "{5949CD00-0BB6-415C-A2DC-FDAD8CC6FCEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0BED3B50-8F72-4B8F-8C28-27B026516E1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BED3B50-8F72-4B8F-8C28-27B026516E1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BED3B50-8F72-4B8F-8C28-27B026516E1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BED3B50-8F72-4B8F-8C28-27B026516E1B}.Release|Any CPU.Build.0 = Release|Any CPU
{5949CD00-0BB6-415C-A2DC-FDAD8CC6FCEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5949CD00-0BB6-415C-A2DC-FDAD8CC6FCEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5949CD00-0BB6-415C-A2DC-FDAD8CC6FCEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5949CD00-0BB6-415C-A2DC-FDAD8CC6FCEA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6382B662-8521-4E47-A1D1-63E6E30AF760}
EndGlobalSection
EndGlobal
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Connect_X
{
public class Column
{
private List<String> column;
private int iLastToken; // index of last token in column
public bool isFull = false;
public Column(int h)
{
iLastToken = -1;
column = new List<String>(h);
for (int i = 0; i < h; i++)
{
column.Add("O");
}
}
public void reverse() // We reverse only the token already in place not the whole list, avoids calculating gravity again.
{
if (iLastToken >= 1)
{
for (int i = 0; i <= iLastToken/2; i++)
{
string temp = column[iLastToken-i];
column[iLastToken - i] = column[i];
column[i] = temp;
}
}
}
public int getILastToken()
{ return iLastToken; }
public List<String> getColumn()
{
return column;
}
private String getValue(int index)
{
return column[index];
}
private void setValue(int index, string value)
{
column[index] = value;
}
public String this [int index]
{
get => getValue(index);
set => setValue(index, value);
}
public void dropToken(String token)
{
column[iLastToken + 1] = token;
iLastToken++;
if (iLastToken == column.Count-1)
isFull = true;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Connect_X</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Connect_X
{
public class Game
{
// Data member
private List<Column> myBoard; // Game board ( width by height )
private int myWidth, myHeight, myX; // X is the number of token to align in order to win
private bool bPlayerTurn = false;
private bool isFilled = false;
private bool isReverseActive;
public Game(bool mode, int[] param)
{
isReverseActive = mode;
myWidth = param[0];
myHeight = param[1];
myX = param[2];
myBoard = new List<Column>();
for (int i = 0; i < myWidth; i++)
{
myBoard.Add(new Column(myHeight));
}
}
public int getWidth()
{ return myWidth; }
public int getHeight()
{ return myHeight; }
public int getX()
{ return myX; }
public bool getIsReverseActive()
{ return isReverseActive; }
public List<Column> getBoard()
{ return myBoard;}
public void play()
{
Console.Clear();
int isDone = 0;
while (isDone == 0)
{
printBoard();
Console.WriteLine("Player " + (bPlayerTurn ? 2 : 1) + ", in which column do you wish to play [0-" + (myWidth-1) + "] >");
if (!int.TryParse(Console.ReadLine(), out int index))
Console.WriteLine("Please enter a valid input, a number between 0 and " + (myWidth-1));
else if (index < 0 || index >= myWidth)
Console.WriteLine("Input is not within correct range, a number between 0 and " + (myWidth-1));
else if (myBoard[index].isFull)
Console.WriteLine("This column is already full, please select another column");
else
{
playToken(index, bPlayerTurn);
if (isReverseActive)
doReverse();
isDone = checkBoardWin();
}
Console.Clear();
}
printBoard();
printGameResult(isDone);
}
private void doReverse()
{
bool isInputValid = false;
do
{
printBoard();
Console.WriteLine("Player " + (bPlayerTurn ? 1 : 2) + ", which column do you wish to reverse [0-" + (myWidth-1) + "] >");
if (!int.TryParse(Console.ReadLine(), out int index))
Console.WriteLine("Please enter a valid input, a number between 0 and " + (myWidth-1));
else if (index < 0 || index >= myWidth)
Console.WriteLine("Input is not within correct range, a number between 0 and " + (myWidth-1));
else
{
myBoard[index].reverse();
isInputValid = true;
}
} while (!isInputValid);
}
private void printGameResult(int isDone)
{
switch (isDone)
{
case 1:
Console.WriteLine("Player 1 won !");
break;
case 2:
Console.WriteLine("Player 2 won !");
break;
case 3:
Console.WriteLine("Both Player won !");
break;
default: // Default case appear when isDone = 4 meaning tie because board is full
Console.WriteLine("Nobody won !");
break;
}
}
private int checkBoardWin()
{
bool wPlayer1 = false;
bool wPlayer2 = false;
//Check horizontal row
for (int i = 0; i < myWidth - myX + 1 && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight && !(wPlayer1 && wPlayer2); j++)
{
bool checkRow = myBoard[i][j] != "O";
for (int k = 0; k < myX; k++)
if (myBoard[i][j] != myBoard[i + k][j])
{
checkRow = false;
break;
}
if (checkRow)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
//Check vertical row
for (int i = 0; i < myWidth && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight - myX + 1 && !(wPlayer1 && wPlayer2); j++)
{
bool checkRow = myBoard[i][j] != "O";
for (int k = 0; k < myX; k++)
if (myBoard[i][j] != myBoard[i][j + k])
{
checkRow = false;
break;
}
if (checkRow)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
//Check diagonal row
for (int i = 0; i < myWidth - myX + 1 && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight && !(wPlayer1 && wPlayer2); j++)
{
bool checkUpDiagonal = (myBoard[i][j] != "O") && ((j + myX) <= myHeight); // No upward diagonal after height - X
bool checkDownDiagonal = (myBoard[i][j] != "O") && ((j - myX) >= -1); // No downward diagonal before 0 + X - 1
for (int k = 0; k < myX; k++)
{
if (checkUpDiagonal) // If we can search for an upward diagonal we try, this avoids using indexes out of our board range.
if (myBoard[i][j] != myBoard[i + k][j + k])
checkUpDiagonal = false;
if (checkDownDiagonal) // If we can search for an downward diagonal we try, this avoids using indexes out of our board range.
if (myBoard[i][j] != myBoard[i + k][j - k])
checkDownDiagonal = false;
}
if (checkUpDiagonal || checkDownDiagonal)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
if (wPlayer1 && wPlayer2) // Both players won
return 3;
else if (wPlayer1) // Only player 1 won
return 1;
else if (wPlayer2) // Only player 2 won
return 2;
else if (isFilled) // No player won but board is full
return 4;
else // No player won and board is not full yet
return 0;
}
private void playToken(int index, bool player)
{
myBoard[index].dropToken(player ? "R" : "Y");
bPlayerTurn = !player;
if(checkIfAllColumnFull())
isFilled = true;
}
// Check if every column is full
private bool checkIfAllColumnFull()
{
bool full = true;
for (int i = 0; i < myWidth; i++)
if (!myBoard[i].isFull)
full = false;
return full;
}
// Prints the gameBoard in console
private void printBoard()
{
ConsoleColor currentBackGroundColor = Console.BackgroundColor;
for (int i = myHeight-1; i > -1; --i)
{
Console.Write("|");
foreach (Column col in myBoard)
{
Console.Write(" ");
if (col[i] == "Y")
Console.BackgroundColor = ConsoleColor.Yellow;
else if (col[i] == "R")
Console.BackgroundColor = ConsoleColor.Red;
Console.Write(" ");
Console.BackgroundColor = currentBackGroundColor;
Console.Write(" |");
}
Console.Write(Environment.NewLine);
}
string columnStr = " ";
for (int i = 0; i < myWidth; i++)
columnStr += " " + i + " ";
Console.WriteLine(columnStr + Environment.NewLine); // Only for better visibility while playing
}
}
}
// See https://aka.ms/new-console-template for more information
using Connect_X;
public class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Welcome to Connect-X !");
Console.WriteLine("This game is based on the famous Connect 4." + Environment.NewLine);
Console.WriteLine("----- RULES -----" + Environment.NewLine);
Console.WriteLine("- Each player takes turn playing.");
Console.WriteLine("- Each turn the token drop to the lowest possible place in the chosen column.");
Console.WriteLine("- First player to align X token in a row win (horizontal, vertical and diagonal rows).");
Console.WriteLine("- If the board is filled without a winner it is a tie" + Environment.NewLine);
int gameMode = 0;
while (gameMode == 0)
gameMode = getGameMode();
int[] parameters = [7, 6, 4];
if (gameMode == 3 || gameMode == 4)
parameters = getGameParameters();
Game game = new Game(gameMode % 2 == 0,parameters); // If gameMode equal 2 or 4, reverse is active and 2 or 4 % 2 equal zero meaning we activate reverse.
game.play();
}
private static int getGameMode()
{
// Ask the user to choose a gamemode.
Console.WriteLine("Choose a gameMode from the following list:");
Console.WriteLine("a - Default connect-4");
Console.WriteLine("b - Default connect-4 with column reverse");
Console.WriteLine("c - Connect-X, you choose width and height of the board and number of token to align to win");
Console.WriteLine("d - Connect-X with reverse");
Console.Write("Your option? ");
// Use a switch statement to do the math.
switch (Console.ReadLine())
{
case "a":
return 1;
case "b":
return 2;
case "c":
return 3;
case "d":
return 4;
default:
Console.WriteLine("Input is invalid, select of the given option");
return 0;
}
}
private static int getInt(string message, int lowBorder, int highBorder)
{
bool isIntNotValid = true;
int i;
do
{
Console.Write(message);
if (!int.TryParse(Console.ReadLine(), out i))
Console.WriteLine("Input is not valid, input must be an integer");
else if (i < lowBorder || i > highBorder)
Console.WriteLine("Input is not valid, input must be between " + lowBorder + " and " + highBorder);
else
isIntNotValid = false;
} while (isIntNotValid);
return i;
}
private static int[] getGameParameters()
{
int[] parameters = new int[3];
parameters[0] = getInt("Enter width of the gameboard [5-20] >", 5, 20);
parameters[1] = getInt("Enter height of the gameboard [5-20] >", 5, 20);
parameters[2] = getInt("Enter number of token to align to win [3-" + (parameters[0] < parameters[1] ? parameters[0] : parameters[1]) + "] >", 3, (parameters[0] < parameters[1] ? parameters[0] : parameters[1]));
return parameters;
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Class only to test Winning conditions of gameBoard
namespace Connect_X
{
public class WinEngine
{
public List<List<String>> myBoard;
public int myWidth, myHeight, myX;
public bool isFilled;
public WinEngine(List<List<String>> board, int X, bool full)
{
myBoard = board;
myWidth = myBoard.Count;
myHeight = myBoard[0].Count;
myX = X;
isFilled = full;
}
public int checkBoardWin()
{
bool wPlayer1 = false;
bool wPlayer2 = false;
//Check horizontal row
for (int i = 0; i < myWidth - myX + 1 && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight && !(wPlayer1 && wPlayer2); j++)
{
bool checkRow = myBoard[i][j] != "O";
for (int k = 0; k < myX; k++)
if (myBoard[i][j] != myBoard[i + k][j])
{
checkRow = false;
break;
}
if (checkRow)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
//Check vertical row
for (int i = 0; i < myWidth && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight - myX + 1 && !(wPlayer1 && wPlayer2); j++)
{
bool checkRow = myBoard[i][j] != "O";
for (int k = 0; k < myX; k++)
if (myBoard[i][j] != myBoard[i][j + k])
{
checkRow = false;
break;
}
if (checkRow)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
//Check diagonal row
for (int i = 0; i < myWidth - myX + 1 && !(wPlayer1 && wPlayer2); i++)
{
for (int j = 0; j < myHeight && !(wPlayer1 && wPlayer2); j++)
{
bool checkUpDiagonal = (myBoard[i][j] != "O") && ((j + myX) <= myHeight); // No upward diagonal after height - X
bool checkDownDiagonal = (myBoard[i][j] != "O") && ((j - myX) >= -1); // No downward diagonal before 0 + X - 1
for (int k = 0; k < myX; k++)
{
if (checkUpDiagonal) // If we can search for an upward diagonal we try, this avoids using indexes out of our board range.
if (myBoard[i][j] != myBoard[i + k][j + k])
checkUpDiagonal = false;
if (checkDownDiagonal) // If we can search for an downward diagonal we try, this avoids using indexes out of our board range.
if (myBoard[i][j] != myBoard[i + k][j - k])
checkDownDiagonal = false;
}
if (checkUpDiagonal || checkDownDiagonal)
{
if (myBoard[i][j] == "Y")
wPlayer1 = true;
else
wPlayer2 = true;
}
}
}
if (wPlayer1 && wPlayer2) // Both players won
return 3;
else if (wPlayer1) // Only player 1 won
return 1;
else if (wPlayer2) // Only player 2 won
return 2;
else if (isFilled) // No player won but board is full
return 4;
else // No player won and board is not full yet
return 0;
}
}
}
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v8.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v8.0": {
"Connect-X/1.0.0": {
"runtime": {
"Connect-X.dll": {}
}
}
}
},
"libraries": {
"Connect-X/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}
\ No newline at end of file
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment