Skip to content

Instantly share code, notes, and snippets.

@arturaz
Created July 16, 2018 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arturaz/9ac42bec25b5e3386cd47169de9f0f67 to your computer and use it in GitHub Desktop.
Save arturaz/9ac42bec25b5e3386cd47169de9f0f67 to your computer and use it in GitHub Desktop.
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