Skip to content

Instantly share code, notes, and snippets.

@tangentstorm
Last active December 14, 2015 04:39
Show Gist options
  • Save tangentstorm/5029722 to your computer and use it in GitHub Desktop.
Save tangentstorm/5029722 to your computer and use it in GitHub Desktop.
penominos in haxe
import Substance;
class Grid
{
public var data : Array<Array<Int>>;
public var width:Int;
public var depth:Int;
public function new (proto, width:Int=-1, depth:Int=-1)
{
data = proto;
// if no width/height given, assume we have a square
if (width == -1)
{
this.depth = proto.length;
this.width = this.depth == 0 ? 0 : proto[0].length;
}
else
{
this.width = width;
this.depth = depth;
}
}
// @TODO: factor out the loop and use anonymous functions instead
// there should be one version to transform and one to build a new grid
public function iterate2(f, g, ulc:Point=null, lrc:Point=null) : Void
{
if (ulc == null) ulc = new Point(0,0); // upper left corner
if (lrc == null) lrc = new Point(this.width, this.depth); // lower right corner
for (row in ulc.y ... lrc.y)
{
g(this, row, true);
for (col in ulc.x ... lrc.x)
{
// function(oldGrid, newX, newY, oldValue)
var newCol = col-ulc.x;
if (newCol < 0)
{
throw "wtf??: ulc.x =" + ulc.x
+ '; lrc.x =' + lrc.x
+ '; newCol = col-ulc.x = ' + newCol;
}
f(this, row-ulc.y, newCol, this.data[row][col]);
}
g(this, row, false);
}
}
public function iterate(f, ulc:Point=null, lrc:Point=null) : Void
{
iterate2(f, function(self, row, before) {}, ulc, lrc);
}
public function transform(f, ulc:Point=null, lrc:Point=null) : Grid
{
var newWidth = this.width;
var newDepth = this.depth;
if (ulc != null)
{
newWidth = lrc.x - ulc.x;
newDepth = lrc.y - ulc.y;
}
var proto:Array<Array<Int>> = [];
var original = this;
iterate2(// for every cell:
function(self, row, col, old)
{
f(original, proto, row, col, old);
},
// for every row:
function(self, row, before)
{
if (before)
{
var newRow = [];
for ( i in 0...newWidth)
newRow.push(0);
proto.push(newRow);
}
},
// bounding box:
ulc, lrc);
return new Grid(proto, newWidth, newDepth);
}
public function copy(ulc:Point=null, lrc:Point=null) : Grid
{
var theCopy = transform(function(self, proto, row, col, old)
{
//trace('proto[' + row + ',' + col + '] = ' + old);
proto[row][col] = old;
}, ulc, lrc);
if (ulc != null)
{
theCopy.width = lrc.x - ulc.x;
theCopy.depth = lrc.y - ulc.y;
}
return theCopy;
}
public function blankCopy() : Grid
{
return transform(function(self, proto, row, col, old)
{
proto[row][col] = 0;
});
}
public function rotateRight()
{
return transform(function(self, proto, row, col, old)
{
// new row(depth) corresponds to old col
// new col(distance right) corresponds
// to how far UP the old piece was
proto[row][col] = self.data[self.width-col-1][row];
});
}
public function rotateLeft() : Grid
{
return transform(function(self, proto, row, col, old)
{
proto[row][col] = self.data[col][self.depth-row-1];
});
}
public function equals(other:Grid) : Bool
{
// first check that the two grids are the same height
// @TODO: check that both are same width
if (! (other.width == this.width)
&& (other.width == this.width))
{
return false;
}
// if so, check that the contents are the same:
var isSame:Bool = true;
iterate(function(self, row, col, val)
{
isSame = isSame && (other.data[row][col] == val);
});
return isSame;
}
public function toString()
{
var out:StringBuf = new StringBuf();
out.add("[");
iterate2(function(self, row, col, val)
{
out.add(val);
out.add(",");
},
function(self, row, before)
{
if (before)
{
out.add("[");
}
else
{
out.add("],\n");
}
});
out.add("]");
return out.toString();
}
public function dump(label:String) : Grid
{
trace("\n-- dumping grid (" + label + ") --\n"
+ this.toString()
+ "\n -- end of grid --\n");
return this;
}
public function insertColumn(before:Int=0, fill:Int=0) : Grid
{
var res = this.copy();
for (row in 0 ... this.depth)
{
res.data[row].insert(before, fill);
}
return res;
}
public function insertRow(before:Int=0, fill:Int=0) : Grid
{
var res = this.copy();
var row = [];
for (i in 0 ... this.width)
{
row.push(fill);
}
res.data.insert(before, row);
return res;
}
public function count(what:Int) : Int
{
var res:Int = 0;
for (row in 0 ... this.depth)
{
for (col in 0 ... this.width)
{
if (this.data[row][col] == what)
{
res++;
}
}
}
return res;
}
}
class GridTest extends haxe.unit.TestCase {
private static var X = 1;
private static var _ = 0;
public function testEqual() {
assertTrue(new Grid([[X]]).equals(new Grid([[X]])));
}
public function testRotateRight() {
var grid = new Grid([[_,X],
[_,X]]);
assertTrue(grid.rotateRight()
.equals(new Grid([[_,_],
[X,X]])));
}
public function testRotateLeft() {
var grid = new Grid([[_,X],
[_,X]]);
assertTrue(grid.rotateLeft()
.equals(new Grid([[X,X],
[_,_]])));
}
public function testInsertColumn() {
var grid = new Grid([[X,X],
[X,X]]);
assertTrue(grid.insertColumn(0).equals
(new Grid([[_,X,X],
[_,X,X]])));
assertTrue(grid.insertColumn(1).equals
(new Grid([[X,_,X],
[X,_,X]])));
assertTrue(grid.insertColumn(2).equals
(new Grid([[X,X,_],
[X,X,_]])));
}
public function testInsertRow() {
var grid = new Grid([[X,X],
[X,X]]);
assertTrue(grid.insertRow(0).equals
(new Grid([[_,_],
[X,X],
[X,X]])));
assertTrue(grid.insertRow(1).equals
(new Grid([[X,X],
[_,_],
[X,X]])));
assertTrue(grid.insertRow(2).equals
(new Grid([[X,X],
[X,X],
[_,_]])));
}
public function testCopy() {
var grid = new Grid([[00,10,20,30],
[01,11,21,31],
[02,12,22,32],
[03,13,23,33],
[00,00,00,00]]);
assertTrue(grid.copy().equals(grid));
// start and end points:
var theCopy = grid.copy(new Point(1,1), new Point(4,3));
assertTrue(theCopy.equals
(new Grid([[11,21,31],
[12,22,32]])));
assertTrue(theCopy.width == 3);
assertTrue(theCopy.depth == 2);
}
public function testCopy2() {
var grid = new Grid([[00,10,20,30],
[01,11,21,31],
[02,12,22,32],
[03,13,23,33],
[04,14,24,34]], 4, 5);
// copy a 1x1 point
var theCopy = grid.copy(new Point(1,2), new Point(2,3));
assertTrue(theCopy.equals(new Grid([[12]])));
assertTrue(theCopy.width == 1);
assertTrue(theCopy.depth == 1);
// copy a 1x1 point on bottom
var theCopy = grid.copy(new Point(1,4), new Point(2,5));
assertTrue(theCopy.equals(new Grid([[14]])));
assertTrue(theCopy.width == 1);
assertTrue(theCopy.depth == 1);
// copy a 2x1 point on bottom
var theCopy = grid.copy(new Point(1,4), new Point(3,5));
assertTrue(theCopy.equals(new Grid([[14,24]], 2, 1)));
assertTrue(theCopy.width == 2);
assertTrue(theCopy.depth == 1);
}
public function testCount() {
assertTrue(new Grid([[X,X],
[X,X]])
.count(X) == 4);
assertTrue(new Grid([[X,_],
[_,X]])
.count(X) == 2);
assertTrue(new Grid([[_,_],
[_,_]])
.count(X) == 0);
}
}
class Pentomino
{
static var _ = 0;
static var X = 1;
// names from http://en.wikipedia.org/wiki/Pentomino
public static var SHAPES = [
// the L/Q
[[ _,_,_,_ ],
[ X,_,_,_ ],
[ X,X,X,X ],
[ _,_,_,_ ]],
// the Y
[[ _,_,_,_ ],
[ _,X,_,_ ],
[ X,X,X,X ],
[ _,_,_,_ ]],
// the X
[[ _,X,_ ],
[ X,X,X ],
[ _,X,_ ]],
// the V
[[ _,_,X ],
[ _,_,X ],
[ X,X,X ]],
// the Z
[[ _,_,_,_ ],
[ _,_,_,X ],
[ _,X,X,X ],
[ _,X,_,_ ]],
// the W
[[ _,_,X ],
[ _,X,X ],
[ X,X,_ ]],
// the I/O
[[_,_,_,_,_],
[_,_,_,_,_],
[X,X,X,X,X],
[_,_,_,_,_],
[_,_,_,_,_]],
// the T;
[[ _,_,X ],
[ X,X,X ],
[ _,_,X ]],
// the U
[[X,_,X],
[X,X,X],
[_,_,_]],
// the N/S
[[_,_,_,_,_],
[_,_,_,_,_],
[_,X,X,_,_],
[_,_,X,X,X],
[_,_,_,_,_]],
// the P
[[ _,_,_ ],
[ _,X,X ],
[ X,X,X ]],
// the F/R
[[ _,X,_ ],
[ _,X,X ],
[ X,X,_ ]]
];
public static function atRandom()
{
return SHAPES[Math.floor(Math.random() * Pentomino.SHAPES.length)];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment