/// <summary> /// Adds a play to <see cref="squaresList"/>. The play is not scored. /// </summary> /// <param name="play">The <see cref="Play"/> to be added to the <see cref="Board"/>.</param> public void AddPlayToBoard(Play play) { if (!this.PlayIsValid(play)) { throw new InvalidPlayException(); } for (int i = 0; i < play.GetParallelListLength(); ++i) { this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].InsertLetterTile(play.GetLetterTile(i)); } this.lastPlay = play; this.lastPlayIsNull = false; }
/// <summary> /// Tells whether a <see cref="Play"/> can legally be placed onto the board. /// </summary> /// <param name="play">The <see cref="Play"/> being checked.</param> /// <returns>True if play can be added to the board. Returns false otherwise.</returns> public bool PlayIsValid(Play play) { if (play.GetParallelListLength() == 0) { // Cuz that's kinda pointless. return false; } if (play.GetParallelListLength() > 7) { // Yeah . . . no. return false; } if (play.GetParallelListLength() == 1 && this.boardGrid[7, 7].IsEmpty()) { // The first play has to have at least 2 letters in it. return false; } // Make sure the first play puts a LetterTile into the central square. if (this.boardGrid[7, 7].IsEmpty()) { bool putsTileInCentralSquare = false; for (int i = 0; i < play.GetParallelListLength(); ++i) { if (play.GetCoordinateX(i) == 7 && play.GetCoordinateY(i) == 7) { putsTileInCentralSquare = true; } } if (!putsTileInCentralSquare) { return false; } } bool allXCoordinatesAreTheSame = true; bool allYCoordinatesAreTheSame = true; int coordX = play.GetCoordinateX(0); int coordY = play.GetCoordinateY(0); // Make sure that all LetterTiles are in either the same row or in the same column. for (int i = 0; i < play.GetParallelListLength(); ++i) { if (coordX != play.GetCoordinateX(i)) { allXCoordinatesAreTheSame = false; } if (coordY != play.GetCoordinateY(i)) { allYCoordinatesAreTheSame = false; } } // Make sure that there are no duplicates in the play. if (allXCoordinatesAreTheSame) { for (int i = 0; i < play.GetParallelListLength(); ++i) { int numberOfMatches = 0; for (int j = 0; j < play.GetParallelListLength(); ++j) { if (play.GetCoordinateY(i) == play.GetCoordinateY(j)) { ++numberOfMatches; } } if (numberOfMatches != 1) { return false; } else { numberOfMatches = 0; } } } else { for (int i = 0; i < play.GetParallelListLength(); ++i) { int numberOfMatches = 0; for (int j = 0; j < play.GetParallelListLength(); ++j) { if (play.GetCoordinateX(i) == play.GetCoordinateX(j)) { ++numberOfMatches; } } if (numberOfMatches != 1) { return false; } else { numberOfMatches = 0; } } } if (!((allXCoordinatesAreTheSame ^ allYCoordinatesAreTheSame) || play.GetParallelListLength() == 1)) { return false; } // Make sure that no letters are being inserted into where there are already letters. if (allXCoordinatesAreTheSame) { for (int i = 0; i < play.GetParallelListLength(); ++i) { if (!this.boardGrid[coordX, play.GetCoordinateY(i)].IsEmpty()) { return false; } } } if (allYCoordinatesAreTheSame) { for (int i = 0; i < play.GetParallelListLength(); ++i) { if (!this.boardGrid[play.GetCoordinateX(i), coordY].IsEmpty()) { return false; } } } // Make sure that any gaps between the letters in the play are filled by letters that are already on the board. if (allXCoordinatesAreTheSame) { List<int> coordsY = new List<int>(); for (int i = 0; i < play.GetParallelListLength(); ++i) { coordsY.Add(play.GetCoordinateY(i)); } coordsY.Sort(); int prevY = coordsY[0]; for (int i = 1; i < play.GetParallelListLength(); ++i) { while (coordsY[i] != prevY + 1) { if (this.boardGrid[coordX, prevY + 1].IsEmpty()) { return false; } ++prevY; } ++prevY; } } if (allYCoordinatesAreTheSame) { List<int> coordsX = new List<int>(); for (int i = 0; i < play.GetParallelListLength(); ++i) { coordsX.Add(play.GetCoordinateX(i)); } coordsX.Sort(); int prevX = coordsX[0]; for (int i = 1; i < play.GetParallelListLength(); ++i) { while (coordsX[i] != prevX + 1) { if (this.boardGrid[prevX + 1, coordY].IsEmpty()) { return false; } ++prevX; } ++prevX; } } // Make sure that at least one of the letters in the play is adjacent to a letter on the board, // if a play has been added to the board. if (!this.boardGrid[7, 7].IsEmpty()) { bool playIsAdjacentToSomething = false; for (int i = 0; i < play.GetParallelListLength(); ++i) { int x = play.GetCoordinateX(i); int y = play.GetCoordinateY(i); // Check down. if (y < 14 && !this.boardGrid[x, y + 1].IsEmpty()) { playIsAdjacentToSomething = true; break; } // Check up. if (y > 0 && !this.boardGrid[x, y - 1].IsEmpty()) { playIsAdjacentToSomething = true; break; } // Check left. if (x > 0 && !this.boardGrid[x - 1, y].IsEmpty()) { playIsAdjacentToSomething = true; break; } // Check right. if (x < 14 && !this.boardGrid[x + 1, y].IsEmpty()) { playIsAdjacentToSomething = true; break; } } return playIsAdjacentToSomething; } return true; }
/// <summary> /// Scores a <see cref="Play"/> that was already added to the board. /// </summary> /// <param name="play">The <see cref="Play"/> to be scored.</param> /// <param name="shouldRemoveMultipliers">Tells whether the <see cref="GameBoardSquare"/>s which are being filled by /// the <see cref="LetterTile"/>s in play should have their score multipliers set to 1.</param> /// <returns>The score of a <see cref="Play"/> that was already added to the board.</returns> public int ScorePlay(Play play, bool shouldRemoveMultipliers) { // Make sure the play is already on the board. for (int i = 0; i < play.GetParallelListLength(); ++i) { int x = play.GetCoordinateX(i); int y = play.GetCoordinateY(i); if (!this.boardGrid[x, y].ContainedLetterTile.Equals(play.GetLetterTile(i))) { throw new InvalidPlayException(); } } int totalPoints = 0; // If the play consists of only one LetterTile, score vertically and horizontally around it. if (play.GetParallelListLength() == 1) { totalPoints += this.ScoreOneHorizontalWord(play.GetCoordinateX(0), play.GetCoordinateY(0)); totalPoints += this.ScoreOneVerticalWord(play.GetCoordinateX(0), play.GetCoordinateY(0)); } else if (play.GetCoordinateY(0) == play.GetCoordinateY(1)) { // Otherwise, if the play is a horizontal play, score all of the vertical words that branch off from that // play, and then score the horizontal word in play. int horizontalWordMultiplier = 1; int horizontalWordPoints = 0; for (int i = 0; i < play.GetParallelListLength(); ++i) { horizontalWordMultiplier *= this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].WordMultiplier; } for (int i = 0; i < play.GetParallelListLength(); ++i) { totalPoints += this.ScoreOneVerticalWord(play.GetCoordinateX(i), play.GetCoordinateY(i)); horizontalWordPoints += this.ScoreOneTile(play.GetCoordinateX(i), play.GetCoordinateY(i)); } // Get the points from the adjacent squares to the left and right of the played letters. int minX = play.GetCoordinateX(0); int maxX = minX; for (int i = 0; i < play.GetParallelListLength(); ++i) { if (minX > play.GetCoordinateX(i)) { minX = play.GetCoordinateX(i); } if (maxX < play.GetCoordinateX(i)) { maxX = play.GetCoordinateX(i); } } // Go left. int count = 1; while (true) { if (minX - count < 0 || this.boardGrid[minX - count, play.GetCoordinateY(0)].IsEmpty()) { break; } else { horizontalWordPoints += this.ScoreOneTile(minX - count, play.GetCoordinateY(0)); ++count; } } // Go right. count = 1; while (true) { if (maxX + count > 14 || this.boardGrid[maxX + count, play.GetCoordinateY(0)].IsEmpty()) { break; } else { horizontalWordPoints += this.ScoreOneTile(maxX + count, play.GetCoordinateY(0)); ++count; } } // Check for gaps between letters in the play, and score them. List<int> coordsX = new List<int>(); for (int i = 0; i < play.GetParallelListLength(); ++i) { coordsX.Add(play.GetCoordinateX(i)); } coordsX.Sort(); count = 1; for (int i = 0; i < coordsX.Count - 1; ++i) { while (coordsX[i] + count < coordsX[i + 1]) { horizontalWordPoints += this.ScoreOneTile(coordsX[i] + count, play.GetCoordinateY(0)); ++count; } count = 1; } horizontalWordPoints *= horizontalWordMultiplier; totalPoints += horizontalWordPoints; } else { // Otherwise, if the play is a vertical play, score all of the horizontal words that branch off from that // play, and then score the vertical word in play. int verticalWordMultiplier = 1; int verticalWordPoints = 0; for (int i = 0; i < play.GetParallelListLength(); ++i) { verticalWordMultiplier *= this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].WordMultiplier; } for (int i = 0; i < play.GetParallelListLength(); ++i) { totalPoints += this.ScoreOneHorizontalWord(play.GetCoordinateX(i), play.GetCoordinateY(i)); verticalWordPoints += this.ScoreOneTile(play.GetCoordinateX(i), play.GetCoordinateY(i)); } // Get the points from the adjacent squares above and below the played letters. int minY = play.GetCoordinateY(0); int maxY = minY; for (int i = 0; i < play.GetParallelListLength(); ++i) { if (minY > play.GetCoordinateY(i)) { minY = play.GetCoordinateY(i); } if (maxY < play.GetCoordinateY(i)) { maxY = play.GetCoordinateY(i); } } // Go up. int count = 1; while (true) { if (minY - count < 0 || this.boardGrid[play.GetCoordinateX(0), minY - count].IsEmpty()) { break; } else { verticalWordPoints += this.ScoreOneTile(play.GetCoordinateX(0), minY - count); ++count; } } // Go down. count = 1; while (true) { if (maxY + count > 14 || this.boardGrid[play.GetCoordinateX(0), maxY + count].IsEmpty()) { break; } else { verticalWordPoints += this.ScoreOneTile(play.GetCoordinateY(0), maxY + count); ++count; } } // Check for gaps between letters in the play, and score them. List<int> coordsY = new List<int>(); for (int i = 0; i < play.GetParallelListLength(); ++i) { coordsY.Add(play.GetCoordinateY(i)); } coordsY.Sort(); count = 1; for (int i = 0; i < coordsY.Count - 1; ++i) { while (coordsY[i] + count < coordsY[i + 1]) { verticalWordPoints += this.ScoreOneTile(play.GetCoordinateX(0), coordsY[i] + count); ++count; } count = 1; } verticalWordPoints *= verticalWordMultiplier; totalPoints += verticalWordPoints; } if (shouldRemoveMultipliers) { // Clear the word and letter multipliers of the GameBoardSquares in the play. for (int i = 0; i < play.GetParallelListLength(); ++i) { this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].RemoveScoreMultipliers(); } } // Give the 50 point bonus for using 7 LetterTiles. if (play.GetParallelListLength() == 7) { totalPoints += 50; } return totalPoints; }
/// <summary> /// Gets a list of all the words created by a given play. /// </summary> /// <param name="play">The play being checked.</param> /// <returns>The list of words created by the play.</returns> public List<string> GetWordsInPlay(Play play) { List<string> words = new List<string>(); bool isVerticalPlay; // Make sure that all of the LetterTiles in the play are already on the board. for (int i = 0; i < play.GetParallelListLength(); ++i) { if (this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].IsEmpty()) { throw new InvalidPlayException(); } if (!this.boardGrid[play.GetCoordinateX(i), play.GetCoordinateY(i)].ContainedLetterTile.Equals(play.GetLetterTile(i))) { throw new InvalidPlayException(); } } if (play.GetParallelListLength() == 1 || play.GetCoordinateX(0) == play.GetCoordinateX(1)) { isVerticalPlay = true; } else { isVerticalPlay = false; } int x = play.GetCoordinateX(0); int y = play.GetCoordinateY(0); if (isVerticalPlay) { int topOfWord = y; int midX = x; StringBuilder wordBuilder = new StringBuilder(); // Get to the top of the vertical word. while (topOfWord > 0) { if (this.boardGrid[x, topOfWord - 1].IsEmpty()) { break; } else { --topOfWord; } } while (topOfWord <= 14) { if (this.boardGrid[x, topOfWord].IsEmpty()) { break; } else { wordBuilder.Append(this.boardGrid[x, topOfWord].ContainedLetterTile.LetterValue); ++topOfWord; } } if (wordBuilder.ToString().Length > 1) { words.Add(wordBuilder.ToString()); } wordBuilder.Clear(); // Get all the words that branch off from that word. for (int i = 0; i < play.GetParallelListLength(); ++i) { int leftOfWord = play.GetCoordinateX(i); // Go to the left end of the word while (leftOfWord > 0) { if (this.boardGrid[leftOfWord - 1, play.GetCoordinateY(i)].IsEmpty()) { break; } else { --leftOfWord; } } // Read rightward until the word ends. while (leftOfWord <= 14) { if (this.boardGrid[leftOfWord, play.GetCoordinateY(i)].IsEmpty()) { break; } else { wordBuilder.Append(this.boardGrid[leftOfWord, play.GetCoordinateY(i)].ContainedLetterTile.LetterValue); ++leftOfWord; } } if (wordBuilder.ToString().Length > 1) { words.Add(wordBuilder.ToString()); } wordBuilder.Clear(); } } else { int leftOfWord = x; int midY = y; StringBuilder wordBuilder = new StringBuilder(); // Get to the top of the vertical word. while (leftOfWord > 0) { if (this.boardGrid[leftOfWord - 1, y].IsEmpty()) { break; } else { --leftOfWord; } } while (leftOfWord <= 14) { if (this.boardGrid[leftOfWord, y].IsEmpty()) { break; } else { wordBuilder.Append(this.boardGrid[leftOfWord, y].ContainedLetterTile.LetterValue); ++leftOfWord; } } if (wordBuilder.ToString().Length > 1) { words.Add(wordBuilder.ToString()); } wordBuilder.Clear(); // Get all the words that branch off from that word. for (int i = 0; i < play.GetParallelListLength(); ++i) { int topOfWord = play.GetCoordinateY(i); // Go to the left end of the word while (topOfWord > 0) { if (this.boardGrid[play.GetCoordinateX(i), topOfWord - 1].IsEmpty()) { break; } else { --topOfWord; } } // Read rightward until the word ends. while (topOfWord <= 14) { if (this.boardGrid[play.GetCoordinateX(i), topOfWord].IsEmpty()) { break; } else { wordBuilder.Append(this.boardGrid[play.GetCoordinateX(i), topOfWord].ContainedLetterTile.LetterValue); ++topOfWord; } } if (wordBuilder.ToString().Length > 1) { words.Add(wordBuilder.ToString()); } wordBuilder.Clear(); } } return words; }