Created
July 16, 2018 19:08
-
-
Save arturaz/9ac42bec25b5e3386cd47169de9f0f67 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.Collections.Immutable; | |
using System.Linq; | |
using com.tinylabproductions.TLPLib.Collection; | |
using com.tinylabproductions.TLPLib.Data; | |
using com.tinylabproductions.TLPLib.Extensions; | |
using com.tinylabproductions.TLPLib.Functional; | |
using com.tinylabproductions.TLPLib.Utilities; | |
namespace game.code.models { | |
public class Board { | |
// Board is rectangular. | |
const int DIMENSIONS = 18; | |
static readonly NonEmpty<ImmutableArray<int>> DOUBLING_SPOT_INDEXES = NonEmpty.array(2, 8, 9, 15); | |
static readonly NonEmpty<ImmutableArray<Point2D>> STARTING_POINTS = NonEmpty.array( | |
new Point2D(8, 8), new Point2D(9, 8), | |
new Point2D(8, 9), new Point2D(9, 9) | |
); | |
readonly Dictionary<Point2D, RotatedTilePart> board = new Dictionary<Point2D, RotatedTilePart>(); | |
public bool satisfies(Point2D point, Fn<RotatedTilePart, bool> predicate) => | |
board.get(point).valueOut(out var part) && predicate(part); | |
public bool connectsDown(Point2D point) => satisfies(point, _ => _.connectsDown()); | |
public bool connectsUp(Point2D point) => satisfies(point, _ => _.connectsUp()); | |
public bool connectsLeft(Point2D point) => satisfies(point, _ => _.connectsLeft()); | |
public bool connectsRight(Point2D point) => satisfies(point, _ => _.connectsRight()); | |
public bool isEmpty(Point2D point) => !board.ContainsKey(point); | |
public bool canPlace(Option<RotatedTilePart> maybePart, Point2D point, out bool connectsToBoard) { | |
if (board.ContainsKey(point)) { | |
connectsToBoard = false; | |
return false; | |
} | |
var canConnectUp = connectsDown(point.up); | |
var canConnectRight = connectsLeft(point.right); | |
var canConnectDown = connectsUp(point.down); | |
var canConnectLeft = connectsRight(point.left); | |
if (maybePart.valueOut(out var part)) { | |
var connectsUp = part.connectsUp() == canConnectUp; | |
var connectsRight = part.connectsRight() == canConnectRight; | |
var connectsDown = part.connectsDown() == canConnectDown; | |
var connectsLeft = part.connectsLeft() == canConnectLeft; | |
connectsToBoard = connectsUp || connectsRight || connectsDown || connectsLeft; | |
return (connectsUp || isEmpty(point.up)) | |
&& (connectsRight || isEmpty(point.right)) | |
&& (connectsDown || isEmpty(point.down)) | |
&& (connectsLeft || isEmpty(point.left)); | |
} | |
else { | |
// Empty tile does not connect with anything | |
connectsToBoard = false; | |
return !canConnectUp | |
&& !canConnectLeft | |
&& !canConnectDown | |
&& !canConnectRight; | |
} | |
} | |
static Option<RotatedTilePart> map(Option<TilePart> maybeTilePart, Rotation rotation) => | |
maybeTilePart.valueOut(out var part) | |
? F.some(new RotatedTilePart(part, rotation)) | |
: F.none_; | |
public bool isValid(Point2D position, Tile tile, Rotation rotation) => | |
isValid( | |
new TilePositions(position, rotation), | |
map(tile.part1, rotation), map(tile.part2, rotation), map(tile.part3, rotation) | |
); | |
public bool isValid( | |
TilePositions positions, | |
Option<RotatedTilePart> t1, Option<RotatedTilePart> t2, Option<RotatedTilePart> t3 | |
) { | |
if (!positions.within(DIMENSIONS)) return false; | |
if (board.isEmpty()) return positions.matchesAnyOf(STARTING_POINTS); | |
return | |
canPlace(t1, positions.part1, out var p1ConnectsToBoard) | |
&& canPlace(t2, positions.part2, out var p2ConnectsToBoard) | |
&& canPlace(t3, positions.part3, out var p3ConnectsToBoard) | |
&& (p1ConnectsToBoard || p2ConnectsToBoard || p3ConnectsToBoard); | |
} | |
public void apply(Point2D position, Tile tile, Rotation rotation) { | |
var positions = new TilePositions(position, rotation); | |
var t1 = map(tile.part1, rotation); | |
var t2 = map(tile.part2, rotation); | |
var t3 = map(tile.part3, rotation); | |
if (!isValid(positions, t1, t2, t3)) throw new ArgumentException(); | |
foreach (var t in t1) board.Add(positions.part1, t); | |
foreach (var t in t2) board.Add(positions.part2, t); | |
foreach (var t in t3) board.Add(positions.part3, t); | |
} | |
public void possibleToPlacements(Tile tile, List<RotatedTile> outTo) { | |
outTo.Clear(); | |
for (var x = 0; x < DIMENSIONS; x++) { | |
for (var y = 0; y < DIMENSIONS; y++) { | |
foreach (var rotation in EnumUtils.GetValues<Rotation>()) { | |
var position = new Point2D(x, y); | |
if (isValid(position, tile, rotation)) { | |
outTo.Add(new RotatedTile(tile, rotation)); | |
} | |
} | |
} | |
} | |
} | |
public Score playerAScore => score(true); | |
public Score playerBScore => score(false); | |
public Score score(bool playerA) { | |
Fn<int, bool> | |
checkA = | |
playerA | |
? new Fn<int, bool>(_idx => connectsDown(new Point2D(_idx, 0))) | |
: _idx => connectsLeft(new Point2D(0, _idx)), | |
checkB = | |
playerA | |
? new Fn<int, bool>(_idx => connectsUp(new Point2D(_idx, DIMENSIONS - 1))) | |
: _idx => connectsRight(new Point2D(DIMENSIONS - 1, _idx)); | |
uint pointsFor(int idx) => DOUBLING_SPOT_INDEXES.a.Contains(idx) ? 2u : 1; | |
uint sideA = 0, sideB = 0; | |
for (var idx = 0; idx < DIMENSIONS; idx++) { | |
if (checkA(idx)) sideA += pointsFor(idx); | |
if (checkB(idx)) sideB += pointsFor(idx); | |
} | |
return new Score(sideA, sideB); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment