Skip to content

Instantly share code, notes, and snippets.

@afonsomatos
Created July 2, 2016 23:37
Show Gist options
  • Save afonsomatos/64432b9170b0304fbaf21919007e1c17 to your computer and use it in GitHub Desktop.
Save afonsomatos/64432b9170b0304fbaf21919007e1c17 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConnectFour
{
enum Tile { Empty, X, O };
class Game
{
public Tile[][] Board { get; set; }
private int Cols { get; }
private int Rows { get; }
public Game(int rows, int cols)
{
// Create Board
this.Board = new Tile[rows]
.Select(_ => new Tile[cols])
.ToArray();
this.Cols = cols;
this.Rows = rows;
}
public Tile[][] GetRightDiagonals(Tile[][] board)
{
Tile[][] diagonals = new Tile[this.Cols + this.Rows - 1][];
int i = 0;
for (int colStart = this.Cols - 1; colStart >= 0; --colStart, ++i)
{
Tile[] dia = new Tile[Math.Min(this.Cols - colStart, this.Rows)];
for (int col = colStart, row = 0; col < this.Cols && row < this.Rows; ++col, ++row)
{
dia[row] = board[row][col];
}
diagonals[i] = dia;
}
// Reach left edge and start going down
for (int rowStart = 1; rowStart < this.Rows; ++rowStart, ++i)
{
Tile[] dia = new Tile[this.Rows - rowStart];
for (int row = rowStart, col = 0; row < this.Rows; ++row, ++col)
{
dia[col] = board[row][col];
}
diagonals[i] = dia;
}
return diagonals;
}
// For the sake of consistency
private Tile[] GetRow(int rowIndex) => this.Board[rowIndex];
private Tile[] GetCol(int colIndex)
{
Tile[] col = new Tile[this.Rows];
for (int i = 0; i < col.Length; ++i)
col[i] = GetRow(i)[colIndex];
return col;
}
public Tile? Winner()
{
// Check horizontal repetition
for (int i = 0; i < this.Rows; ++i)
{
Tile[] row = GetRow(i);
if (row.Repeats<Tile>(Tile.X, 4)) return Tile.X;
if (row.Repeats<Tile>(Tile.O, 4)) return Tile.O;
}
// Check vertical repetition
for (int i = 0; i < this.Cols; ++i)
{
Tile[] col = GetCol(i);
if (col.Repeats<Tile>(Tile.X, 4)) return Tile.X;
if (col.Repeats<Tile>(Tile.O, 4)) return Tile.O;
}
// Check diagonal repetition
Tile[][] rightDiagonals = GetRightDiagonals(this.Board).Where(a => a.Length >= 4).ToArray();
Tile[][] leftDiagonals = GetRightDiagonals(this.Board.Select(a => a.Reverse().ToArray()).ToArray());
foreach (Tile[] dia in rightDiagonals)
{
if (dia.Repeats<Tile>(Tile.X, 4)) return Tile.X;
if (dia.Repeats<Tile>(Tile.O, 4)) return Tile.O;
}
foreach(Tile[] dia in leftDiagonals)
{
if (dia.Repeats<Tile>(Tile.X, 4)) return Tile.X;
if (dia.Repeats<Tile>(Tile.O, 4)) return Tile.O;
}
return null;
}
public void Move(Tile playerTile, int col)
{
// Check invalid tile
if (playerTile == Tile.Empty)
throw new ArgumentException("An empty tile can't make a move.");
// Check if out of range
if (col < 1 || col > 7)
throw new ArgumentOutOfRangeException($"Column must be between 1 and {this.Cols}.");
int colIndex = col - 1;
// Check if column is full
int numberOfTiles = 0;
int rowIndex = this.Rows - 1;
while (rowIndex >= 0)
{
if (this.Board[rowIndex][colIndex] == Tile.Empty) break;
rowIndex--;
numberOfTiles++;
}
if (numberOfTiles == this.Rows)
throw new ArgumentException($"Column {col} is full.");
// Place the tile
this.Board[rowIndex][colIndex] = playerTile;
}
public char ShowTile(Tile t)
{
if (t == Tile.O) return 'O';
if (t == Tile.X) return 'X';
return '.';
}
public string ShowGameGrid()
{
string grid = "";
foreach (Tile[] row in this.Board)
grid += string.Join(" ", row.Select(x => ShowTile(x))) + "\n";
return grid;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConnectFour
{
static class ExtensionMethods
{
public static bool Repeats<T>(this IEnumerable<T> sequence, T item, int times)
{
int timesRepeated = 0;
foreach (T value in sequence)
{
if (value.Equals(item))
{
if (++timesRepeated == times) return true;
}
else timesRepeated = 0;
}
return false;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to ConnectFour!");
Game game = new Game(6, 7);
// Choose starting player
Random rand = new Random();
Tile player = rand.Next(0, 2) == 1 ? Tile.X : Tile.O;
Tile? winner = null;
do
{
Console.WriteLine(game.ShowGameGrid());
Console.Write($"Player {game.ShowTile(player)}, choose column: ");
string input = Console.ReadLine();
int col = Convert.ToInt32(input);
try
{
game.Move(player, col);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
continue;
}
winner = game.Winner();
// Change players' turns
player = player == Tile.X ? Tile.O : Tile.X;
} while (winner == null);
Console.WriteLine($"Player {game.ShowTile(winner.Value)} won!");
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment