In reference to the excellent answer from @Stephen, here is a solution in C# without resorting to LINQ, to show the difference between the two approaches.
This solution handles both 4x4 and 9x9 Sodoku boards.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Sodoku
{
class Program
{
static void Main(string[] args)
{
List<string> lines = new List<string>();
lines.Add("4;1,4,2,3,2,3,1,4,4,2,3,1,3,1,4,2");
lines.Add("4;2,1,3,2,3,2,1,4,1,4,2,3,2,3,4,1");
lines.Add("9;5,3,4,6,7,8,9,1,2,6,7,2,1,9,5,3,4,8,1,9,8,3,4,2,5,6,7,8,5,9,7,6,1,4,2,3,4,2,6,8,5,3,7,9,1,7,1,3,9,2,4,8,5,6,9,6,1,5,3,7,2,8,4,2,8,7,4,1,9,6,3,5,3,4,5,2,8,6,1,7,9");
lines.Add("9;8,7,1,4,6,9,3,5,2,4,2,6,3,5,1,8,9,7,5,9,3,7,2,8,4,6,1,3,5,2,9,4,7,6,1,8,6,4,9,1,8,2,5,7,3,1,8,7,5,3,6,2,4,9,9,6,4,2,1,3,7,8,5,7,3,8,6,9,5,1,2,4,2,1,5,8,7,4,9,3,6");
lines.Add("9;1,2,7,5,3,9,8,4,6,4,5,3,8,6,1,7,9,2,8,9,6,4,7,2,1,5,3,2,8,9,3,1,7,4,6,5,3,6,5,2,8,4,9,1,7,7,4,1,9,5,6,3,2,8,9,7,4,6,2,8,5,3,1,5,1,2,7,4,3,6,8,9,6,3,8,1,9,5,2,7,4");
lines.Add("4;1,4,4,3,2,3,4,4,3,2,3,1,3,1,4,2");
foreach (var line in lines)
{
var tokens = line.Split(';');
var NxN = int.Parse(tokens[0]);
var nums = tokens[1].Trim().Split(',').Select(int.Parse).ToArray();
// Copy into Grid. Input is in row major form.
var grid = new int[NxN, NxN];
{
int i = 0;
for (int row = 0; row < NxN; row++)
{
for (int col = 0; col < NxN; col++)
{
grid[row, col] = nums[i];
i++;
}
}
}
int violations = 0;
// Check if each column passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[row, col];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each row passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[col, row];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each sub-grid passes tests for Sodoku.
// In 9x9 Sodoku, there are 9 subgrids of 3x3 each.
{
int NxNsub = (int)Math.Sqrt(NxN); // Length of side of sub-grid, for a 9x9 board this will be 3.
for (int row = 0; row < NxN; row += NxNsub)
{
for (int col = 0; col < NxN; col += NxNsub)
{
var tempArray = new int[NxN];
int index = 0;
for (int i = 0; i < NxNsub; i++)
{
for (int j = 0; j < NxNsub; j++)
{
tempArray[index] = grid[i + col, j + row];
index++;
}
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
}
Console.WriteLine(violations == 0 ? "True" : "False");
// Correct output is:
// True
// False
// True
// True
// True
// False
}
Console.ReadKey();
}
/// <summary>
/// Checks to see if one-dimensional array passes Sodoku rules:
/// 1. Digits range from 1 to N.
/// 2. No repeating digits.
/// Could be way more efficient, but this solution is more readable compared to other concise forms.
/// </summary>
/// <param name="array">Array.</param>
/// <returns>True if one-dimensional array passes Sodoku rules.</returns>
static bool IfArrayPassesSodoku(int[] array)
{
int violations = 0;
// Check for repeating digits.
bool ifRepeatedDigits = (array.Distinct().ToArray().Length != array.Length);
if (ifRepeatedDigits == true)
{
return false;
}
// Check to see that it contains the digits 1 to N.
var sorted = array.OrderBy(o => o).ToArray();
if (array.Length == 4)
{
if (sorted[0] != 1 || sorted[3] != 4)
{
return false;
}
}
else if (array.Length == 9)
{
if (sorted[0] != 1 || sorted[8] != 9)
{
return false;
}
}
else
{
Console.Write("Error E5234. Invalid grid size.\n");
return false;
}
return true;
}
}
}