2

I'm trying to finish this boggle game Python challenge for school, and I've created a draw board function that creates a board with 16 random letters. How do I use a def function to ask the user to input a word and then score it, depending on how long the word is? Once that is completed, the game should work properly. Any help will be greatly appreciated :)

import random

def loadwords ():
    print "Loading word list from file.. "
    wordList = []
    inFile = open ('words.txt','r')
    for line in inFile:
        wordList.append(line.strip().lower())
    #inFile : locates file in the folder, opens it
    #wordlist: list of the words (strings)
    print " " , len(wordList), "words loaded"
    inFile.close()
    return wordList

def spellCheck (word, wordList):
    if (word in wordList) == True:
        return True
    else:
        return False

def drawBoard (randomLetters):

    '''Takes a randomList of 16 characters
    Prints out a 4 x 4 grid'''

    print " %s %s %s %s " %(randomLetters [0], randomLetters [1], randomLetters [2], randomLetters [3])
    print " %s %s %s %s " %(randomLetters [4], randomLetters [5], randomLetters [6], randomLetters [7])
    print " %s %s %s %s " %(randomLetters [8], randomLetters [9], randomLetters [10], randomLetters [11])
    print " %s %s %s %s " %(randomLetters [12], randomLetters [13], randomLetters [14], randomLetters [15])

def wordinput ():
    #asks user to input the longest word they can from grid
    wordinput = raw_input ("Enter a word made up of the letters in the 4x4 table")
    for letters in wordinput:
        letters == randomLetters

def randomLetters ():
    letters = []
    alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','v','w','x','y','z']
    for i in range (0,16,1):
        letters.append(random.choice(alphabet))
    return letters

dictionary = loadwords()
letterList = randomLetters()
drawBoard(letterList)
wordinput(randomLetters)
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
user1655562
  • 81
  • 2
  • 8
  • 1
    So the user enters a word, which is checked to see if it's in a dictionary - but isn't this missing probably the hardest part - ie, making sure the entered word can indeed be made up from the board? – Jon Clements Nov 20 '12 at 14:47
  • I have no idea what you mean, i've got an external file to access a large list of words, how ever i have no idea how to save the points and make the user input a word that is in the grid. – user1655562 Nov 20 '12 at 14:50

3 Answers3

3

raw_input (in Python 2) or input (in Python 3) allows to read a string.

Then you need to check if all the letters are contained in the alphabet...

def wordInLetter(word, letters):
    for i in range(word):
        if word[i] not in letters:
             return False
    return True

Or shorter:

def wordInLetter(word, letters):
    return all(letter in letters for letter in word)

But wait, you don't want to make it possible to use one letter several times!

Let's use the Counter to track how many times every letter is in the letter bag and work from that:

from collections import Counter
def wordInLetter(word, letters):
    available = Counter(letters)
    for letter in word:
        if available[letter] == 0:
             return False
        available[letter] -= 1
    return True

This seems to work nicely. I hope this is what you need.

In [3]: wordInLetter('kos','akos')
Out[3]: True

In [4]: wordInLetter('kos','ako')
Out[4]: False

In [5]: wordInLetter('koss','akos')
Out[5]: False

EDIT

So we're not only interested about whether word can be combined in letters, but we also want to know if it can be done by matching adjacent letters. So another try:

import math
def wordInLetterSearch(word, letters, startX, startY):
    # Assume: letters is a list of X letters, where X is a k*k square
    k = int(len(letters) ** 0.5)

    if len(word) == 0:
        return True

    def letter(x, y):
        return letters[x + y*k]

    def adjacent(x, y):
        if x > 0:
           yield x-1, y
        if x < k-1:
           yield x+1, y
        if y > 0:
           yield x, y-1
        if y < k-1:
           yield x, y+1

    # try to move in all 4 directions
    return any(letter(x2, y2) == word[0] and wordInLetterSearch(word[1:], letters, x2, y2)
               for x2, y2 in adjacent(startX, startY))

def wordInLetter(word, letters):
    k = int(len(letters) ** 0.5)

    def coords(i):
        return i%k, i/k

    # look for a starting point
    return any(letter == word[0]
                    and wordInLetterSearch(word[1:], letters,
                                           coords(i)[0], coords(i)[1])
               for i, letter in enumerate(letters)) coords(i)[1])
                   for i, letter in enumerate(letters))

This is a bit complicated. Basically it's a 2-step search: First we look for a starting point (a position inside letters where the letter matches the first character of the word), then we move snake-like to adjacent fields where possible, recursively.

Little modification is required to match Boggle rules exactly:

  • modify adjacent to allow diagonals too (easy),
  • prevent visiting the same spot twice (medium; hint: add a parameter to wordInLetterSearch, use a set).

I'll leave these as an exercise.

Kos
  • 70,399
  • 25
  • 169
  • 233
  • It's a good start, but slightly more complicated (from Wiki)...: `Each player searches for words that can be constructed from the letters of sequentially adjacent cubes, where "adjacent" cubes are those horizontally, vertically or diagonally neighboring. Words must be at least three letters long, may include singular and plural (or other derived forms) separately, but may not use the same letter cube more than once per word. [snip]` – Jon Clements Nov 20 '12 at 14:53
  • Oh, looks like I described Scrabble instead. I'll expand to include these rules. – Kos Nov 20 '12 at 14:57
  • There, I hope we're home now. – Kos Nov 20 '12 at 15:29
1

Here is another variant. It should be easier to read but the idea is the same: simple backtracking. Sometimes, it is easier to abort the iteration on the caller-side (no not execute the next step), sometimes on the calle-side (on every iteration, check precondition and abort if invalid).

def wordInBoardIter(letters, word, x, y):
    n = int(len(letters)**0.5)
    if word == "": return True # empty - all letters are found
    if x<0 or y<0 or x>=n or y>= n: return False #outside of board
    if letters[x+y*n] != word[0]: return False # we are looking at the wrong position
    # one step further:
    return any(wordInBoardIter(letters, word[1:], x+dx,y+dy) for dx,dy in [(1,0), (0,1), (-1,0), (0,-1)])


def wordInBoard(letters, word):
    n = int(len(letters)**0.5)
    return any(any(wordInBoardIter(letters, word, x,y) for x in range(n)) for y in range(n))

if __name__ == '__main__':
    letters = ['a', 'h', 'e', 'l',
               'x', 'd', 'l', 'l',
               'y', 'v', 'r', 'o',
               'z', 'w', 'o', 'w']
    print "hello     : %s" % ("found" if wordInBoard(letters, "hello") else "not found")
    print "helloworld: %s" % ("found" if wordInBoard(letters, "helloworld") else "not found")
    print "foobar    : %s" % ("found" if wordInBoard(letters, "foobar") else "not found")

There are the same exercises in this version (diagonal tiles and disallowing the reuse the same letters twice).

Peter Schneider
  • 1,683
  • 12
  • 31
0

I haven't played boggle much myslef, but a solution you could use to do this would be to take the word the user inputted and use the len() command to return the length of the word. Then take that length and score it. Here's a basic example (modify it to fit the rules of the game):

def wordinput ():
    #asks user to input the longest word they can from grid
    wordinput = raw_input ("Enter a word made up of the letters in the 4x4 table")
    for letters in wordinput:
        letters == randomLetters
    scoreWord(wordInput)

def scoreWord(word)
    #finds the amount of characters in the word
    wordLength = len(word)
    #multiplies the maunt of letters in the word by two to get the score
    #(not sure how boggle scoring works)
    score = wordLength * 2
Ben Schwabe
  • 1,283
  • 1
  • 21
  • 36