using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace PocketLoop {
public partial class MainForm : Form {
private Random rnd = new Random();
private Bitmap backBuffer = null;
private CBoard board = null;
private int cellSize = 44;
private int offsetX = 5;
private int offsetY = 5;
private bool m_bCleared = false;
private int nextGridSizeX = 5;
private int nextGridSizeY = 5;
private CBoard nextBoard = null;
private CBoard nextBoardIncomplete = null;
private System.Threading.Thread genThread = null;
private bool showCountdown = false;
private bool m_bMouseMoved = false;
int[,]aroundPos = new int[9, 2] { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 } };
private const string StartupFilename = "startup.lop";
private const string OptionsFilename = "pocketloop.cfg";
private int MIN_DOT_DISTANCE = 2; // Default for QVGA screens
private int m_nStartingCoordX = 0;
private int m_nStartingCoordY = 0;
private int m_nCurrentX = 0;
private int m_nCurrentY = 0;
private uint m_nLastDotCoordX = 0; // These remember the coordinates of the last dot selected.
private uint m_nLastDotCoordY = 0;
private CConnector m_oSelectedConnector = null; // Used for marking unknowns.
private bool m_bStartedDrawing = false; // Need this to tell difference between draw and click.
private bool m_bDrawWinningBoard = false;
public class Tupple {
public int X, Y;
public Tupple(int x, int y) {
X = x;
Y = y;
}
}
public MainForm() {
InitializeComponent();
StartNewGenerationThread();
LoadOptions();
try {
board = LoadBoardFile(GetPath() + "\\" + StartupFilename);
} catch (Exception) { }
Resized(null, null);
UpdateScreen("Welcome to PocketLoop");
}
public static string GetPath() {
return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
}
private void LoadOptions() {
try {
FileStream fs = File.OpenRead(GetPath() + "/" + OptionsFilename);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, (int)fs.Length);
fs.Close();
if (data.Length == 4 && data[0] == 1) {
setNextGridSize(data[1], data[2], false);
menuAutoClear.Checked = (data[3] == 0 ? false : true );
}
} catch (Exception) { }
}
private void SaveOptions() {
FileStream fs;
try {
fs = File.Open(GetPath() + "/" + OptionsFilename,
FileMode.Create);
} catch (Exception) {
return;
}
byte[] data = new byte[4];
data[0] = 1; // Version
data[1] = (byte)nextGridSizeX;
data[2] = (byte)nextGridSizeY;
data[3] = (byte)( menuAutoClear.Checked ? 1 : 0);
fs.Write(data, 0, data.Length);
fs.Close();
}
private CBoard LoadBoardFile(string filename) {
FileStream fs = File.OpenRead(filename);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, (int) fs.Length);
fs.Close();
return new CBoard(data, false);
}
private void SaveBoardToFile(CBoard board, string filename) {
FileStream fs = File.Open(filename, FileMode.Create, FileAccess.Write);
byte[] data = board.toBinary();
fs.Write(data, 0, data.Length);
data = board.GetManuallyCleared();
fs.Write(data, 0, data.Length);
fs.Close();
}
void Draw(object sender, PaintEventArgs e) {
//DrawGrid(e.Graphics);
//return;
if (backBuffer == null)
backBuffer = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
if (m_bDrawWinningBoard)
{
DrawGrid(Graphics.FromImage(backBuffer), true);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), false);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), true);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), false);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), true);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), false);
e.Graphics.DrawImage(backBuffer, 0, 0);
System.Threading.Thread.Sleep(100);
DrawGrid(Graphics.FromImage(backBuffer), true);
e.Graphics.DrawImage(backBuffer, 0, 0);
// Only flash once.
m_bDrawWinningBoard = false;
}
else
{
DrawGrid(Graphics.FromImage(backBuffer), true);
e.Graphics.DrawImage(backBuffer, 0, 0);
}
}
protected override void OnPaintBackground(PaintEventArgs pevent) {
// Don't allow the background to paint. (Backbuffer)
}
void ClearBitmapCache() {
backBuffer = null;
dotValidImage = null;
dotInvalidImage = null;
horizConnectorSetImage = null;
horizConnectorUnknownImage = null;
horizConnectorInvalidImage = null;
vertConnectorSetImage = null;
vertConnectorUnknownImage = null;
vertConnectorInvalidImage = null;
numberImage = null;
}
private Bitmap dotValidImage = null;
private Bitmap dotInvalidImage = null;
void DrawDot(Graphics gfx, int x, int y, bool isValid) {
if (dotValidImage == null) {
dotValidImage = new Bitmap(4, 4);
Graphics.FromImage(dotValidImage).Clear(Color.White);
//Graphics.FromImage(dotValidImage).FillRectangle(new SolidBrush(Color.Gray), 1, 1, 2, 2);
dotInvalidImage = new Bitmap(4, 4);
Graphics.FromImage(dotInvalidImage).FillRectangle(new SolidBrush(Color.Red), 0, 0, 4, 4);
}
gfx.DrawImage((isValid ? dotValidImage : dotInvalidImage), offsetX + x * cellSize - 1, offsetY + y * cellSize - 1);
}
private Bitmap horizConnectorSetImage = null;
private Bitmap horizConnectorUnknownImage = null;
private Bitmap horizConnectorInvalidImage = null;
void DrawHorizConnector(Graphics gfx, int x, int y, CConnector c, bool drawSetConnectors) {
if (horizConnectorSetImage == null) {
horizConnectorSetImage = new Bitmap(cellSize - 4, 2);
horizConnectorUnknownImage = new Bitmap(cellSize - 4, 2);
//horizConnectorInvalidImage = new Bitmap(cellSize - 4, 2);
horizConnectorInvalidImage = horizConnectorSetImage;
Graphics.FromImage(horizConnectorInvalidImage).FillRectangle(new SolidBrush(Color.Red), 0, 0, cellSize - 4, 2);
Graphics.FromImage(horizConnectorSetImage).FillRectangle(new SolidBrush(Color.Black), 0, 0, cellSize - 4, 2);
Bitmap dashedBitmap = new Bitmap(3, 3);
Graphics.FromImage(dashedBitmap).Clear(Color.White);
Graphics.FromImage(dashedBitmap).FillRectangle(new SolidBrush(Color.Black), 0, 0, 1, 1);
Graphics.FromImage(horizConnectorUnknownImage).Clear(Color.White);
Graphics.FromImage(horizConnectorUnknownImage).FillRectangle(new TextureBrush( dashedBitmap), 0, 0, cellSize - 4, 1);
}
if (c.GetStatus() != ConnectorStatus.Unset)
{
if (drawSetConnectors || (c.GetStatus() == ConnectorStatus.Unknown))
{
gfx.DrawImage((c.GetStatus() == ConnectorStatus.Set ? (c.Valid ? horizConnectorSetImage : horizConnectorInvalidImage) : horizConnectorUnknownImage),
offsetX + x * cellSize + 3, offsetY + y * cellSize);
}
}
}
private Bitmap vertConnectorSetImage = null;
private Bitmap vertConnectorUnknownImage = null;
private Bitmap vertConnectorInvalidImage = null;
void DrawVertConnector(Graphics gfx, int x, int y, CConnector c, bool drawSetConnectors) {
if (vertConnectorSetImage == null) {
vertConnectorSetImage = new Bitmap(2, cellSize - 4);
vertConnectorUnknownImage = new Bitmap(2, cellSize - 4);
//vertConnectorInvalidImage = new Bitmap(2, cellSize - 4);
vertConnectorInvalidImage = vertConnectorSetImage;
Graphics.FromImage(vertConnectorInvalidImage).FillRectangle(new SolidBrush(Color.Red), 0, 0, 2, cellSize - 4);
Graphics.FromImage(vertConnectorSetImage).FillRectangle(new SolidBrush(Color.Black), 0, 0, 2, cellSize - 4);
Graphics.FromImage(vertConnectorUnknownImage).Clear(Color.White);
Bitmap dashedBitmap = new Bitmap(3,3);
Graphics.FromImage( dashedBitmap).Clear( Color.White);
Graphics.FromImage( dashedBitmap).FillRectangle( new SolidBrush(Color.Black),0,0,1,1);
Graphics.FromImage(vertConnectorUnknownImage).FillRectangle( new TextureBrush( dashedBitmap) , 0, 0, 1, cellSize - 4);
}
if (c.GetStatus() != ConnectorStatus.Unset)
{
if (drawSetConnectors || (c.GetStatus() == ConnectorStatus.Unknown))
{
gfx.DrawImage((c.GetStatus() == ConnectorStatus.Set ? (c.Valid ? vertConnectorSetImage : vertConnectorInvalidImage) : vertConnectorUnknownImage),
offsetX + x * cellSize, offsetY + y * cellSize + 3);
}
}
}
Bitmap[,] numberImage = null;
void DrawNumber(Graphics gfx, int x, int y, CNumber n) {
if (numberImage == null) {
numberImage = new Bitmap[4, 2];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 2; j++) {
numberImage[i, j] = new Bitmap(cellSize - 4, cellSize - 4);
Graphics g = Graphics.FromImage(numberImage[i, j]);
g.Clear(Color.White);
TextCenter(i.ToString(), g, new Font(FontFamily.GenericSansSerif, (cellSize) / 2 / (AutoScaleDimensions.Width / 96), FontStyle.Bold),
(j == 1 ? new SolidBrush(Color.Black) : new SolidBrush(Color.Red)), (cellSize - 4) / 2, (cellSize - 4) / 2);
}
}
}
if (n.Number != -1) {
gfx.DrawImage(numberImage[n.Number, (n.Valid ? 1 : 0)],
x * cellSize + offsetX + 3, y * cellSize + offsetY + 2);
}
}
void TextCenter(string str, Graphics grph, Font fnt, Brush brsh, float cx, float cy) {
SizeF strParams = grph.MeasureString(str, fnt);
float x = cx - strParams.Width / 2;
float y = cy - strParams.Height / 2;
grph.DrawString(str, fnt, brsh, x, y);
}
void DrawGrid(Graphics gfx, bool drawSetConnectors) {
gfx.Clear(Color.White);
if (board == null) return;
offsetX = (this.Width - (board.MaxX - 1) * cellSize) / 2;
offsetY = (this.Height - lblMessage.Height - (board.MaxY - 1) * cellSize) / 2;
/*
SolidBrush brushBlack = new SolidBrush(Color.Black);
SolidBrush brushBlue = new SolidBrush(Color.FromArgb(30, 113, 184));
SolidBrush brushPencil = new SolidBrush(Color.Red);
Font fontArial;
Font fontThick;
Font fontPencil;
Font fontPencilBold;
if (Width > 400) {
fontArial = new Font("Arial", cellSize * 1 / 3, System.Drawing.FontStyle.Regular);
fontThick = new Font("Arial", cellSize * 1 / 3, System.Drawing.FontStyle.Bold);
fontPencil = new Font("Courier", cellSize * 1 / 9, System.Drawing.FontStyle.Regular);
fontPencilBold = new Font("Courier", cellSize * 1 / 9, System.Drawing.FontStyle.Bold);
} else {
fontArial = new Font("Arial", cellSize * 2 / 3, System.Drawing.FontStyle.Regular);
fontThick = new Font("Arial", cellSize * 2 / 3, System.Drawing.FontStyle.Bold);
fontPencil = new Font("Courier", cellSize * 2 / 9, System.Drawing.FontStyle.Regular);
fontPencilBold = new Font("Courier", cellSize * 2 / 9, System.Drawing.FontStyle.Bold);
}
*/
for (int x = 0; x < board.MaxX; x++) {
for (int y = 0; y < board.MaxY; y++)
{
if (x + 1 < board.MaxX)
{
DrawHorizConnector(gfx, x, y, board.Dot[x, y].Right, drawSetConnectors);
}
if (y + 1 < board.MaxY)
{
DrawVertConnector(gfx, x, y, board.Dot[x, y].Down, drawSetConnectors);
}
if (x + 1 < board.MaxX && y + 1 < board.MaxY)
{
DrawNumber(gfx, x, y, board.Number[x, y]);
}
DrawDot(gfx, x, y, board.Dot[x, y].Valid);
}
}
}
void MousePressed(object sender, MouseEventArgs e)
{
m_bCleared = false;
m_oSelectedConnector = null;
m_bStartedDrawing = true;
m_bMouseMoved = false;
m_nStartingCoordX = e.X;
m_nStartingCoordY = e.Y;
m_nCurrentX = e.X;
m_nCurrentY = e.Y;
// Get selected connector and closest dot coordinates.
getSelectedConnector(e.X, e.Y, out m_oSelectedConnector);
getClosestDotCoordinates(e.X, e.Y, out m_nLastDotCoordX, out m_nLastDotCoordY);
clearTimer.Enabled = true;
}
private bool didClickDot(int pixelX, int pixelY, uint dotX, uint dotY)
{
pixelX -= offsetX;
pixelY -= offsetY;
double distanceX = Math.Abs((dotX * cellSize) - pixelX);
double distanceY = Math.Abs((dotY * cellSize) - pixelY);
// Get distance between where user clicked and closest dot.
double distance = Math.Sqrt((distanceX * distanceX) + (distanceY * distanceY));
return (distance <= MIN_DOT_DISTANCE);
}
private void getSelectedConnector(int pixelX, int pixelY, out CConnector selectedConnector)
{
selectedConnector = null;
pixelX -= offsetX;
pixelY -= offsetY;
int sum = (pixelX + pixelY) / cellSize;
int diff = (pixelX - pixelY + (board.MaxX + board.MaxY) * cellSize) / cellSize - (board.MaxX + board.MaxY);
int x = (sum + diff + 1) / 2;
int y = (sum - diff > 0 ? (sum - diff) / 2 : (sum - diff - 1) / 2);
if (x >= 0 && x < board.MaxX && y >= 0 && y < board.MaxY)
{
if (((sum + diff) % 2) == 0)
{
if (x < board.MaxX - 1)
{
selectedConnector = board.Dot[x, y].Right;
}
}
else
{
if (y < board.MaxY - 1)
{
selectedConnector = board.Dot[x, y].Down;
}
}
}
}
private void getClosestDotCoordinates(int pixelX, int pixelY, out uint coordX, out uint coordY)
{
// Get point that user clicked. Don't allow points outside the grid.
pixelX -= offsetX;
pixelY -= offsetY;
pixelX = (pixelX < 0) ? 0 : pixelX;
pixelY = (pixelY < 0) ? 0 : pixelY;
pixelX = (pixelX > (cellSize * board.MaxX)) ? (cellSize * board.MaxX) : pixelX;
pixelY = (pixelY > (cellSize * board.MaxY)) ? (cellSize * board.MaxY) : pixelY;
// Get "coordinates" of the top left corner of the box the user clicked.
coordX = (uint)(pixelX / cellSize);
coordY = (uint)(pixelY / cellSize);
// Now figure out which corner of the box the user wants.
if ((pixelX % cellSize) >= (cellSize / 2))
{
// Want right half of box. Make sure we don't go outside the grid.
coordX = (coordX < (board.MaxX - 1)) ? (coordX + 1) : coordX;
}
if ((pixelY % cellSize) >= (cellSize / 2))
{
// Want bottom half of box. Make sure we don't go outside the grid.
coordY = (coordY < (board.MaxY - 1)) ? (coordY + 1) : coordY;
}
}
private void MouseMoved(object sender, MouseEventArgs e)
{
m_nCurrentX = e.X;
m_nCurrentY = e.Y;
if (!m_bMouseMoved && (Math.Abs(m_nCurrentX - m_nStartingCoordX) > MIN_DOT_DISTANCE ||
Math.Abs(m_nCurrentY - m_nStartingCoordY) > MIN_DOT_DISTANCE)) {
m_bMouseMoved = true;
}
uint currCoordX = 0;
uint currCoordY = 0;
CConnector modifiedConnecter = null;
if (m_bStartedDrawing && m_bMouseMoved)
{
// Get connector to mark as set.
getClosestDotCoordinates(e.X, e.Y, out currCoordX, out currCoordY);
if ((currCoordX > m_nLastDotCoordX) && (currCoordY == m_nLastDotCoordY))
{
// Moved right.
modifiedConnecter = board.Dot[m_nLastDotCoordX, m_nLastDotCoordY].Right;
}
else if ((currCoordX == m_nLastDotCoordX) && (currCoordY > m_nLastDotCoordY))
{
// Moved down.
modifiedConnecter = board.Dot[m_nLastDotCoordX, m_nLastDotCoordY].Down;
}
else if ((currCoordX < m_nLastDotCoordX) && (currCoordY == m_nLastDotCoordY))
{
// Moved left.
modifiedConnecter = board.Dot[m_nLastDotCoordX, m_nLastDotCoordY].Left;
}
else if ((currCoordX == m_nLastDotCoordX) && (currCoordY < m_nLastDotCoordY))
{
// Moved up.
modifiedConnecter = board.Dot[m_nLastDotCoordX, m_nLastDotCoordY].Up;
}
else
{
// Same corner.
return;
}
m_nLastDotCoordX = currCoordX;
m_nLastDotCoordY = currCoordY;
// Toggle between set and unknown.
modifiedConnecter.SetStatus((modifiedConnecter.GetStatus() != ConnectorStatus.Set) ?
ConnectorStatus.Set : ConnectorStatus.Unknown);
// Do autoclear if it's turned on.
if (board.manuallyCleared.Contains(modifiedConnecter)) board.manuallyCleared.Remove(modifiedConnecter);
if (menuAutoClear.Checked) board.AutoClear();
// See if user solved board and if so hilight the solution.
CConnector checkSolvedConnector = (modifiedConnecter.GetStatus() == ConnectorStatus.Set) ?
modifiedConnecter : board.GetAnySetConnnector();
checkForWinAndUpdateScreen(checkSolvedConnector);
}
}
void MouseReleased(object sender, MouseEventArgs e)
{
if (m_bCleared || m_bMouseMoved) return;
m_bStartedDrawing = false;
clearTimer.Enabled = false;
if (m_oSelectedConnector != null)
{
m_oSelectedConnector.SetStatus((m_oSelectedConnector.GetStatus() == ConnectorStatus.Set) ?
ConnectorStatus.Unset : ConnectorStatus.Set);
if (m_oSelectedConnector.GetStatus() != ConnectorStatus.Unset)
{
if (board.manuallyCleared.Contains(m_oSelectedConnector))
{
board.manuallyCleared.Remove(m_oSelectedConnector);
}
}
if (menuAutoClear.Checked) board.AutoClear();
// See if user solved board and if so hilight the solution.
CConnector checkSolvedConnector = (m_oSelectedConnector.GetStatus() == ConnectorStatus.Set) ?
m_oSelectedConnector : board.GetAnySetConnnector();
checkForWinAndUpdateScreen(checkSolvedConnector);
}
}
private void clearTimer_Tick(object sender, EventArgs e)
{
m_bCleared = true;
clearTimer.Enabled = false;
if (m_bMouseMoved || m_oSelectedConnector == null) {
return;
}
m_bStartedDrawing = false;
m_oSelectedConnector.SetStatus((m_oSelectedConnector.GetStatus() == ConnectorStatus.Unset) ?
ConnectorStatus.Unknown : ConnectorStatus.Unset);
if (menuAutoClear.Checked)
{
if (m_oSelectedConnector.GetStatus() != ConnectorStatus.Unset)
{
if (board.manuallyCleared.Contains(m_oSelectedConnector))
board.manuallyCleared.Remove(m_oSelectedConnector);
}
else
{
board.manuallyCleared.Add(m_oSelectedConnector);
}
board.AutoClear();
}
UpdateScreen("");
}
private void checkForWinAndUpdateScreen(CConnector setConnector)
{
if ((setConnector != null) && board.IsSolved())
{
m_bDrawWinningBoard = true;
UpdateScreen("You found the solution!");
}
else
{
m_bDrawWinningBoard = false;
UpdateScreen(string.Empty);
}
}
private void menuExit_Click(object sender, EventArgs e) {
try {
SaveBoardToFile(board, GetPath() + "\\" + StartupFilename);
} catch (Exception) { }
Close();
}
private void generatePuzzle(CBoard board, int count) {
while (count > 0) {
int posX = rnd.Next(board.MaxX-1);
int posY = rnd.Next(board.MaxY-1);
if (board.Number[posX, posY].Number != -1) continue;
if (board.IncreasedNumber(posX - 1, posY) == -1 &&
board.IncreasedNumber(posX + 1, posY) == -1 &&
board.IncreasedNumber(posX, posY -1 ) == -1 &&
board.IncreasedNumber(posX, posY + 1) == -1)
continue; // Invalid numbers to grow. Must be adjacent to an existing one
int prev= board.IncreasedNumber( posX + aroundPos[0,0], posY + aroundPos[0,1]);
int borderCount = 0;
int fillCount = 0;
bool valid = true;
for (int i = 0; i < 9; i++) {
if (board.IncreasedNumber(posX + aroundPos[i, 0], posY + aroundPos[i, 1]) != -1) {
fillCount++;
if (fillCount > 4) {
valid = false;
break; // Avoid filling all the area
}
}
if (board.IncreasedNumber(posX + aroundPos[i, 0], posY + aroundPos[i, 1]) != prev) {
borderCount++;
if (borderCount > 2) {
valid = false;
break; // Bail-out. We touched another part. Avoid cycles.
}
}
prev = board.IncreasedNumber(posX + aroundPos[i, 0], posY + aroundPos[i, 1]);
}
if (valid) {
board.Number[posX, posY].Number = 3;
count--;
}
}
for (int x = 0; x < board.MaxX; x++) {
for (int y = 0; y < board.MaxY; y++) {
if (board.IncreasedNumber(x - 1, y) != board.IncreasedNumber(x, y)) {
board.Dot[x, y].Down.SetStatus (ConnectorStatus.Set);
}
if (board.IncreasedNumber(x, y-1) != board.IncreasedNumber(x, y)) {
board.Dot[x, y].Right.SetStatus (ConnectorStatus.Set);
}
}
}
for (int x = 0; x < board.MaxX - 1; x++) {
for (int y = 0; y < board.MaxY - 1; y++) {
board.Number[x, y].Number = board.Number[x, y].Count(ConnectorStatus.Set);
}
}
for (int x = 0; x < board.MaxX; x++) {
for (int y = 0; y < board.MaxY; y++) {
if (board.Dot[x, y].Down.GetStatus() == ConnectorStatus.Set)
board.Dot[x, y].Down.SetStatus (ConnectorStatus.Unknown);
if (board.Dot[x, y].Right.GetStatus() == ConnectorStatus.Set)
board.Dot[x, y].Right.SetStatus (ConnectorStatus.Unknown);
}
}
}
private void advance(int x, int y, Direction dir, out int nextX, out int nextY) {
nextX = x;
nextY = y;
switch (dir) {
case Direction.Right:
nextX = x + 1;
break;
case Direction.Left:
nextX = x - 1;
break;
case Direction.Up:
nextY = y - 1;
break;
case Direction.Down:
nextY = y + 1;
break;
}
}
private bool binaryEqual(byte[] a, byte[] b) {
if (a.Length != b.Length) return false;
for (int i = 0; i < a.Length; i++)
if (a[i] != b[i])
return false;
return true;
}
private void generatePath(int startingX, int startingY, int posX, int posY, Direction dir, Direction d2, Direction d3, int depth, List<byte[]> solutionList, int maxSolutionCount) {
ConnectorStatus s1,s2, s3;
int nextX, nextY;
if (solutionList.Count >= maxSolutionCount) return;
advance(posX, posY, dir, out nextX, out nextY);
if( nextX<0 || nextY<0 || nextX+1>board.MaxX || nextY+1>board.MaxY) return;
s1 = board.Dot[posX, posY].getConnector(dir).GetStatus();
s2 = board.Dot[posX, posY].getConnector(d2).GetStatus();
s3 = board.Dot[posX, posY].getConnector(d3).GetStatus();
if( s1 == ConnectorStatus.Unset) return;
board.Dot[posX, posY].getConnector(dir).SetStatus(ConnectorStatus.Set);
if (board.Dot[posX, posY].getConnector(d2).GetStatus() != ConnectorStatus.Set)
board.Dot[posX, posY].getConnector(d2).SetStatus (ConnectorStatus.Unset);
if (board.Dot[posX, posY].getConnector(d3).GetStatus() != ConnectorStatus.Set)
board.Dot[posX, posY].getConnector(d3).SetStatus (ConnectorStatus.Unset);
if (board.Dot[posX, posY].getConnector(dir).Valid &&
board.Dot[posX, posY].getConnector(d2).Valid &&
board.Dot[posX, posY].getConnector(d3).Valid) {
//UpdateScreen();
if (startingX == nextX && startingY == nextY) {
byte[] solutionBuffer = (new CBoard(board.toBinary(),true)).toBinary();
CBoard solution = new CBoard(solutionBuffer, true);
if (solution.Valid) {
bool found = true;
foreach (byte[] buffer in solutionList) {
if (binaryEqual(buffer,solutionBuffer)) {
found = false;
break;
}
}
if (found) {
solutionList.Add(solutionBuffer);
}
}
} else {
List<Direction> list = new List<Direction>(3);
list.Add(dir);
list.Add((dir < Direction.Left ? dir + 1 : Direction.Up));
list.Add((dir > Direction.Up ? dir - 1 : Direction.Left));
generatePath(startingX, startingY, nextX, nextY, list[0], list[1], list[2], depth + 1, solutionList, maxSolutionCount);
generatePath(startingX, startingY, nextX, nextY, list[1], list[0], list[2], depth + 1, solutionList, maxSolutionCount);
generatePath(startingX, startingY, nextX, nextY, list[2], list[1], list[0], depth + 1, solutionList, maxSolutionCount);
}
}
board.Dot[posX, posY].getConnector(dir).SetStatus (s1);
board.Dot[posX, posY].getConnector(d2).SetStatus (s2);
board.Dot[posX, posY].getConnector(d3).SetStatus (s3);
}
private void GenerateNew() {
rnd = new Random();
CBoard newboard = new CBoard(nextGridSizeX+1, nextGridSizeY+1);
newboard.Number[rnd.Next(newboard.MaxX - 1), rnd.Next(newboard.MaxY - 1)].Number = 3;
generatePuzzle(newboard, nextGridSizeX*nextGridSizeY/2);
Reduce(newboard);
if (menuAutoClear.Checked)
newboard.AutoClear();
nextBoard = newboard;
}
private void Reduce( CBoard board) {
List<Tupple> positionList = new List<Tupple>();
for (int x = 0; x < board.MaxX - 1; x++) {
for (int y = 0; y < board.MaxY - 1; y++) {
positionList.Insert(rnd.Next(positionList.Count), new Tupple(x, y));
}
}
int depth;
switch (board.MaxX - 1) {
case 5:
depth = 5;
break;
case 6:
depth = 4;
break;
case 7:
depth = 3;
break;
default:
depth = 2;
break;
}
byte[] savedBoard = board.toBinary();
while (positionList.Count > 0) {
board.Number[positionList[0].X, positionList[0].Y].Number = -1;
SimplifyResult r =board.Solve( depth, false);
if( r == SimplifyResult.Terminal) {
board.LoadBinary(savedBoard, false);
board.Number[positionList[0].X, positionList[0].Y].Number = -1;
savedBoard = board.toBinary();
}
positionList.RemoveAt(0);
if (showCountdown) {
UpdateScreen("New grid countdown: " + positionList.Count);
}
board.LoadBinary(savedBoard, false);
nextBoardIncomplete = new CBoard(savedBoard, false);
}
board = new CBoard(savedBoard, false);
if (menuAutoClear.Checked) {
board.AutoClear();
}
if (showCountdown) {
UpdateScreen("New grid ready");
}
}
private delegate void UpdateScreenDelegate(string msg);
private void UpdateScreen(string msg) {
if (InvokeRequired)
Invoke(new UpdateScreenDelegate(UpdateScreen), msg);
else {
lblMessage.Text = msg;
Invalidate();
}
}
private void menuNewBoard_Click(object sender, EventArgs e) {
if (nextBoard == null) {
if (showCountdown == true && nextBoardIncomplete != null) {
board = nextBoardIncomplete;
} else {
UpdateScreen("Please wait. Generating.");
showCountdown = true;
return;
}
} else {
board = nextBoard;
}
showCountdown = false;
Resized(null, null);
if (genThread != null) {
genThread.Abort();
}
nextBoard = null;
nextBoardIncomplete = null;
StartNewGenerationThread();
UpdateScreen( "New grid " + (board.MaxX-1) + "x"+ (board.MaxY-1) + " loaded");
}
private void Resized(object sender, EventArgs e) {
if (board != null) {
cellSize = Math.Min((Width - 15) / (board.MaxX - 1), (Height - 15 - lblMessage.Height) / (board.MaxY-1));
}
if (this.CurrentAutoScaleDimensions.Height == 96F)
MIN_DOT_DISTANCE = 2; //QVGA
else
MIN_DOT_DISTANCE = 4; //VGA
lblMessage.Top = Height - lblMessage.Height;
ClearBitmapCache();
UpdateScreen("");
}
private void StartNewGenerationThread() {
try {
genThread.Abort();
} catch (Exception) { }
genThread = new System.Threading.Thread(GenerateNew);
genThread.IsBackground = true;
genThread.Priority = System.Threading.ThreadPriority.BelowNormal;
genThread.Start();
}
private void menuSimplify_Click(object sender, EventArgs e) {
lblMessage.Text = "";
SimplifyResult r = board.Solve(1,true);
UpdateScreen("Done: " + r.ToString());
}
//private void menuReduce_Click(object sender, EventArgs e) {
// board.manuallyCleared.Clear();
// // Fix seed so that it always reduces in the same way
// // Helps with regression testing and performance testing
// rnd = new Random(12345);
// lblMessage.Text = "";
// System.Threading.Thread t = new System.Threading.Thread(Reduce);
// t.IsBackground = true;
// t.Start();
//}
private void menuRestart_Click(object sender, EventArgs e) {
board.Restart();
board.manuallyCleared.Clear();
if (menuAutoClear.Checked)
board.AutoClear();
Invalidate();
}
private void menuSave_Click(object sender, EventArgs e)
{
if (board == null)
return;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Pocket Loop files (*.pol)|*.pol";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(saveFileDialog1.FileName);
sw.Write((board.MaxX-1) + ":" + (board.MaxY-1) + ":");
for (int y = 0; y < board.MaxY-1; y++)
{
for (int x = 0; x < board.MaxX-1; x++)
{
if (board.Number[x,y].Number == -1)
sw.Write(".");
else
sw.Write(board.Number[x,y].Number);
}
}
sw.Close();
}
}
private void menuOpen_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Pocket Loop files (*.pol)|*.pol";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
lblMessage.Text = "";
StreamReader sr = new StreamReader(openFileDialog1.FileName);
string inp = sr.ReadLine();
sr.Close();
string[] split = inp.Split(new Char[] { ':' });
int x = Convert.ToInt32(split[0]);
int y = Convert.ToInt32(split[1]);
board = new CBoard(x + 1, y + 1);
char[] nums = split[2].ToCharArray();
int curridx = 0;
for (y = 0; y < board.MaxY - 1; y++)
{
for (x = 0; x < board.MaxX - 1; x++)
{
if (nums[curridx] == '.')
board.Number[x, y].Number = -1;
else
board.Number[x, y].Number = nums[curridx] - '0';
curridx++;
}
}
}
catch (Exception)
{
lblMessage.Text = "Error loading file";
board = null;
}
}
}
private void menuAutoClear_Click(object sender, EventArgs e)
{
menuAutoClear.Checked = !menuAutoClear.Checked;
if (menuAutoClear.Checked)
{
board.AutoClear();
Invalidate();
}
SaveOptions();
}
private void menuHint_Click(object sender, EventArgs e) {
lblMessage.Text = "";
SimplifyResult r = board.Solve(1, true);
UpdateScreen("Done: " + r.ToString());
}
private void setNextGridSize(int x, int y, bool manualChange) {
if (x != nextGridSizeX || y != nextGridSizeY) {
nextGridSizeX = x;
nextGridSizeY = y;
StartNewGenerationThread();
nextBoard = null;
nextBoardIncomplete = null;
} else {
nextGridSizeX = x;
nextGridSizeY = y;
}
menuGridSize10.Checked = (nextGridSizeX == 10 && nextGridSizeY == 10);
menuGridSize10x7.Checked = (nextGridSizeX == 10 && nextGridSizeY == 7);
menuGridSize10x5.Checked = (nextGridSizeX == 10 && nextGridSizeY == 5);
menuGridSize9.Checked = (nextGridSizeX == 9 && nextGridSizeY == 9);
menuGridSize9x6.Checked = (nextGridSizeX == 9 && nextGridSizeY == 6);
menuGridSize8.Checked = (nextGridSizeX == 8 && nextGridSizeY == 8);
menuGridSize8x5.Checked = (nextGridSizeX == 8 && nextGridSizeY == 5);
menuGridSize7.Checked = (nextGridSizeX == 7 && nextGridSizeY == 7);
menuGridSize6.Checked = (nextGridSizeX == 6 && nextGridSizeY == 6);
menuGridSize5.Checked = (nextGridSizeX == 5 && nextGridSizeY == 5);
if (manualChange) {
UpdateScreen("New grid will be " + x + "x" + y);
SaveOptions();
}
}
private void menuGridSize10_Click(object sender, EventArgs e) {
setNextGridSize(10, 10, true);
}
private void menuGridSize9_Click(object sender, EventArgs e) {
setNextGridSize(9, 9, true);
}
private void menuGridSize8_Click(object sender, EventArgs e) {
setNextGridSize(8, 8, true);
}
private void menuGridSize7_Click(object sender, EventArgs e) {
setNextGridSize(7,7, true);
}
private void menuGridSize6_Click(object sender, EventArgs e) {
setNextGridSize(6,6, true);
}
private void menuGridSize5_Click(object sender, EventArgs e) {
setNextGridSize(5,5, true);
}
private void menuGridSize10x5_Click(object sender, EventArgs e) {
setNextGridSize(10, 5, true);
}
private void menuGridSize10x7_Click(object sender, EventArgs e) {
setNextGridSize(10, 7, true);
}
private void menuGridSize9x6_Click(object sender, EventArgs e) {
setNextGridSize(9, 6, true);
}
private void menuGridSize8x5_Click(object sender, EventArgs e) {
setNextGridSize(8, 5, true);
}
private void OpenFile(int number) {
try {
board = LoadBoardFile( GetPath() + "\\grid" + number + ".lop");
Resized(null, null);
UpdateScreen("Grid " + number + " loaded");
} catch (Exception e) {
MessageBox.Show(e.Message, "Unable to load Grid " + number,
MessageBoxButtons.OK, MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
}
private void SaveFile(int number) {
try {
SaveBoardToFile(board, GetPath() + "\\grid"+number+".lop");
UpdateScreen("Grid " + number + " saved");
} catch (Exception e) {
MessageBox.Show(e.Message, "Unable to save Grid " + number,
MessageBoxButtons.OK, MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
}
private void menuOpenGrid1_Click(object sender, EventArgs e) {
OpenFile(1);
}
private void menuOpenGrid2_Click(object sender, EventArgs e) {
OpenFile(2);
}
private void menuOpenGrid3_Click(object sender, EventArgs e) {
OpenFile(3);
}
private void menuOpenGrid4_Click(object sender, EventArgs e) {
OpenFile(4);
}
private void menuOpenGrid5_Click(object sender, EventArgs e) {
OpenFile(5);
}
private void menuSaveGrid1_Click(object sender, EventArgs e) {
SaveFile(1);
}
private void menuSaveGrid2_Click(object sender, EventArgs e) {
SaveFile(2);
}
private void menuSaveGrid3_Click(object sender, EventArgs e) {
SaveFile(3);
}
private void menuSaveGrid4_Click(object sender, EventArgs e) {
SaveFile(4);
}
private void menuSaveGrid5_Click(object sender, EventArgs e) {
SaveFile(5);
}
private void menuHowToPlay_Click(object sender, EventArgs e) {
HelpForm help = new HelpForm("Help.htm");
help.Show();
}
private void menuAbout_Click(object sender, EventArgs e) {
HelpForm help = new HelpForm("About.htm");
help.Show();
}
private void menuOpenEditor_Click(object sender, EventArgs e)
{
EditorForm form = new EditorForm();
form.ShowDialog();
}
}
}