void AddPiece(Well thisWell, Piece thisPiece) { var orientation = orientations[thisPiece.ID][thisPiece.O]; // this is the top left point in the bounding box of this orientation of this piece var xActual = thisPiece.Position.X + orientation.XMin; var yActual = thisPiece.Position.Y + orientation.YMin; // update the "highestBlue" value to account for newly-placed piece thisWell.HighestBlue = Math.Min(thisWell.HighestBlue, yActual.Value); // row by row bitwise line alteration // because we do this from the top down, we can remove lines as we go for (int row = 0; row < orientation.YDim; row++) { // can't negative bit-shift, but alas X can be negative thisWell.Content[yActual.Value + row] |= (orientation.Rows[row] << xActual.Value); // check for a complete line now // NOTE: completed lines don't count if you've lost if (yActual >= thisWell.Bar && thisWell.Content[yActual.Value+row] == (1 << thisWell.Width) - 1 ) { // move all lines above this point down for (int k = yActual.Value + row; k > 1; k--) { thisWell.Content[k] = thisWell.Content[k - 1]; } // insert a new blank line at the top // though of course the top line will always be blank anyway thisWell.Content[0] = 0; thisWell.Score++; thisWell.HighestBlue++; } } }
int BestWellRating(Well thisWell, PieceType pieceId, int thisSearchDepth) { var thisPiece = new Piece(pieceId, new Point(0, 0), 0); int? bestRating = null; while (thisPiece.Position.Y + 4 < thisWell.Depth // piece is above the bottom && thisWell.Content[thisPiece.Position.Y + 4] == 0 // nothing immediately below it ) { thisPiece = TryTransform(thisWell, thisPiece, Transform.Down); } var piecePositions = new List<Piece>(); piecePositions.Add(thisPiece); var ints = new Dictionary<int, int>(); ints[Hashcode(thisPiece.Position, thisPiece.O)] = 1; var i = 0; while (i < piecePositions.Count) { thisPiece = piecePositions[i]; // apply all possible transforms foreach (Transform j in Enum.GetValues(typeof(Transform))) { var newPiece = TryTransform(thisWell, thisPiece, j); if (newPiece == null) { // piece locked? better add that to the list // do NOT check locations, they aren't significant here if (j == Transform.Down) { var newWell = new Well(thisWell.Score, thisWell.HighestBlue); for (int row2 = 0; row2 < thisWell.Depth; row2++) { newWell.Content[row2] = thisWell.Content[row2]; } AddPiece(newWell, thisPiece); var currentRating = newWell.HighestBlue + ( thisSearchDepth == 0 ? 0 : WorstPieceRating(newWell, thisSearchDepth - 1)/ 100 ); if (bestRating == null || currentRating > bestRating) { bestRating = currentRating; } } } else // transform succeeded? { var newHashcode = Hashcode(newPiece.Position, newPiece.O); if (!ints.ContainsKey(newHashcode)) { piecePositions.Add(newPiece); ints[newHashcode] = 1; } } } i++; } return bestRating.Value; }
int WorstPieceRating(Well thisWell, int thisSearchDepth) { int? worstRating = null; foreach(var piece in pieces) { var currentRating = BestWellRating(thisWell, piece.ID, thisSearchDepth); if (worstRating == null || currentRating < worstRating) { worstRating = currentRating; } if (worstRating.Value == 0) { return 0; } } return worstRating.Value; }
Piece WorstPiece(Well thisWell) { int? worstRating = null; PieceType? worstId = null; foreach (var piece in pieces) { var currentRating = BestWellRating(thisWell, piece.ID, searchDepth); if (worstRating == null || currentRating < worstRating) { worstRating = currentRating; worstId = piece.ID; } if (worstRating.Value == 0) { break; } } return new Piece(worstId.Value, new Point((int)Math.Floor(((double)(thisWell.Width - 4) / 2)),0),0); }
Piece TryTransform(Well thisWell, Piece thisPiece, Transform transformId) { var id = thisPiece.ID; var x = thisPiece.Position.X; var y = thisPiece.Position.Y; var o = thisPiece.O; // apply transform (very fast now) switch (transformId) { case Transform.Left: x--; break; case Transform.Right: x++; break; case Transform.Down: y++; break; case Transform.Up: o = (o + 1) % 4; break; } var orientation = orientations[id][o]; var xActual = x + orientation.XMin; var yActual = y + orientation.YMin; if (xActual < 0 // make sure not off left side || xActual + orientation.XDim > thisWell.Width // make sure not off right side || yActual + orientation.YDim > thisWell.Depth // make sure not off bottom ) { return null; } // make sure there is NOTHING IN THE WAY // we do this by hunting for bit collisions for (int row = 0; row < orientation.Rows.Count; row++) // 0 to 0, 1, 2 or 3 depending on vertical size of piece { if((thisWell.Content[yActual.Value+row] & (orientation.Rows[row] << xActual)) != 0) // [altered it] { return null; } } return new Piece(id,new Point(x,y),o); }
void ClearField() { liveWell = new Well(); livePiece = WorstPiece(liveWell); }