Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Question 1 — Scrabble Description In the Scrabble board game, a player has a ran

ID: 3852195 • Letter: Q

Question

Question 1Scrabble

Description

In the Scrabble board game, a player has a random collection of seven letters, from which he/she plays a word left-to-right or top-to-bottom on a 15×15 board, to accumulate points. Except for the first word, each word must join with existing words on the board to make valid words.

Starting Program

The following sections of the assignment describe what to do in each of the function definitions. These functions are in alphabetical order by function name, because that is the order of the function definitions in the starting program.1 This is not the order you will want to use to develop the code.

1 Function definitions that are given to you completely implemented are in alphabetical order at the top of the file, and function stubs are in alphabetical order at the bottom. A line of asterisks separates them.

One plausible order to do your development might be: genRepeatedChars, doMenu, getInt, tryLetters, getWords, display, wordValue and displayLetters. Whichever order you use, you will probably find it useful when trying to implement a function from a stub to print the incoming parameter values, and the values returned.

To avoid having extraordinarily long printouts, given that the wordlist is hundreds of thousands of words long, in the handout program we have set MAX_WORD_LENGTH to 2. That is, the program will only find 2-letter words. There aren't very many of those, so the outputs remain of reasonable size. As your program gets closer to working, you can increase MAX_WORD_LENGTH to a maximum of 15 to produce more words. Ensure your final version has it set to 15.

Function display
def display(words, label) :
This function takes a list or a set of words, and prints it to the console.

First it prints a horizontal line to separate this output from previous output (see sample output).

Then it prints a heading "Valid words:" or "Valid user words:". The italicized phrase that comes after "Valid" is the value of label.

It prints out the list of words. There are several requirements, and your mark for this function will depend on how many you implement successfully.

Every word in words must be printed.

Each letter in each word should be printed with a subscript representing the letter's point

value (e.g., R1O1B3E1D2). A word is formatted that way by a call to displayLetters.

Each word should be followed by its total point value in brackets (e.g., R1O1B3E1D2 (8)).

Words should be lined up in fixed width columns.

Finally display prints another heading, "Best word:" and shows a single word with the maximum number of points among the words. If there are multiple words with that point total, any one of them will do.

There is no return value.

Function displayLetters
def displayLetters(text) :
This function is used to show the point values of all letters in text. Notes:

Every character in text must be a letter from 'A' to 'Z'. These are the only characters for which point values are defined. For example, text cannot be a phrase with blanks in it.

The point value of every character from 'A' to 'Z' is stored in the global constant POINTS.

The subscript characters from 0 to 10 are stored in order in the global variable subscripts. The subscripts are just special Unicode characters of small size that are placed slightly below the font baseline. The main function has already created POINTS and subscripts by the time this function is called.

The return value is the list of converted characters with subscripts; if text has the value 'ROBED' on entry, the return value should be R1O1B3E1D2.

Function doMenu
def doMenu(hashes, wordGroups) :

This function asks the user which action to perform next, and then it carries out that single action. It provides error correction, so it will keep asking until a valid action is selected. It should follow the example shown in the notes for a menu. See the sample output to see what the menu interaction looks like. Here are the choices to offer the user.

• a) change the number of random letters
The two choices allowed are 7 or 8. Users have seven letters on their racks, but they have to fit the word onto the board, which often means using one letter from another word already placed. This function should call getInt appropriately to acquire the user's choice with error correction.

b) change the time limit
The default time limit is 20 seconds, but this is quite long when looking for Scrabble words. Any time between 1 and 120 seconds should be acceptable. This function should again call getInt appropriately to acquire the user's choice with error correction.

c) try a new set of letters
In this choice, the user is presented with a random sequence of letters from which to make words. The function should call tryLetters to carry out this choice.

q) quit
The function should do nothing in this case.

The parameters of doMenu are provided to pass down to tryLetters when it is called. After the single action is complete, doMenu should return the user's choice in uppercase ('A', 'B', 'C' or 'Q') to the calling code.

Function genRepeatedChars
def genRepeatedChars(chars, repeats) :

This function is used to generate a list of all the Scrabble tiles. As a simple example, if there are five letters, A, B, C, D and E, with 9 A tiles, 2 B tiles, 2 C tiles, 4 D tiles and 12 E tiles, the parameters of this function will be chars 'ABCDE' and repeats [9, 2, 2, 4, 12]. The return value will be a list: ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'C', 'C', 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E']. Assume without checking that the parameters are a string with unique characters, and a list of non-negative integers.

Function getWords
def getWords(letters) :

This function repeatedly prompts the user to enter a word made up of the letters from the parameter.

The repetition ends after the number of seconds specified by the global variable timeOut. You can determine how much time has elapsed since the first input request using the library function time.time. It returns the time since some point in the past, in seconds. Simply record the time before the input loop, then record it again each time through the loop. If the difference from the start is more than timeOut seconds, drop out of the loop.

Display the letters to the user as formatted by displayLetters, so the user can see the point count for each letter.

No error-checking is required. Whatever the user enters is considered valid at this point. Record all entries in a list or set, in uppercase.

Return a set of user entries, without duplicates. The easiest way to remove duplicates from a list of strings is to convert it to a set: stringSet = set(stringList). This works because every entry in a set must be unique. Duplicates are discarded.

Function tryLetters
def tryLetters(hashes, wordGroups) :

This function generates a string of random letters, gets user input by calling getWords, and displays

the results.

By the time tryLetters is called, main has produced a global list of letters called allLetters. It uses genRepeatedChars to do so, and so allLetters contains 98 letters2 representing the tiles in a Scrabble game. They can be in any order.

To generate a random sample of the letters, call random.shuffle(allLetters). Then use a slice to take the required number of letters from the shuffled list, and convert it to a string.

Call calcWordHashes (and note its similarities and differences to getCode from Assignment 2) to hash the string with the chosen letters (note that calcWordHashes requires an argument providing a list of words, but we have just one string).

Call filterWords to find all the word groups from the input file that can be made from letters in the random sample.

In this program we are interested in individual words, not word groups, so expand all the word groups and make a big set (called allWords) containing all the words that can be made from letters in the random sample,.

Call getWords to get a set of the words identified by the user and save it as userWords.

The invalid words provided by the user are the entries in userWords that are not in allWords. They could be valid words that can't be made from these letters, or strings that are not words at all. The set difference operation aSet – bSet finds all the entries in set aSet that are not in set bSet. Print out the invalid words.

The valid words provided by the user are those that are in both userWords and allWords. The set intersection operation aSet.intersection(bSet) finds all the entries that are in both aSet and bSet.

Call display to print out the valid words neatly and to find the best one (that is, the one with the highest point count).

Call display again to print the list of all words, and to find the best one. Function wordValue

def wordValue(word) :
This function returns the total value of the parameter word, found by adding up the point counts of

all the letters in word.

Starting code:

Explanation / Answer

main.py

PURPOSE: To help someone become better at Scrabble®
"""
# imports
import random # to shuffle the letter list in tryLetters
import sys    # to use sys.exit to stop the program in one of the stubs
              # This import can be deleted later.
import time   # For timing user input as well as termination output

# constants
COUNTS = (9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1, 6, 4, 6, 4, 2,
          2, 1, 2, 1) # quantity of each letter A to Z in Scrabble collection
MIN_WORD_LENGTH = 2 # shortest word to use in anagram
MAX_WORD_LENGTH = 15 # longest word to use in anagram
POINTS = (1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1,
          4, 4, 8, 4, 10) # Scrabble points for each letter A to Z
PRIMES = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
          43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 1) # prime
          # numbers used to create unique hash for each letter collection
REGISTERED = "N{REGISTERED SIGN}" # registered trade mark sign
STOP = "Q" # input used to stop the program

# function definitions

#..........................................................................main
def main() :
    """main function that drives the program operations"""
    global allLetters, LETTERS, sampleSize, subscripts, timeOut
    print("WELCOME TO SCRABBLE%s !" % REGISTERED)
    print("'Scrabble' is a registered trade mark of Hasbro, Inc.")
    print()
    print("Test your ability to find Scrabble words!")
  
    LETTERS = genCharRange('A','Z') # lowercase from 'a' to 'z'
    subscripts = list(genCharRange('0','9'))
    subscripts.append(subscripts[1] + subscripts[0])
    allLetters = genRepeatedChars(LETTERS, COUNTS) # list of Scrabble letters
    sampleSize = 7 # number of letters in Scrabble hand
    timeOut = 20 # [s] guessing time
  
    words = getWordList(MIN_WORD_LENGTH, MAX_WORD_LENGTH) # read word list;
                                                         # print stats
  
    wordhashes = calcWordHashes(words) # calculate a hash for each word
    sortedHashes, wordGroups = groupWords(wordhashes, words) # sort the hashes
                                     # group words with the same hashes
                                     # print extreme cases
  
    result = doMenu(sortedHashes, wordGroups) # result is user choice
  
    while result != STOP :
        result = doMenu(sortedHashes, wordGroups)
    
    showTermination()
    return  
  
#............................................................... calcWordHashes
def calcWordHashes(words) :
    """hash each word by multiplying an appropriate prime number for
    each letter in the word. Return list of hashes."""
    wordhashes = [] # hashes for the words
    for word in words :
        word = word.lower()
        hashVal = 1 # hash for this specific word
        for letter in word.upper() : # calculate one letter at a time
            hashVal *= PRIMES[LETTERS.find(letter)] # nonletters have factor 1
        wordhashes.append(hashVal)
    return wordhashes

#.................................................................. filterWords
def filterWords(origHash, hashes, wordGroups) :
    """Eliminate hashes and corresponding word groups that do not divide
    evenly into origHash. Return the reduced lists of hashes and word
    groups."""
    newhashes = [] # hash values that divide evenly into origHash
    newWordGroups = [] # wordGroups corresponding to newHashes
    for loc, hashVal in enumerate(hashes) :
        useThisOne = origHash % hashVal == 0 # if True, a word to retain
        newhashes += useThisOne * [hashVal]
        newWordGroups += useThisOne * [wordGroups[loc]]
    return newhashes, newWordGroups

#..................................................................genCharRange
def genCharRange(firstChar, lastChar) :
    """Return a string containing every character from firstChar to
    lastChar inclusive."""
    letters = [chr(num) for num in range(ord(firstChar), ord(lastChar) + 1)] #
               # list comprehension to produce characters from first to last
    return ''.join(letters)

#...................................................................getWordList
def getWordList(minLength, maxLength) :
    """Open a standard list of English words and return them in a list.
    minLength and maxLength are inclusive bounds on the length of word
    we want to keep."""
    filename = "twl06.txt" # name of word file, assumed in local folder
    flink = open(filename, 'r', encoding="utf-8") # link to input file
    print( " Reading words from %s" % filename)
    words = [ ]            # word list
    for eachline in flink :
        text = eachline.strip() # line contains one word
        # print(eachline, text)
        # text = text.replace('%','') # not needed with this file
        words += [text.upper()] * (minLength <= len(text) <= maxLength)
    flink.close()
    print( "%d words read: %s" % (len(words),', '.join(words[:6]+['...'])))
    return words

#................................................................... groupWords
def groupWords(hashes, words) :
    """Put both hashes and words in sorted order by hashes. Then group words
    that have the same hash, and return hashes and word groups. The hashes
    should be sorted, and each hash is unique. Each corresponding word group
    is formatted as a single string like this: 'baker|brake|break' """
    sortedPairs = sorted(zip(hashes,words)) # (hash, word) pairs sorted by hash
    sortedHashes = [] # unique hashes sorted in increasing order
    wordGroups = [] # groups of words with same hash, each as a list
    prevhash = 0 # hash for previous entry
    for hashVal, word in sortedPairs :
        newhash = hashVal != prevhash # new hash value found
        sortedHashes += newhash * [hashVal] # add new hash entry?
        wordGroups += newhash * [[]]   # add new empty list of words?
        wordGroups[-1].append(word)
        prevhash = hashVal
    return sortedHashes, ['|'.join(group) for group in wordGroups]

#.............................................................. showTermination
def showTermination() :
    '''Print termination output, including author and date.'''
    print( " Programmed by Edison Guillermo from Instructors")
    print( "Date: " + time.ctime())
    print( "End of processing")
  
#***************************** PUT YOUR CODE HERE *****************************

#...................................................................... display
def display(words, label) :
    print("-" * 82)
    wordList = list(words)
    newLine = 1
    wordPoints = []
    print(label)
    print(" ", end ="")
    for word in words:
        wordPoint = 0
        for letter in word:
            wordPoint += POINTS[LETTERS.find(letter)]
        wordPoints.append(wordPoint)
      
        print("%19s%4s%s" %((displayLetters(word),"(%d)" % (wordPoint),
                " " * (newLine % 3 == 0))), end="")
      
        newLine +=1
    print(" Best word:", end ="")
    try:
        bestWordVal = max(wordPoints)
        bestWord = displayLetters(wordList[wordPoints.index(bestWordVal)])
    except:
        bestWord = ""
        bestWordVal = 0
  
    print(" %33s%4s" % (bestWord,"(%d)" % (bestWordVal)*(bestWordVal != 0)))
    return
  
#............................................................... displayLetters
def displayLetters(text) :
    text.replace(" ", "")
    newText = ""
    for letter in text:
        newText += letter + subscripts[POINTS[LETTERS.find(letter)]]
    return newText
  
#....................................................................... doMenu
def doMenu(hashes, wordGroups) :
    global sampleSize, timeOut
    cont = False
  
  
    whata = "Enter int n so that 7 <= n < 9 for number of letters to play: "
    whatb = "Enter int n so that 1 <= n < 121 for seconds to guess words: "
    while cont == False:
        print("Choose one of the following and enter the letter:")
        print("%4s a) change the number of random letters" % (" "))
        print("%4s b) change the time limit" % (" "))
        print("%4s c) try a new set of letters" % (" "))
        print("%4s q) quit" % (" "))
        cont = True
        userChoice = input()
        userChoice = userChoice.upper()
        if userChoice == "A":
            sampleSize = getInt(7,9, whata)
        elif userChoice == "B":          
            timeOut = getInt(1,121,whatb)
        elif userChoice == "C":
            tryLetters(hashes, wordGroups)
        elif userChoice == "Q":
            pass
          
        else:
            print(" Invalid response '%s'; try again" % (userChoice))
            cont = False
    return userChoice

#............................................................. genRepeatedChars
def genRepeatedChars(chars, repeats) :
    newChars=[]
    for letter in range(len(chars)):
        for repeater in range(repeats[letter]):
            newChars.append(chars[letter])
    return newChars

#.................................................................getInt
def getInt(lo, hi, what) :
    validInt = False  
    while validInt == False:
        numberStr = input(what)
        if not numberStr.isdigit():
            print("*** %s is not an int" % (numberStr))
        else:
            numberStr = int(numberStr)
            if lo > numberStr:
                print("*** %d is too small" % (numberStr))
            elif hi <= numberStr:
                print("*** %d is too big" % (numberStr))
            else:
                validInt = True
      
    return int(numberStr)

#..................................................................... getWords
def getWords(letters) :
    scoreLetters = displayLetters(letters)
    words = []
    timeTotal = 0
    print("Time limit: %d seconds" % (timeOut))
    while timeTotal <= timeOut:
        timea = time.time()
        word = input("Enter a word made from letters in %23s "%(scoreLetters))
        timeb = time.time()
        timeTotal += (timeb-timea)
        userWord = word.upper()
        words.append(userWord)
      
    word = set(words)
  
  
    return word

#................................................................... tryLetters
def tryLetters(hashes, wordGroups) :

    random.shuffle(allLetters)
    letters = allLetters [0:sampleSize]
    newLetters = ["".join(letters)]
    hashletters = calcWordHashes(newLetters)
    allWords = []
  
    newHashes,filteredLetters = filterWords(hashletters[0],hashes,wordGroups)
    for splitter in filteredLetters:
        word = splitter.split("|")
        allWords += word
    wordSet = set(allWords)
    userWords = getWords("".join(letters))
    invalidLet = userWords - wordSet
    validLet = userWords.intersection(wordSet)
    print("Invalid user words: %s" % ", ".join(invalidLet))
    display(validLet,"Valid User Words:")
    display(wordSet,"Valid words:")
    """
    userIn = input("Press <Enter> to continue, <q> to quit:")
    if userIn.upper() == STOP :
        sys.exit()
    """                                                 
    return

#.................................................................... wordValue
def wordValue(word) :  
    return POINTS[LETTERS.find(word[0])]


main()

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote