Skip to content

Instantly share code, notes, and snippets.

@tangentstorm
Created February 25, 2013 13:28
Show Gist options
  • Save tangentstorm/5029796 to your computer and use it in GitHub Desktop.
Save tangentstorm/5029796 to your computer and use it in GitHub Desktop.
// Copyright (c) 2011 Michal J Wallace and Sean D. Siem
// See the file license.txt for copying permission.
// $Id: Grid.cs 993 2012-10-15 19:56:23Z mwallace $
using System;
using System.Collections.Generic;
using System.Text;
using JsonFx.Json;
namespace AlchementrixCore
{
/**
* Represents an arbitrary grid of data.
*/
public class Grid
{
public delegate Tile PopulateGrid(int row, int col);
public delegate void VisitGrid(int row, int col);
private const int kDefaultSize = 16;
protected Tile[][] fData;
protected int fSize;
public int width
{
get { return fSize; }
}
public int depth
{
get { return fSize; }
}
public Grid(int size = kDefaultSize)
{
Reset(size);
Populate((int row, int col) => Tile.Empty);
}
public Grid(int[][] data)
{
Reset(data.Length);
Populate((int row, int col) => Tile.fromInt(data[row][col]));
}
public Grid(PopulateGrid pop, int size = kDefaultSize)
{
Reset(size);
Populate(pop);
}
private void Reset(int size)
{
fSize = size;
fData = new Tile[fSize][];
for (int row = 0; row < fSize; ++row)
{
fData[row] = new Tile[fSize];
}
}
private int[][] AsInts()
{
int[][] res = new int[fSize][];
for (int row = 0; row < fSize; ++row)
{
res[row] = new int[fSize];
for (int col = 0; col < fSize; ++col)
{
res[row][col] = (int) this.GetSub(row, col);
}
}
return res;
}
private string[][] AsStrings()
{
string[][] res = new string[fSize][];
for (int row = 0; row < fSize; ++row)
{
res[row] = new string[fSize];
for (int col = 0; col < fSize; ++col)
{
res[row][col] = fData[row][col].ToString();
}
}
return res;
}
private void Populate(PopulateGrid pop)
{
for (int row = 0; row < fSize; ++row)
{
for (int col = 0; col < fSize; ++col)
{
fData[row][col] = pop(row, col);
}
}
}
public void Visit(VisitGrid visit)
{
for (int row = 0; row < fSize; ++row)
{
for (int col = 0; col < fSize; ++col)
{
visit(row, col);
}
}
}
public void Update(Grid grid)
{
grid.Visit((int row, int col) =>
{
fData[row][col] = grid.fData[row][col];
});
}
/**
* Takes a json representation of a grid. As a testing
* aid, the following symbols can be used for numbers.
* These will be converted before the json is deserialized.
*
* _ X
* 0 1
*/
public Grid(string alchyCode, bool convertRandom = false)
{
string json = alchyCode;
var data = new JsonReader().Read<List<List<String>>>(json);
fSize = data.Count;
fData = new Tile[fSize][];
int row = 0;
foreach (var rowData in data)
{
fData[row] = new Tile[fSize];
int col = 0;
foreach (string cell in rowData)
{
fData[row][col++] = Tile.fromString(cell, convertRandom);
}
row++;
}
}
public static bool operator ==(Grid a, Grid b)
{
try
{
return a.ToString() == b.ToString();
}
catch (NullReferenceException)
{
return false;
}
}
public static bool operator !=(Grid a, Grid b)
{
return !(a == b);
}
public bool Equals(Grid b)
{
return this == b;
}
override
public bool Equals(Object o)
{
return false;
}
override
public String ToString()
{
String json = new JsonWriter().Write(this.AsStrings());
String alchy = json;
return alchy.Replace("],", "],\n ").Replace('"','\'');
}
public Grid Transform(PopulateGrid pop)
{
return new Grid(pop, fSize);
}
public Grid RotatedClockwise()
{
return Transform((int row, int col) =>
fData[fSize - col - 1][row]);
}
public Grid RotatedCounterClockwise()
{
return Transform((int row, int col) =>
fData[col][fSize - row - 1]);
}
public int Count(Substance what)
{
int count = 0;
Visit((int row, int col) =>
{
if (fData[row][col].sub == what)
{
count++;
}
});
return count;
}
public Tile this[int row, int col]
{
get { return fData[row][col]; }
set { fData[row][col] = value; }
}
public Substance GetSub(int row, int col)
{
return fData[row][col].sub;
}
public void Put(int row, int col, Substance sub)
{
fData[row][col] = new Tile((int)sub);
}
virtual
public Grid Copy()
{
return Transform((int row, int col) => fData[row][col]);
}
public Grid BlankCopy()
{
return Transform((int row, int col) => Tile.Empty);
}
public void Clear()
{
Populate((int row, int col) => Tile.Empty);
}
override public int GetHashCode()
{
return fData.GetHashCode();
}
// @TODO: this expands to a square. it probably should either
// fill in the extra area with zeros, or I should implement
// non-square grids. (At the moment, this is fine, though, because
// it's only used by ShapeFinder which zeroes the grid up front)
public Grid SubGrid(int minRow, int minCol, int maxRow, int maxCol)
{
int w = maxCol - minCol;
int h = maxRow - minRow;
return new Grid(
(int row, int col) =>
{
int fromRow = minRow + row;
int fromCol = minCol + col;
return (fromRow < this.depth && fromCol < this.width)
? this.fData[fromRow][fromCol]
: Tile.Empty;
},
Math.Max(w, h));
}
public bool Contains(Point p)
{
return (p.col >= 0) && (p.col < width)
&& (p.row >= 0) && (p.row < depth);
}
public Tile GetTile(int row, int col)
{
return fData[row][col];
}
public Tile GetTile(Point p)
{
if (this.Contains(p))
return fData[p.row][p.col];
else
return new Tile(Substance.Nothing);
}
}
}
// Copyright (c) 2011 Michal J Wallace and Sean D. Siem
// See the file license.txt for copying permission.
// $Id: Shape.cs 993 2012-10-15 19:56:23Z mwallace $
using System;
using System.Collections.Generic;
using System.Text;
namespace AlchementrixCore
{
public class Shape
{
public Grid grid;
public Point pos;
public Shape(Grid grid, Point p)
{
this.pos = p;
this.grid = grid;
}
public static Shape AtRandom(int row, int col)
{
return new Shape(Pentomino.AtRandom(), new Point(row, col));
}
public int row { get { return pos.row; } }
public int col { get { return pos.col; } }
public void Sink(Well well)
{
Nudge(well, Point.Down);
}
public void Nudge(Well well, Point change)
{
if (CanNudge(well, change))
{
pos += change;
}
else
{
throw new CantMoveThere();
}
}
public bool CanNudge(Well well, Point change)
{
bool answer = true;
grid.Visit((int row, int col) =>
{
int newRow = this.pos.row + change.row + row;
int newCol = this.pos.col + change.col + col;
if (answer && grid.GetSub(row, col) != Substance.Nothing)
{
answer = (GameSettings.hover)
? well.InBounds(newRow, newCol)
: well.IsEmpty(newRow, newCol);
}
});
return answer;
}
public class CantMoveThere : Exception
{
}
internal void RotateCW(Well well)
{
grid = grid.RotatedClockwise();
if (!CanNudge(well, Point.Center))
{
// undo it:
grid = grid.RotatedCounterClockwise();
throw new CantMoveThere();
}
}
}
public class Pentomino
{
public const String L =
"[[ '_', '_', '_', '_' ]," +
" [ '%', '_', '_', '_' ]," +
" [ '%', '%', '%', '%' ]," +
" [ '_', '_', '_', '_' ]]";
public const String Y =
"[[ '_', '_', '_', '_' ]," +
" [ '_', '%', '_', '_' ]," +
" [ '%', '%', '%', '%' ]," +
" [ '_', '_', '_', '_' ]]";
public const String X =
"[[ '_', '%', '_' ]," +
" [ '%', '%', '%' ]," +
" [ '_', '%', '_' ]]";
public const String V =
"[[ '_', '_', '%' ]," +
" [ '_', '_', '%' ]," +
" [ '%', '%', '%' ]]";
public const String Z =
"[[ '_', '_', '_', '_' ]," +
" [ '_', '_', '_', '%' ]," +
" [ '_', '%', '%', '%' ]," +
" [ '_', '%', '_', '_' ]]";
public const String W =
"[[ '_', '_', '%' ]," +
" [ '_', '%', '%' ]," +
" [ '%', '%', '_' ]]";
public const String I =
"[[ '_', '_', '_', '_', '_' ]," +
" [ '_', '_', '_', '_', '_' ]," +
" [ '%', '%', '%', '%', '%' ]," +
" [ '_', '_', '_', '_', '_' ]," +
" [ '_', '_', '_', '_', '_' ]]";
public const String T =
"[[ '_', '_', '%' ]," +
" [ '%', '%', '%' ]," +
" [ '_', '_', '%' ]]";
public const String U =
"[['%', '_', '%']," +
" ['%', '%', '%']," +
" ['_', '_', '_']]";
public const String N =
"[[ '_', '_', '_', '_', '_']," +
" [ '_', '_', '_', '_', '_']," +
" [ '_', '%', '%', '_', '_']," +
" [ '_', '_', '%', '%', '%']," +
" [ '_', '_', '_', '_', '_']]";
public const String P =
"[[ '_', '_', '_' ]," +
" [ '_', '%', '%' ]," +
" [ '%', '%', '%' ]]";
public const String F =
"[[ '_', '%', '_' ]," +
" [ '_', '%', '%' ]," +
" [ '%', '%', '_' ]]";
public static Grid AtRandom()
{
String[] all = { L, Y, X, V, Z, W, I, T, U, N, P, F };
return new Grid(all[GameSettings.random.Next(all.Length)], true);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment