protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { int smallestSize = BoardState.Height * BoardState.Width + 1; resultBitmap = null; resultX = 0; resultY = 0; //TODO: If we weren't a singleton we could track our used Width/Height int currentHeight = CalcUsedHeight(ref board); int currentWidth = CalcUsedWidth(ref board); //Console.WriteLine($"Current {currentWidth}x{currentHeight}"); for (var x = 0; x < BoardState.Width; x++) { for (var y = 0; y < BoardState.Height; y++) { foreach (var bitmap in piece.PossibleOrientations) { var size = Math.Max(currentWidth, x + bitmap.Width) * Math.Max(currentHeight, y + bitmap.Height); if (size < smallestSize && x + bitmap.Width <= BoardState.Width && y + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, x, y)) { smallestSize = size; resultBitmap = bitmap; resultX = x; resultY = y; } } } } return(resultBitmap != null); }
// to spawn a new object dropping out of the box by gravity public void spawnNew(PieceDefinition pd, Vector3 pos, float dropSpeed, int skinNum) { isActive = true; piece = new GamePiece(pd, this, skinNum, position - pos); piece.init(); applyTweening(dropSpeed); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int x, out int y) { for (var oppositeWallGap = 0; oppositeWallGap < BoardState.Width; oppositeWallGap++) { //TODO: Could use the minimum of the size of the sides of the bitmap in this gap < part to skip some wasteful loops for (var gap = 0; gap < BoardState.Height; gap++) { foreach (var bitmap in piece.PossibleOrientations) { //Try place in x direction if (gap + bitmap.Width <= BoardState.Width && oppositeWallGap + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, gap, oppositeWallGap)) { resultBitmap = bitmap; x = gap; y = oppositeWallGap; return(true); } //Try place in y direction if (oppositeWallGap + bitmap.Width <= BoardState.Width && gap + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, oppositeWallGap, gap)) { resultBitmap = bitmap; x = oppositeWallGap; y = gap; return(true); } } } } resultBitmap = null; x = -1; y = -1; return(false); }
public GamePiece(PieceDefinition newPd, Board newMaster, int type, Vector3 newPosition) { pd = newPd; //Debug.Log(pd); master = newMaster; slotNum = type; position = newPosition; }
public void PlayerPlacedPiece(int player, PieceDefinition piece, int x, int y, PieceBitmap bitmap) { Console.WriteLine($"Player {player} placed {piece.Name} at {x},{y}"); if (PrintBoardsAfterPlacement) { PrintBoards(true); } }
// converts a piece that is here to be a special piece public void convertToSpecial(PieceDefinition pd) { if (isFilled) { piece.pd.performPower(arrayRef); // trigger specials if any } piece.destroy(0); piece.specialMe(pd); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { resultBitmap = null; resultX = -1; resultY = -1; //TODO: We could do better with a good tiebreaker int bestScore = int.MaxValue; int tieBreakerScore = int.MaxValue; int tiedForBest = 0; foreach (var bitmap in piece.PossibleOrientations) { for (int x = 0; x < BoardState.Width - bitmap.Width + 1; x++) { for (int y = 0; y < BoardState.Height - bitmap.Height + 1; y++) { if (board.CanPlace(bitmap, x, y)) { CalculateScore(board, bitmap, x, y, _doubler, out var score); if (score < bestScore) { bestScore = score; tieBreakerScore = x + y; resultBitmap = bitmap; resultX = x; resultY = y; tiedForBest = 0; } else if (score == bestScore) { tiedForBest++; int ourTieBreaker = x + y; if (ourTieBreaker < tieBreakerScore) { //Console.WriteLine("Beat the tie"); tieBreakerScore = ourTieBreaker; resultBitmap = bitmap; resultX = x; resultY = y; } } } } } } //if (tiedForBest > 0) // Console.WriteLine($"{_doubler} {tiedForBest}"); return(resultBitmap != null); }
public override void Reason() { if (!pieceProvided) { def = _context.nextQueue.GetNext(); pieceProvided = false; } _context.piece = _context.playfield.SpawnTileGroup(def, _context.spawnLocation); _machine.ChangeState <StateGravitate>().AddLine(); }
// for board reset when no more moves public void resetMe(PieceDefinition pieceType, int skinNum) { if (pd.ignoreReset) { // non-resettable piece return; } pd = pieceType; Debug.Log(pd.name); slotNum = skinNum; dressMe(); }
public void TwoPossibleOrientations() { var piece = new PieceDefinition("test", 0, 0, 0, new[] { "##" }); Assert.Equal(2, piece.PossibleOrientations.Length); Assert.Equal(2, piece.TotalUsedLocations); }
public void SinglePossibleOrientation() { var piece = new PieceDefinition("test", 0, 0, 0, new[] { "#" }); Assert.Single(piece.PossibleOrientations); Assert.Equal(1, piece.TotalUsedLocations); }
// spawn a new piece on the boar d itself (appear mode) which scales from small to big public void spawnNewAppear(PieceDefinition pd, float appearSpeed, int skinNum) { isActive = true; piece = new GamePiece(pd, this, skinNum, position); piece.init(); LeanTween.cancel(piece.thisPiece); // cancel any active tweens on this object float scaleSize = 0; scaleSize = piece.thisPiece.transform.localScale.x; piece.thisPiece.transform.localScale = Vector3.zero; // appear from scale 0 LeanTween.value(piece.thisPiece, appearTweeningSubFunction, 0f, scaleSize, appearSpeed).setOnUpdateParam(piece.thisPiece); }
// sets the piece that is here to be a special piece public void setSpecialPiece(PieceDefinition pd) { if (panel.pnd.hasStartingPiece) { piece.removePiece(1); if (pd.isSpecial) { // if it's a special type, define the appropriate skin piece.slotNum = pd.skinToUseDuringSpawn(arrayRef[0], arrayRef[1]); } piece.pd = pd; // sets the pd type } }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { var holes = new List <int>(); int leastHoles = BoardState.Width * BoardState.Height; int largestHoleSize = 0; resultBitmap = null; resultX = -1; resultY = -1; //TODO: Distance could be < the piece size too for (var distance = 0; distance < BoardState.Width + BoardState.Height; distance++) { //TODO: Min(distance, Width - bitmap.MinSideSize) ? for (var x = 0; x <= distance; x++) { var y = distance - x; foreach (var bitmap in piece.PossibleOrientations) { if (x + bitmap.Width <= BoardState.Width && y + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, x, y)) { var clone = board; clone.Place(bitmap, x, y); holes.Clear(); PlacementHelper.HoleCount(clone, ref holes); //TODO: No Linq if (holes.Count < leastHoles || (holes.Count == leastHoles && holes.Max() > largestHoleSize)) { leastHoles = holes.Count; largestHoleSize = holes.Max(); resultBitmap = bitmap; resultX = x; resultY = y; } } } } if (resultBitmap != null) { return(true); } } return(false); }
public override bool powerMatched(int posX1, int posY1, int posX2, int posY2, bool execute, PieceDefinition thisPd, PieceDefinition otherPd) { if (otherPd.isDestructible) { if (execute) { StartCoroutine(doPower6Merge(posX1, posY1, posX2, posY2)); // match 6 type power ( clears the entire board ) } return(true); } return(false); }
// for external scripts to call, destroys the game piece with validation checks public void destroy(int i) { if (pd != null) { if (!pd.isSpecial) { // not a special piece... it is a colored piece master.gm.matchCount[slotNum]++; // increase the type count that is destroyed. } pd.onPieceDestroyed(this); // call the piece type onDestroy function (if any) pd = null; // null the piece attribute here master.gm.animScript.doAnim(animType.GLOBALDESTROY, master.arrayRef[0], master.arrayRef[1]); } destroyCall(i); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { _evaluator.BeginEvaluation(board); resultBitmap = null; resultX = -1; resultY = -1; int bestScore = int.MinValue; //Exhaustively place it and make new child nodes for (var index = 0; index < piece.PossibleOrientations.Length; index++) { var bitmap = piece.PossibleOrientations[index]; var searchWidth = BoardState.Width - bitmap.Width + 1; var searchHeight = BoardState.Height - bitmap.Height + 1; //TODO? If this is the first piece, remove mirrors/rotations from the children //if (isFirstPiece) //{ // //TODO: This doesn't stop diagonal mirrors // searchWidth = (BoardState.Width - bitmap.Width) / 2 + 1; // searchHeight = (BoardState.Height - bitmap.Height) / 2 + 1; //} for (int x = 0; x < searchWidth; x++) { for (int y = 0; y < searchHeight; y++) { if (board.CanPlace(bitmap, x, y)) { var clone = board; clone.Place(bitmap, x, y); var score = _evaluator.Evaluate(in clone, x, x + bitmap.Width, y, y + bitmap.Height); if (score > bestScore) { resultBitmap = bitmap; resultX = x; resultY = y; bestScore = score; } } } } } return(resultBitmap != null); }
/// <summary> /// Swaps out the internal piece for <paramref name="toHold"/> and outputs <paramref name="swapped"/>. Returns <see langword="true"/> when the swap is successful. /// </summary> /// <param name="toHold"></param> /// <param name="swapped"></param> /// <returns></returns> public bool Swap(PieceDefinition toHold, out PieceDefinition?swapped) { if (isLocked) { swapped = null; return(false); } else { swapped = heldPiece; heldPiece = toHold; isLocked = true; return(true); } }
// reset the board when no more moves public void reset(PieceDefinition pd, int skinNum) { if (panel.isFillable()) { // if the panel can hold a game piece if (isFilled) { piece.resetMe(pd, skinNum); // reset it } else { // game piece was stolen by another board and the reference is wrong. create a new piece piece = new GamePiece(pd, this, skinNum, position); piece.init(); } isFalling = false; isActive = true; } }
/// <summary> /// Finds a placement (Not guaranteed to be any good) for the given piece on the given board /// </summary> public static void GetFirstPlacement(BoardState board, PieceDefinition piece, out PieceBitmap bitmap, out int x, out int y) { for (var index = 0; index < piece.PossibleOrientations.Length; index++) { bitmap = piece.PossibleOrientations[index]; for (y = BoardState.Height - bitmap.Height; y >= 0; y--) { for (x = BoardState.Width - bitmap.Width; x >= 0; x--) { if (board.CanPlace(bitmap, x, y)) { return; } } } } throw new Exception("GetFirstPlacement couldn't find a placement"); }
/// <summary> /// This runs from the highest x/y backwards, as a rule of thumb placement strategies should try place starting at 0,0 so this is likely to finish quicker /// </summary> public static bool CanPlace(BoardState board, PieceDefinition piece) { for (var index = 0; index < piece.PossibleOrientations.Length; index++) { var bitmap = piece.PossibleOrientations[index]; for (var y = BoardState.Height - bitmap.Height; y >= 0; y--) { for (var x = BoardState.Width - bitmap.Width; x >= 0; x--) { if (board.CanPlace(bitmap, x, y)) { return(true); } } } } return(false); }
private void BufferPiece(PieceDefinition piece) { for (var y = 0; y < 5; y++) { for (var x = 0; x < 5; x++) { bool here = false; if (piece.Bitmap.Width > x && piece.Bitmap.Height > y) here = piece.Boolmap[x, y]; _lines[y].Append(here ? '#' : ' '); } _lines[y].Append(" | "); } _lines[5].Append($"$:{piece.ButtonCost.ToString().PadRight(3)} | "); _lines[6].Append($"T:{piece.TimeCost.ToString().PadRight(3)} | "); _lines[7].Append($"+:{piece.ButtonsIncome.ToString().PadRight(3)} | "); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { foreach (var bitmap in piece.PossibleOrientations) { for (var y = 0; y <= BoardState.Height - bitmap.Height; y++) { for (var x = 0; x <= BoardState.Width - bitmap.Width; x++) { if (board.CanPlace(bitmap, x, y)) { resultBitmap = bitmap; resultX = x; resultY = y; return(true); } } } } resultBitmap = null; resultX = -1; resultY = -1; return(false); }
public double CalculateValueOfPurchasing(SimulationState state, int pieceIndex, PieceDefinition piece) { var offset = OffsetForPosition(state); var value = piece.TotalUsedLocations * _value[offset + UsedLocationUtilityOffset]; value += piece.ButtonCost * _value[offset + ButtonCostUtilityOffset]; value += piece.TimeCost * _value[offset + TimeCostUtilityOffset]; //TODO: Should we have piece income and total income utilities? value += SimulationHelpers.ButtonIncomeAmountAfterPosition(state.PlayerPosition[state.ActivePlayer]) * piece.ButtonsIncome * _value[offset + IncomeUtilityOffset]; value += SimulationHelpers.ButtonIncomeAmountAfterPosition(state.PlayerPosition[state.ActivePlayer]) * piece.ButtonsIncome * piece.ButtonsIncome * _value[offset + IncomeSquaredUtilityOffset]; //TODO: Should this be boolean or vary by difference in location? if (state.PlayerPosition[state.NonActivePlayer] >= (state.PlayerPosition[state.ActivePlayer] + piece.TimeCost)) { value += _value[offset + GetAnotherTurnUtilityOffset]; } //TODO: Should this be boolean or vary by income amount? if (SimulationHelpers.ButtonIncomeAmountAfterPosition(state.PlayerPosition[state.ActivePlayer]) != SimulationHelpers.ButtonIncomeAmountAfterPosition(Math.Min(SimulationState.EndLocation, state.PlayerPosition[state.ActivePlayer] + piece.TimeCost))) { value += _value[offset + ReceiveIncomeUtilityOffset]; } return(value); //TODO Clamp? Divide by total utilities? }
// old powerMatched function.. public virtual bool powerMatched(int posX1, int posY1, int posX2, int posY2, bool execute, PieceDefinition pdMain, PieceDefinition pdSub) { return(false); // default is nothing.. }
public void PlayerPurchasedPiece(int player, PieceDefinition piece) { _turn++; Console.WriteLine($"{_turn}) Player {player} purchased {piece.Name}"); }
public bool TryPlacePiece(BoardState board, PieceDefinition piece, in PieceCollection possibleFuturePieces, int possibleFuturePiecesOffset, out PieceBitmap bitmap, out int x, out int y)
public double CalculateValueOfPurchasing(SimulationState state, int pieceIndex, PieceDefinition piece) { return(1); }
protected abstract double CalculateValue(SimulationState state, int pieceIndex, PieceDefinition piece);
protected override double CalculateValue(SimulationState state, int pieceIndex, PieceDefinition piece) { return(_calculator.CalculateValueOfPurchasing(state, pieceIndex, piece)); }