/// <summary> /// Initialize the tiles. /// </summary> public void SetupTiles() { Tiles = new ScrabbleTile[ScrabbleForm.BOARD_WIDTH, ScrabbleForm.BOARD_HEIGHT]; TileBag = new TileBag(); var specialTilePositions = WordScorer.GetTileTypes(); for (int x = 1; x <= ScrabbleForm.BOARD_WIDTH; x++) { for (int y = 1; y <= ScrabbleForm.BOARD_HEIGHT; y++) { var tile = new ScrabbleTile { XLoc = x - 1, YLoc = y - 1 }; tile.BackColor = SystemColors.ButtonFace; tile.Location = new Point(x * (ScrabbleForm.TILE_SIZE + 2), y * (ScrabbleForm.TILE_SIZE + 2)); tile.Size = new Size(ScrabbleForm.TILE_SIZE, ScrabbleForm.TILE_SIZE); tile.UseVisualStyleBackColor = false; tile.Font = new Font("Verdana", 15.75F, FontStyle.Regular); tile.Click += Tile_Click; tile.TileType = specialTilePositions[x - 1, y - 1]; tile.SetRegularBackgroundColour(); ScrabbleForm.Controls.Add(tile); Tiles[x - 1, y - 1] = tile; } } }
/// <summary> /// Fills the player's rack with tiles. Will attempt to fill the rack completely, /// or just take as many as it can if there's not enough tiles left to completely re-fill /// the rack. /// </summary> public void FillRack(List <RackTile> tiles) { // How many letters in the rack are missing? int missingLetters = tiles.Where(r => string.IsNullOrEmpty(r.Text)).Count(); // Take random letters from the tile back, and fill up the rack again. var letters = ScrabbleForm.TileManager.TileBag.TakeLetters(missingLetters); for (int x = 0; x < letters.Length; x++) { var tile = tiles.FirstOrDefault(r => string.IsNullOrEmpty(r.Text)); tile.Letter = letters[x]; tile.LetterValue = WordScorer.LetterValue(letters[x]); tile.Text = letters[x].ToString(); } }
public void FindWords(int r, int c, History hist, string prefix, object directionData, bool substitionsMade, bool lettersWithoutSubstitions) { //Add to history trail and word hist.Push(r, c); var letter = boardModel.Letters[r, c]; prefix += letter; if (IsQincludeU && letter == 'Q') { prefix += 'U'; } if (!wordList.Find(prefix, wholeWord: false)) { //prefix not in dictionary, no point continuing this way hist.Pop(); return; } //only return words passing through one of the mandatory tiles, if enabled. if (!boardModel.UsingMandatoryTiles || hist.Overlaps(boardModel.MandatoryLocations)) { //Check words in whitespace or edge of the board if that setting is used bool wordEndOk = true; if (WordMustEndWithSpace) { var nextDirs = directionStrategy.GetNextDirections(r, c, boardModel, hist, directionData); if (nextDirs.Count() > 0) { var next = nextDirs.First(d => true); wordEndOk = char.IsWhiteSpace(boardModel.Letters[next.Row, next.Column]); } } if (WordMustHaveSubstitutions && !substitionsMade) { wordEndOk = false; } if (stepValidationStrategy != null && !stepValidationStrategy.ValidateWordEnd(boardModel, prefix, r, c, directionData, substitionsMade, lettersWithoutSubstitions)) { wordEndOk = false; } //check if the current path is a valid word if (wordEndOk && prefix.Length >= MinWordLength && wordList.Find(prefix, wholeWord: true)) { if (!foundWordsDict.ContainsKey(prefix)) { Word newWord = new Word(prefix, hist.Copy()); foundWords.Add(newWord); foundWordsDict.Add(prefix, newWord); } else { //found the same word a second time, check to see which one has a higher score, replace if new word has higher score WordScorer scorer = new WordScorer(boardModel) { includeIntersectionWordScores = true, UseLengthBonus = false }; Word newWord = new Word(prefix, hist.Copy()); int newWordPathScore = scorer.getWordScore(newWord, false, true); //TODO need to track which letters have been added for wordfinding so the intersects and bonuses are scored properly int oldWordPathScore = scorer.getWordScore(foundWordsDict[prefix], false, true); if (newWordPathScore > oldWordPathScore) { foundWordsDict[prefix].AlternatePaths.Add(foundWordsDict[prefix].Path); foundWordsDict[prefix].Path = newWord.Path; } else { foundWordsDict[prefix].AlternatePaths.Add(newWord.Path); } } } } //stop recursion if we are at max length if (hist.Count == MaxWordLength) { hist.Pop(); return; } if (stepValidationStrategy != null && !stepValidationStrategy.Validate(boardModel, prefix, r, c, directionData)) { //failed validation after adding this letter hist.Pop(); return; } foreach (var direction in directionStrategy.GetNextDirections(r, c, boardModel, hist, directionData)) { char preOverRideLetter = boardModel.Letters[direction.Row, direction.Column]; var nextLetter = boardModel.Letters[direction.Row, direction.Column]; if (direction.OverrideLetter.HasValue) { nextLetter = direction.OverrideLetter.Value; boardModel.Letters[direction.Row, direction.Column] = nextLetter; substitionsMade = true; } else { lettersWithoutSubstitions = true; } if (nextLetter != '?') { FindWords(direction.Row, direction.Column, hist, prefix, direction.DirectionData, substitionsMade, lettersWithoutSubstitions); } else { for (char ch = 'A'; ch <= 'Z'; ch++) { boardModel.Letters[direction.Row, direction.Column] = ch; FindWords(direction.Row, direction.Column, hist, prefix, direction.DirectionData, substitionsMade, lettersWithoutSubstitions); } boardModel.Letters[direction.Row, direction.Column] = '?'; } boardModel.Letters[direction.Row, direction.Column] = preOverRideLetter; } hist.Pop(); }
private void populateResultsList() { lstResults.Items.Clear(); WordScorer scorer = new WordScorer(boardModel); scorer.SetWordScores(foundWords); //Get no of words and total possible score if all found words played int maxTotal = 0; for (int i = 0; i < foundWords.Count; i++) { maxTotal += foundWords[i].Score; } lblMaxPossibleScore.Text = maxTotal.ToString(); lblWords.Text = foundWords.Count.ToString(); if (cbkSortbyScore.Checked) { foundWords.Sort(new ScoredWordComparer()); foundWords.Reverse(); lstResults.FormattingEnabled = true; foreach (Word word in foundWords) { lstResults.Items.Add(word.Text + " (" + word.Score.ToString() + ")"); } } if (cbkSortbyScoreComplexity.Checked) { foundWords.Sort(new ScoredComplexWordComparer()); foundWords.Reverse(); lstResults.FormattingEnabled = true; foreach (Word word in foundWords) { lstResults.Items.Add(word.Text + " (" + word.Score.ToString() + ")"); } } if (cbkSortbyPath.Checked) { //For path sort, we remove low-scoring words int minScore = 0; if (Int32.TryParse(txtMinScore.Text, out minScore)) { //Got the min. score, now remove too-low words for (int i = foundWords.Count - 1; i >= 0; i--) { if (foundWords[i].Score < minScore) { foundWords.RemoveAt(i); } } } foundWords.Sort(new WordPathComparer()); lstResults.FormattingEnabled = true; foreach (Word word in foundWords) { lstResults.Items.Add(word.Text + " (" + word.Score.ToString() + ")"); } } if (cbkSortbyLength.Checked) { foundWords.Sort(new WordLengthComparer()); foundWords.Reverse(); foreach (Word word in foundWords) { lstResults.Items.Add(word.Text); } } }