using System;
using System.Collections.Generic;
using System.Text;
namespace Calcoolation.Core
{
/// <summary>
/// Represents the game board. Provides funcionalities for random generation for: numbers, cages and operations
/// </summary>
public class Board
{
#region attributes
int currentOperation = 0;
int size = 0;
Cell[,] matrix = null;
List<Cage> cages = new List<Cage>();
static Board instance;
#endregion attributes
#region constructor
private Board()
{
currentOperation = (DateTime.Now.Millisecond % 4) + 1;
}
#endregion constructor
#region properties
public static Board Instance
{
get
{
if (instance == null)
instance = new Board();
return instance;
}
}
#endregion properties
#region methods
public void GenerateBoard(int size)
{
this.size = size;
this.matrix = new Cell[size, size];
ResetBoard();
GenerateNumbers();
GenerateCages();
}
public void PickOperation(Cage cage)
{
bool success = false;
while (!success)
{
if (currentOperation == 5)
currentOperation = 1;
switch (currentOperation)
{
case 1:
cage.Operation = Operations.Plus;
int sum = 0;
foreach (Cell cell in cage.CellList)
{
sum += Convert.ToInt32(cell.CellValue);
}
cage.Result = sum;
success = true;
break;
case 2:
cage.Operation = Operations.Minus;
if (cage.CellList.Count == 2)
{
int sub = Convert.ToInt32(cage.CellList[0].CellValue) - Convert.ToInt32(cage.CellList[1].CellValue);
if (sub > 0)
{
cage.Result = sub;
success = true;
}
else
{
sub = Convert.ToInt32(cage.CellList[1].CellValue) - Convert.ToInt32(cage.CellList[0].CellValue);
if (sub > 0)
{
cage.Result = sub;
success = true;
}
}
}
break;
case 3:
cage.Operation = Operations.Multiply;
int mult = 1;
foreach (Cell cell in cage.CellList)
{
mult *= Convert.ToInt32(cell.CellValue);
}
cage.Result = mult;
success = true;
break;
case 4:
cage.Operation = Operations.Divide;
if (cage.CellList.Count == 2)
{
int quo = Convert.ToInt32(cage.CellList[0].CellValue) / Convert.ToInt32(cage.CellList[1].CellValue);
int rem = Convert.ToInt32(cage.CellList[0].CellValue) - quo * Convert.ToInt32(cage.CellList[1].CellValue);
if (rem == 0)
{
cage.Result = quo;
success = true;
}
else
{
quo = Convert.ToInt32(cage.CellList[1].CellValue) / Convert.ToInt32(cage.CellList[0].CellValue);
rem = Convert.ToInt32(cage.CellList[1].CellValue) - quo * Convert.ToInt32(cage.CellList[0].CellValue);
if (rem == 0)
{
cage.Result = quo;
success = true;
}
}
}
break;
}
currentOperation++;
}
}
public bool TestResult()
{
bool success = true;
string testString = "";
for (int i = 1; i <= size; i++)
{
testString += i.ToString();
}
List<int> userList = new List<int>();
string userString = "";
//Testing row numbers
for (int row = 0; row < size; row++)
{
userList = new List<int>();
userString = "";
for (int column = 0; column < size; column++)
userList.Add(matrix[column, row].UserValue);
userList.Sort();
for (int i = 0; i < size; i++)
userString += userList[i].ToString();
success = success && userString.Equals(testString);
}
//Testing column numbers
for (int column = 0; column < size; column++)
{
userList = new List<int>();
userString = "";
for (int row = 0; row < size; row++)
userList.Add(matrix[column, row].UserValue);
userList.Sort();
for (int i = 0; i < size; i++)
userString += userList[i].ToString();
success = success && userString.Equals(testString);
}
//Testing each cage
foreach (Cage cage in cages)
{
success = success && cage.TestResult();
}
return success;
}
private void GenerateNumbers()
{
ResetBoard();
Random rnd = new Random();
string number = "0";
int minSize = size;
int maxSize = 0;
bool someSolved = true;
while (someSolved)
{
someSolved = false;
//Search for naked pairs in rows
if (!someSolved)
{
for (int row = 0; row < size; row++)
{
string nakedPairValue = "";
Point nakedPair1 = new Point(0,0);
Point nakedPair2 = new Point(0, 0);
int nakedPairCount = 0;
for (int column = 0; column < size - 1; column++)
{
//if (matrix[column, row].CellValidValues.Length == 2)
if (matrix[column, row].CellValidValues.Length == 2)
{
nakedPair1 = new Point(column, row);
nakedPairValue = matrix[column, row].CellValidValues;
nakedPairCount = 1;
for (int c = column + 1; c < size; c++)
{
if (matrix[c, row].CellValidValues.Length == 2 && matrix[c, row].CellValidValues == nakedPairValue && c != column)
{
nakedPair2 = new Point(c, row);
nakedPairCount++;
}
}
//2 naked pairs found?
if (nakedPairCount == 2)
{
//remove naked pairs values from the other cells in the same row
for (int c = 0; c < size; c++)
{
if (c != nakedPair1.X && c != nakedPair2.X && matrix[c, row].CellValidValues.Length > 1)
{
if (matrix[c, row].CellValidValues.Contains(nakedPairValue[0].ToString()))
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(nakedPairValue[0].ToString(), "");
}
if (matrix[c, row].CellValidValues.Contains(nakedPairValue[1].ToString()))
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(nakedPairValue[1].ToString(), "");
}
}
}
}
}
}
}
}
//Search for naked pairs in columns
if (!someSolved)
{
for (int column = 0; column < size; column++)
{
string nakedPairValue = "";
Point nakedPair1 = new Point(0, 0);
Point nakedPair2 = new Point(0, 0);
int nakedPairCount = 0;
for (int row = 0; row < size - 1; row++)
{
if (matrix[column, row].CellValidValues.Length == 2)
{
nakedPair1 = new Point(column, row);
nakedPairValue = matrix[column, row].CellValidValues;
nakedPairCount = 1;
for (int r = row + 1; r < size; r++)
{
if (matrix[column, r].CellValidValues.Length == 2 && matrix[column, r].CellValidValues == nakedPairValue && r != row)
{
nakedPair2 = new Point(column, r);
nakedPairCount++;
}
}
//2 naked pairs found?
if (nakedPairCount == 2)
{
//remove naked pairs values from the other cells in the same column
for (int r = 0; r < size; r++)
{
if (r != nakedPair1.Y && r != nakedPair2.Y && matrix[column, r].CellValidValues.Length > 1)
{
if (matrix[column, r].CellValidValues.Contains(nakedPairValue[0].ToString()))
{
matrix[column, r].CellValidValues = matrix[column, r].CellValidValues.Replace(nakedPairValue[0].ToString(), "");
}
if (matrix[column, r].CellValidValues.Contains(nakedPairValue[1].ToString()))
{
matrix[column, r].CellValidValues = matrix[column, r].CellValidValues.Replace(nakedPairValue[1].ToString(), "");
}
}
}
}
}
}
}
}
//Search for naked triplets in rows
for (int row = 0; row < size; row++)
{
string nakedTripletValue = "";
Point nakedTriplet1 = new Point(0, 0);
Point nakedTriplet2 = new Point(0, 0);
Point nakedTriplet3 = new Point(0, 0);
int nakedTripletCount = 0;
for (int column = 0; column < size - 1; column++)
{
if (matrix[column, row].CellValidValues.Length == 3)
{
nakedTriplet1 = new Point(column, row);
nakedTriplet2 = new Point(0, 0);
nakedTriplet3 = new Point(0, 0);
nakedTripletValue = matrix[column, row].CellValidValues;
char char1 = nakedTripletValue[0];
char char2 = nakedTripletValue[1];
char char3 = nakedTripletValue[2];
nakedTripletCount = 1;
for (int c = 0; c < size; c++)
{
if (matrix[c, row].CellValidValues.Length > 1 &&
(
matrix[c, row].CellValidValues == (char1.ToString() + char2.ToString() + char3.ToString()) ||
matrix[c, row].CellValidValues == (char1.ToString() + char2.ToString()) ||
matrix[c, row].CellValidValues == (char1.ToString() + char3.ToString()) ||
matrix[c, row].CellValidValues == (char2.ToString() + char3.ToString())
)
&& c != nakedTriplet1.X && c != nakedTriplet2.X && c != nakedTriplet3.X)
{
if (nakedTriplet2.X == 0)
nakedTriplet2 = new Point(c, row);
else
nakedTriplet3 = new Point(c, row);
nakedTripletCount++;
}
}
//3 naked Triplets found?
if (nakedTripletCount == 3)
{
//remove naked Triplets values from the other cells in the same row
for (int c = 0; c < size; c++)
{
if (c != nakedTriplet1.X && c != nakedTriplet2.X && c != nakedTriplet3.X)
{
if (matrix[c, row].CellValidValues.Contains(char1.ToString()))
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(char1.ToString(), "");
}
if (matrix[c, row].CellValidValues.Contains(char2.ToString()))
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(char2.ToString(), "");
}
if (matrix[c, row].CellValidValues.Contains(char3.ToString()))
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(char3.ToString(), "");
}
}
}
}
}
}
}
//Search for cells with a unique solution possible
for (int row = 0; row < size; row++)
{
for (int column = 0; column < size; column++)
{
if (matrix[column, row].CellValidValues.Length == 1 && matrix[column, row].CellValue == "0")
{
number = matrix[column, row].CellValidValues;
SetValue(number, column, row);
someSolved = true;
}
}
}
//Random selection
if (!someSolved)
{
minSize = size;
for (int row = 0; row < size; row++)
{
for (int column = 0; column < size; column++)
{
if (matrix[column, row].CellValidValues.Length < minSize && matrix[column, row].CellValidValues.Length > 1)
{
minSize = matrix[column, row].CellValidValues.Length;
}
if (matrix[column, row].CellValidValues.Length > maxSize)
maxSize = matrix[column, row].CellValidValues.Length;
}
}
for (int row = 0; row < size; row++)
{
for (int column = 0; column < size; column++)
{
number = "0";
if (matrix[column, row].CellValue == "0" && matrix[column, row].CellValidValues.Length == minSize)
{
int pos = rnd.Next(1, matrix[column, row].CellValidValues.Length + 1);
number = matrix[column, row].CellValidValues.Substring(pos - 1, 1);
SetValue(number, column, row);
someSolved = true;
break;
}
}
if (someSolved)
break;
}
}
}
}
private void GenerateCages()
{
cages = new List<Cage>();
bool success = false;
int orientation = 0;
int c2 = 0;
int r2 = 0;
Random rnd = new Random();
for (int r = 0; r < size; r++)
{
for (int c = 0; c < size; c++)
{
if (matrix[c, r].Cage == null)
{
success = false;
while (!success)
{
orientation = rnd.Next(1, 5);
switch (orientation)
{
case 1: // W
c2 = c - 1;
r2 = r;
break;
case 2: // E
c2 = c + 1;
r2 = r;
break;
case 3: // N
c2 = c;
r2 = r - 1;
break;
case 4: // S
c2 = c;
r2 = r + 1;
break;
}
if (c2 >= 0 && c2 < size && r2 >= 0 && r2 < size)
{
Cage cage = matrix[c2, r2].Cage;
if (cage == null)
{
cage = new Cage();
cage.CellList.Add(matrix[c2, r2]);
matrix[c2, r2].Cage = cage;
}
else
{
if (cage.CellList.Count > 3 && (c != size - 1 || r != size - 1))
{
continue;
}
}
cage.CellList.Add(matrix[c, r]);
matrix[c, r].Cage = cage;
cages.Add(cage);
success = true;
}
}
}
}
}
foreach (Cage cage in cages)
{
PickOperation(cage);
}
}
private void ResetBoard()
{
string s = "";
for (int c = 1; c <= size; c++)
s += c.ToString();
for (int row = 0; row < size; row++)
{
for (int column = 0; column < size; column++)
{
matrix[column, row] = new Cell();
matrix[column, row].CellValue = "0";
matrix[column, row].CellValidValues = s;
matrix[column, row].Column = column;
matrix[column, row].Row = row;
matrix[column, row].UserValue = 0;
}
}
}
private void SetValue(string number, int column, int row)
{
for (int c = 0; c < size; c++)
{
matrix[c, row].CellValidValues = matrix[c, row].CellValidValues.Replace(number, "");
}
for (int r = 0; r < size; r++)
{
matrix[column, r].CellValidValues = matrix[column, r].CellValidValues.Replace(number, "");
}
matrix[column, row].CellValidValues = number;
matrix[column, row].CellValue = number;
}
#endregion methods
#region properties
public Cell[,] Matrix
{
get { return matrix; }
}
public List<Cage> Cages
{
get { return cages; }
}
#endregion properties
}
}