// Generated code -- CC0 -- No Rights Reserved -- http://www.redblobgames.com/grids/hexagons/








class Point
{
    public function new(x:Float, y:Float)
    {
        this.x = x;
        this.y = y;
    }
    public var x:Float;
    public var y:Float;
}

class Hex
{
    public function new(q:Int, r:Int, s:Int)
    {
        this.q = q;
        this.r = r;
        this.s = s;
        if (q + r + s != 0) throw "q + r + s must be 0";
    }
    public var q:Int;
    public var r:Int;
    public var s:Int;

    static public function add(a:Hex, b:Hex):Hex
    {
        return new Hex(a.q + b.q, a.r + b.r, a.s + b.s);
    }


    static public function subtract(a:Hex, b:Hex):Hex
    {
        return new Hex(a.q - b.q, a.r - b.r, a.s - b.s);
    }


    static public function scale(a:Hex, k:Int):Hex
    {
        return new Hex(a.q * k, a.r * k, a.s * k);
    }


    static public function rotateLeft(a:Hex):Hex
    {
        return new Hex(-a.s, -a.q, -a.r);
    }


    static public function rotateRight(a:Hex):Hex
    {
        return new Hex(-a.r, -a.s, -a.q);
    }

    static public var directions:Array<Hex> = [new Hex(1, 0, -1), new Hex(1, -1, 0), new Hex(0, -1, 1), new Hex(-1, 0, 1), new Hex(-1, 1, 0), new Hex(0, 1, -1)];

    static public function direction(direction:Int):Hex
    {
        return Hex.directions[direction];
    }


    static public function neighbor(hex:Hex, direction:Int):Hex
    {
        return Hex.add(hex, Hex.direction(direction));
    }

    static public var diagonals:Array<Hex> = [new Hex(2, -1, -1), new Hex(1, -2, 1), new Hex(-1, -1, 2), new Hex(-2, 1, 1), new Hex(-1, 2, -1), new Hex(1, 1, -2)];

    static public function diagonalNeighbor(hex:Hex, direction:Int):Hex
    {
        return Hex.add(hex, Hex.diagonals[direction]);
    }


    static public function length(hex:Hex):Int
    {
        return Std.int((Math.abs(hex.q) + Math.abs(hex.r) + Math.abs(hex.s)) / 2);
    }


    static public function distance(a:Hex, b:Hex):Int
    {
        return Hex.length(Hex.subtract(a, b));
    }

}

class FractionalHex
{
    public function new(q:Float, r:Float, s:Float)
    {
        this.q = q;
        this.r = r;
        this.s = s;
        if (Math.round(q + r + s) != 0) throw "q + r + s must be 0";
    }
    public var q:Float;
    public var r:Float;
    public var s:Float;

    static public function hexRound(h:FractionalHex):Hex
    {
        var qi:Int = Math.round(h.q);
        var ri:Int = Math.round(h.r);
        var si:Int = Math.round(h.s);
        var q_diff:Float = Math.abs(qi - h.q);
        var r_diff:Float = Math.abs(ri - h.r);
        var s_diff:Float = Math.abs(si - h.s);
        if (q_diff > r_diff && q_diff > s_diff)
        {
            qi = -ri - si;
        }
        else
            if (r_diff > s_diff)
            {
                ri = -qi - si;
            }
            else
            {
                si = -qi - ri;
            }
        return new Hex(qi, ri, si);
    }


    static public function hexLerp(a:FractionalHex, b:FractionalHex, t:Float):FractionalHex
    {
        return new FractionalHex(a.q * (1.0 - t) + b.q * t, a.r * (1.0 - t) + b.r * t, a.s * (1.0 - t) + b.s * t);
    }


    static public function hexLinedraw(a:Hex, b:Hex):Array<Hex>
    {
        var N:Int = Hex.distance(a, b);
        var a_nudge:FractionalHex = new FractionalHex(a.q + 1e-06, a.r + 1e-06, a.s - 2e-06);
        var b_nudge:FractionalHex = new FractionalHex(b.q + 1e-06, b.r + 1e-06, b.s - 2e-06);
        var results:Array<Hex> = [];
        var step:Float = 1.0 / Math.max(N, 1);
        for (i in 0...N + 1)
        {
            results.push(FractionalHex.hexRound(FractionalHex.hexLerp(a_nudge, b_nudge, step * i)));
        }
        return results;
    }

}

class OffsetCoord
{
    public function new(col:Int, row:Int)
    {
        this.col = col;
        this.row = row;
    }
    public var col:Int;
    public var row:Int;
    static public var EVEN:Int = 1;
    static public var ODD:Int = -1;

    static public function qoffsetFromCube(offset:Int, h:Hex):OffsetCoord
    {
        var parity:Int = h.q & 1;
        var col:Int = h.q;
        var row:Int = h.r + Std.int((h.q + offset * parity) / 2);
        if (offset != OffsetCoord.EVEN && offset != OffsetCoord.ODD)
        {
            throw "offset must be EVEN (+1) or ODD (-1)";
        }
        return new OffsetCoord(col, row);
    }


    static public function qoffsetToCube(offset:Int, h:OffsetCoord):Hex
    {
        var parity:Int = h.col & 1;
        var q:Int = h.col;
        var r:Int = h.row - Std.int((h.col + offset * parity) / 2);
        var s:Int = -q - r;
        if (offset != OffsetCoord.EVEN && offset != OffsetCoord.ODD)
        {
            throw "offset must be EVEN (+1) or ODD (-1)";
        }
        return new Hex(q, r, s);
    }


    static public function roffsetFromCube(offset:Int, h:Hex):OffsetCoord
    {
        var parity:Int = h.r & 1;
        var col:Int = h.q + Std.int((h.r + offset * parity) / 2);
        var row:Int = h.r;
        if (offset != OffsetCoord.EVEN && offset != OffsetCoord.ODD)
        {
            throw "offset must be EVEN (+1) or ODD (-1)";
        }
        return new OffsetCoord(col, row);
    }


    static public function roffsetToCube(offset:Int, h:OffsetCoord):Hex
    {
        var parity:Int = h.row & 1;
        var q:Int = h.col - Std.int((h.row + offset * parity) / 2);
        var r:Int = h.row;
        var s:Int = -q - r;
        if (offset != OffsetCoord.EVEN && offset != OffsetCoord.ODD)
        {
            throw "offset must be EVEN (+1) or ODD (-1)";
        }
        return new Hex(q, r, s);
    }


    static public function qoffsetFromQdoubled(offset:Int, h:DoubledCoord):OffsetCoord
    {
        var parity:Int = h.col & 1;
        return new OffsetCoord(h.col, Std.int((h.row + offset * parity) / 2));
    }


    static public function qoffsetToQdoubled(offset:Int, h:OffsetCoord):DoubledCoord
    {
        var parity:Int = h.col & 1;
        return new DoubledCoord(h.col, 2 * h.row - offset * parity);
    }


    static public function roffsetFromRdoubled(offset:Int, h:DoubledCoord):OffsetCoord
    {
        var parity:Int = h.row & 1;
        return new OffsetCoord(Std.int((h.col + offset * parity) / 2), h.row);
    }


    static public function roffsetToRdoubled(offset:Int, h:OffsetCoord):DoubledCoord
    {
        var parity:Int = h.row & 1;
        return new DoubledCoord(2 * h.col - offset * parity, h.row);
    }

}

class DoubledCoord
{
    public function new(col:Int, row:Int)
    {
        this.col = col;
        this.row = row;
    }
    public var col:Int;
    public var row:Int;

    static public function qdoubledFromCube(h:Hex):DoubledCoord
    {
        var col:Int = h.q;
        var row:Int = 2 * h.r + h.q;
        return new DoubledCoord(col, row);
    }


    static public function qdoubledToCube(h:DoubledCoord):Hex
    {
        var q:Int = h.col;
        var r:Int = Std.int((h.row - h.col) / 2);
        var s:Int = -q - r;
        return new Hex(q, r, s);
    }


    static public function rdoubledFromCube(h:Hex):DoubledCoord
    {
        var col:Int = 2 * h.q + h.r;
        var row:Int = h.r;
        return new DoubledCoord(col, row);
    }


    static public function rdoubledToCube(h:DoubledCoord):Hex
    {
        var q:Int = Std.int((h.col - h.row) / 2);
        var r:Int = h.row;
        var s:Int = -q - r;
        return new Hex(q, r, s);
    }

}

class Orientation
{
    public function new(f0:Float, f1:Float, f2:Float, f3:Float, b0:Float, b1:Float, b2:Float, b3:Float, start_angle:Float)
    {
        this.f0 = f0;
        this.f1 = f1;
        this.f2 = f2;
        this.f3 = f3;
        this.b0 = b0;
        this.b1 = b1;
        this.b2 = b2;
        this.b3 = b3;
        this.start_angle = start_angle;
    }
    public var f0:Float;
    public var f1:Float;
    public var f2:Float;
    public var f3:Float;
    public var b0:Float;
    public var b1:Float;
    public var b2:Float;
    public var b3:Float;
    public var start_angle:Float;
}

class Layout
{
    public function new(orientation:Orientation, size:Point, origin:Point)
    {
        this.orientation = orientation;
        this.size = size;
        this.origin = origin;
    }
    public var orientation:Orientation;
    public var size:Point;
    public var origin:Point;
    static public var pointy:Orientation = new Orientation(Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0, Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0, 0.5);
    static public var flat:Orientation = new Orientation(3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0), 2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0, 0.0);

    static public function hexToPixel(layout:Layout, h:Hex):Point
    {
        var M:Orientation = layout.orientation;
        var size:Point = layout.size;
        var origin:Point = layout.origin;
        var x:Float = (M.f0 * h.q + M.f1 * h.r) * size.x;
        var y:Float = (M.f2 * h.q + M.f3 * h.r) * size.y;
        return new Point(x + origin.x, y + origin.y);
    }


    static public function pixelToHexFractional(layout:Layout, p:Point):FractionalHex
    {
        var M:Orientation = layout.orientation;
        var size:Point = layout.size;
        var origin:Point = layout.origin;
        var pt:Point = new Point((p.x - origin.x) / size.x, (p.y - origin.y) / size.y);
        var q:Float = M.b0 * pt.x + M.b1 * pt.y;
        var r:Float = M.b2 * pt.x + M.b3 * pt.y;
        return new FractionalHex(q, r, -q - r);
    }


    static public function pixelToHexRounded(layout:Layout, p:Point):Hex
    {
        return FractionalHex.hexRound(Layout.pixelToHexFractional(layout, p));
    }


    static public function hexCornerOffset(layout:Layout, corner:Int):Point
    {
        var M:Orientation = layout.orientation;
        var size:Point = layout.size;
        var angle:Float = 2.0 * Math.PI * (M.start_angle - corner) / 6.0;
        return new Point(size.x * Math.cos(angle), size.y * Math.sin(angle));
    }


    static public function polygonCorners(layout:Layout, h:Hex):Array<Point>
    {
        var corners:Array<Point> = [];
        var center:Point = Layout.hexToPixel(layout, h);
        for (i in 0...6)
        {
            var offset:Point = Layout.hexCornerOffset(layout, i);
            corners.push(new Point(center.x + offset.x, center.y + offset.y));
        }
        return corners;
    }

}



// Tests


class Tests
{
    public function new()
    {
    }

    static public function equalHex(name:String, a:Hex, b:Hex):Void
    {
        if (!(a.q == b.q && a.s == b.s && a.r == b.r))
        {
            Tests.complain(name);
        }
    }


    static public function equalOffsetcoord(name:String, a:OffsetCoord, b:OffsetCoord):Void
    {
        if (!(a.col == b.col && a.row == b.row))
        {
            Tests.complain(name);
        }
    }


    static public function equalDoubledcoord(name:String, a:DoubledCoord, b:DoubledCoord):Void
    {
        if (!(a.col == b.col && a.row == b.row))
        {
            Tests.complain(name);
        }
    }


    static public function equalInt(name:String, a:Int, b:Int):Void
    {
        if (!(a == b))
        {
            Tests.complain(name);
        }
    }


    static public function equalHexArray(name:String, a:Array<Hex>, b:Array<Hex>):Void
    {
        Tests.equalInt(name, a.length, b.length);
        for (i in 0...a.length)
        {
            Tests.equalHex(name, a[i], b[i]);
        }
    }


    static public function testHexArithmetic():Void
    {
        Tests.equalHex("hex_add", new Hex(4, -10, 6), Hex.add(new Hex(1, -3, 2), new Hex(3, -7, 4)));
        Tests.equalHex("hex_subtract", new Hex(-2, 4, -2), Hex.subtract(new Hex(1, -3, 2), new Hex(3, -7, 4)));
    }


    static public function testHexDirection():Void
    {
        Tests.equalHex("hex_direction", new Hex(0, -1, 1), Hex.direction(2));
    }


    static public function testHexNeighbor():Void
    {
        Tests.equalHex("hex_neighbor", new Hex(1, -3, 2), Hex.neighbor(new Hex(1, -2, 1), 2));
    }


    static public function testHexDiagonal():Void
    {
        Tests.equalHex("hex_diagonal", new Hex(-1, -1, 2), Hex.diagonalNeighbor(new Hex(1, -2, 1), 3));
    }


    static public function testHexDistance():Void
    {
        Tests.equalInt("hex_distance", 7, Hex.distance(new Hex(3, -7, 4), new Hex(0, 0, 0)));
    }


    static public function testHexRotateRight():Void
    {
        Tests.equalHex("hex_rotate_right", Hex.rotateRight(new Hex(1, -3, 2)), new Hex(3, -2, -1));
    }


    static public function testHexRotateLeft():Void
    {
        Tests.equalHex("hex_rotate_left", Hex.rotateLeft(new Hex(1, -3, 2)), new Hex(-2, -1, 3));
    }


    static public function testHexRound():Void
    {
        var a:FractionalHex = new FractionalHex(0.0, 0.0, 0.0);
        var b:FractionalHex = new FractionalHex(1.0, -1.0, 0.0);
        var c:FractionalHex = new FractionalHex(0.0, -1.0, 1.0);
        Tests.equalHex("hex_round 1", new Hex(5, -10, 5), FractionalHex.hexRound(FractionalHex.hexLerp(new FractionalHex(0.0, 0.0, 0.0), new FractionalHex(10.0, -20.0, 10.0), 0.5)));
        Tests.equalHex("hex_round 2", FractionalHex.hexRound(a), FractionalHex.hexRound(FractionalHex.hexLerp(a, b, 0.499)));
        Tests.equalHex("hex_round 3", FractionalHex.hexRound(b), FractionalHex.hexRound(FractionalHex.hexLerp(a, b, 0.501)));
        Tests.equalHex("hex_round 4", FractionalHex.hexRound(a), FractionalHex.hexRound(new FractionalHex(a.q * 0.4 + b.q * 0.3 + c.q * 0.3, a.r * 0.4 + b.r * 0.3 + c.r * 0.3, a.s * 0.4 + b.s * 0.3 + c.s * 0.3)));
        Tests.equalHex("hex_round 5", FractionalHex.hexRound(c), FractionalHex.hexRound(new FractionalHex(a.q * 0.3 + b.q * 0.3 + c.q * 0.4, a.r * 0.3 + b.r * 0.3 + c.r * 0.4, a.s * 0.3 + b.s * 0.3 + c.s * 0.4)));
    }


    static public function testHexLinedraw():Void
    {
        Tests.equalHexArray("hex_linedraw", [new Hex(0, 0, 0), new Hex(0, -1, 1), new Hex(0, -2, 2), new Hex(1, -3, 2), new Hex(1, -4, 3), new Hex(1, -5, 4)], FractionalHex.hexLinedraw(new Hex(0, 0, 0), new Hex(1, -5, 4)));
    }


    static public function testLayout():Void
    {
        var h:Hex = new Hex(3, 4, -7);
        var flat:Layout = new Layout(Layout.flat, new Point(10.0, 15.0), new Point(35.0, 71.0));
        Tests.equalHex("layout", h, Layout.pixelToHexRounded(flat, Layout.hexToPixel(flat, h)));
        var pointy:Layout = new Layout(Layout.pointy, new Point(10.0, 15.0), new Point(35.0, 71.0));
        Tests.equalHex("layout", h, Layout.pixelToHexRounded(pointy, Layout.hexToPixel(pointy, h)));
    }


    static public function testOffsetRoundtrip():Void
    {
        for (q in -2...3)
        {
            for (r in -2...3)
            {
                var cube:Hex = new Hex(q, r, -q - r);
                Tests.equalHex("conversion_roundtrip odd-q", cube, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, cube)));
                Tests.equalHex("conversion_roundtrip odd-r", cube, OffsetCoord.roffsetToCube(OffsetCoord.ODD, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, cube)));
                Tests.equalHex("conversion_roundtrip even-q", cube, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, cube)));
                Tests.equalHex("conversion_roundtrip even-r", cube, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, cube)));
            }
        }
        for (col in -2...3)
        {
            for (row in -2...3)
            {
                var offset:OffsetCoord = new OffsetCoord(col, row);
                Tests.equalOffsetcoord("conversion_roundtrip odd-q", offset, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, offset)));
                Tests.equalOffsetcoord("conversion_roundtrip odd-r", offset, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, OffsetCoord.roffsetToCube(OffsetCoord.ODD, offset)));
                Tests.equalOffsetcoord("conversion_roundtrip even-q", offset, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, offset)));
                Tests.equalOffsetcoord("conversion_roundtrip even-r", offset, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, offset)));
            }
        }
    }


    static public function testOffsetFromCube():Void
    {
        Tests.equalOffsetcoord("offset_from_cube odd-r", new OffsetCoord(-2, 2), OffsetCoord.roffsetFromCube(OffsetCoord.ODD, new Hex(-3, 2, 1)));
        Tests.equalOffsetcoord("offset_from_cube odd-r", new OffsetCoord(1, -1), OffsetCoord.roffsetFromCube(OffsetCoord.ODD, new Hex(2, -1, -1)));
        Tests.equalOffsetcoord("offset_from_cube even-r", new OffsetCoord(-2, 2), OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, new Hex(-3, 2, 1)));
        Tests.equalOffsetcoord("offset_from_cube even-r", new OffsetCoord(2, -1), OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, new Hex(2, -1, -1)));
        Tests.equalOffsetcoord("offset_from_cube odd-q", new OffsetCoord(-2, 2), OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, new Hex(-2, 3, -1)));
        Tests.equalOffsetcoord("offset_from_cube odd-q", new OffsetCoord(-1, -2), OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, new Hex(-1, -1, 2)));
        Tests.equalOffsetcoord("offset_from_cube even-q", new OffsetCoord(-2, 2), OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, new Hex(-2, 3, -1)));
        Tests.equalOffsetcoord("offset_from_cube even-q", new OffsetCoord(-1, -1), OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, new Hex(-1, -1, 2)));
    }


    static public function testOffsetToCube():Void
    {
        Tests.equalHex("offset_to_cube odd-r", new Hex(-3, 2, 1), OffsetCoord.roffsetToCube(OffsetCoord.ODD, new OffsetCoord(-2, 2)));
        Tests.equalHex("offset_to_cube odd-r", new Hex(2, -1, -1), OffsetCoord.roffsetToCube(OffsetCoord.ODD, new OffsetCoord(1, -1)));
        Tests.equalHex("offset_to_cube even-r", new Hex(-3, 2, 1), OffsetCoord.roffsetToCube(OffsetCoord.EVEN, new OffsetCoord(-2, 2)));
        Tests.equalHex("offset_to_cube even-r", new Hex(2, -1, -1), OffsetCoord.roffsetToCube(OffsetCoord.EVEN, new OffsetCoord(2, -1)));
        Tests.equalHex("offset_to_cube odd-q", new Hex(-2, 3, -1), OffsetCoord.qoffsetToCube(OffsetCoord.ODD, new OffsetCoord(-2, 2)));
        Tests.equalHex("offset_to_cube odd-q", new Hex(-1, -1, 2), OffsetCoord.qoffsetToCube(OffsetCoord.ODD, new OffsetCoord(-1, -2)));
        Tests.equalHex("offset_to_cube even-q", new Hex(-2, 3, -1), OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, new OffsetCoord(-2, 2)));
        Tests.equalHex("offset_to_cube even-q", new Hex(-1, -1, 2), OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, new OffsetCoord(-1, -1)));
    }


    static public function testOffsetToDoubled():Void
    {
        for (col in -2...3)
        {
            for (row in -2...3)
            {
                var offset:OffsetCoord = new OffsetCoord(col, row);
                Tests.equalDoubledcoord("offset_to_doubled loop odd-q", DoubledCoord.qdoubledFromCube(OffsetCoord.qoffsetToCube(OffsetCoord.ODD, offset)), OffsetCoord.qoffsetToQdoubled(OffsetCoord.ODD, offset));
                Tests.equalDoubledcoord("offset_to_doubled loop even-q", DoubledCoord.qdoubledFromCube(OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, offset)), OffsetCoord.qoffsetToQdoubled(OffsetCoord.EVEN, offset));
                Tests.equalDoubledcoord("offset_to_doubled loop odd-r", DoubledCoord.rdoubledFromCube(OffsetCoord.roffsetToCube(OffsetCoord.ODD, offset)), OffsetCoord.roffsetToRdoubled(OffsetCoord.ODD, offset));
                Tests.equalDoubledcoord("offset_to_doubled loop even-r", DoubledCoord.rdoubledFromCube(OffsetCoord.roffsetToCube(OffsetCoord.EVEN, offset)), OffsetCoord.roffsetToRdoubled(OffsetCoord.EVEN, offset));
                var qdoubled:DoubledCoord = new DoubledCoord(col * 2 + (row & 1), row);
                Tests.equalOffsetcoord("offset_from_doubled loop odd-q", OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, DoubledCoord.qdoubledToCube(qdoubled)), OffsetCoord.qoffsetFromQdoubled(OffsetCoord.ODD, qdoubled));
                Tests.equalOffsetcoord("offset_from_doubled loop even-q", OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, DoubledCoord.qdoubledToCube(qdoubled)), OffsetCoord.qoffsetFromQdoubled(OffsetCoord.EVEN, qdoubled));
                var rdoubled:DoubledCoord = new DoubledCoord(col, row * 2 + (col & 1));
                Tests.equalOffsetcoord("offset_from_doubled loop odd-r", OffsetCoord.roffsetFromCube(OffsetCoord.ODD, DoubledCoord.rdoubledToCube(rdoubled)), OffsetCoord.roffsetFromRdoubled(OffsetCoord.ODD, rdoubled));
                Tests.equalOffsetcoord("offset_from_doubled loop even-r", OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, DoubledCoord.rdoubledToCube(rdoubled)), OffsetCoord.roffsetFromRdoubled(OffsetCoord.EVEN, rdoubled));
            }
        }
    }


    static public function testOffsetFromDoubled():Void
    {
    }


    static public function testDoubledRoundtrip():Void
    {
        for (q in -2...3)
        {
            for (r in -2...3)
            {
                var cube:Hex = new Hex(q, r, -q - r);
                Tests.equalHex("conversion_roundtrip doubled-q", cube, DoubledCoord.qdoubledToCube(DoubledCoord.qdoubledFromCube(cube)));
                Tests.equalHex("conversion_roundtrip doubled-r", cube, DoubledCoord.rdoubledToCube(DoubledCoord.rdoubledFromCube(cube)));
            }
        }
        for (col in -2...3)
        {
            for (row in -2...3)
            {
                var qdoubled:DoubledCoord = new DoubledCoord(col * 2 + (row & 1), row);
                Tests.equalDoubledcoord("conversion_roundtrip doubled-q", qdoubled, DoubledCoord.qdoubledFromCube(DoubledCoord.qdoubledToCube(qdoubled)));
                var rdoubled:DoubledCoord = new DoubledCoord(col, row * 2 + (col & 1));
                Tests.equalDoubledcoord("conversion_roundtrip doubled-r", rdoubled, DoubledCoord.rdoubledFromCube(DoubledCoord.rdoubledToCube(rdoubled)));
            }
        }
    }


    static public function testDoubledFromCube():Void
    {
        Tests.equalDoubledcoord("doubled_from_cube doubled-q", new DoubledCoord(1, 5), DoubledCoord.qdoubledFromCube(new Hex(1, 2, -3)));
        Tests.equalDoubledcoord("doubled_from_cube doubled-r", new DoubledCoord(4, 2), DoubledCoord.rdoubledFromCube(new Hex(1, 2, -3)));
    }


    static public function testDoubledToCube():Void
    {
        Tests.equalHex("doubled_to_cube doubled-q", new Hex(1, 2, -3), DoubledCoord.qdoubledToCube(new DoubledCoord(1, 5)));
        Tests.equalHex("doubled_to_cube doubled-r", new Hex(1, 2, -3), DoubledCoord.rdoubledToCube(new DoubledCoord(4, 2)));
    }


    static public function testAll():Void
    {
        Tests.testHexArithmetic();
        Tests.testHexDirection();
        Tests.testHexNeighbor();
        Tests.testHexDiagonal();
        Tests.testHexDistance();
        Tests.testHexRotateRight();
        Tests.testHexRotateLeft();
        Tests.testHexRound();
        Tests.testHexLinedraw();
        Tests.testLayout();
        Tests.testOffsetRoundtrip();
        Tests.testOffsetFromCube();
        Tests.testOffsetToCube();
        Tests.testOffsetToDoubled();
        Tests.testOffsetFromDoubled();
        Tests.testDoubledRoundtrip();
        Tests.testDoubledFromCube();
        Tests.testDoubledToCube();
    }


    static public function main():Void
    {
        Tests.testAll();
    }


    static public function complain(name:String):Void
    {
        trace("FAIL ", name);
    }

}

