Created
February 25, 2013 13:28
-
-
Save tangentstorm/5029796 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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