This task is part of project07 which is due at 23:00 EDT on 2024-10-29.
You have the option to work with a partner on this task if you wish. Working with a partner requires more work to coordinate schedules, but if you work together and make sure that you are both understanding the code you write, you will make progress faster and learn more.
You can download the starter code for this task using this link.
You can submit this task using this link.
Put all of your work for this task into the file
wordSearch.py
(which is provided among the starter files)
In this task, you will practice nested loops by implementing part of a program that solves word search puzzles. A word search puzzle consists of a text grid, and a list of words that are hidden in it. The goal is to find all of the words on the list.
For example, here is a list of words
cs111, science, center, wellesley, python, computer, nested, loops
that are hidden in the following puzzle. Can you find them?
d s b o s i d d e c x r
u k o p c e n t e r x v
p x k f i m n r h o j x
y e l s e l l e w q s j
t h o e n j k t z u n k
h a o q c i d u a u s 1
o k p p e d l p a y 1 w
n e s t e d n m a 1 h j
s n k p l g v o s f t j
c m w p u l l c d z p l
It's easier to see the placement of the hidden words if we replace all characters not in the hidden words by dashes:
- - - - s - - - - - - -
- - - - c e n t e r - -
p - - - i - - r - - - -
y e l s e l l e w - - -
t - o - n - - t - - - -
h - o - c - - u - - - 1
o - p - e - - p - - 1 -
n e s t e d - m - 1 - -
- - - - - - - o s - - -
- - - - - - - c - - -
In a traditional word search puzzle, words can be hidden vertically, horizontally, or diagonally. They can also be backwards in any direction. To simplify things, in this task your program will search only for words that are oriented horizontally or vertically, not diagonally.
For example, in the above puzzle, your program will find the horizontal
words center
, nested
, and wellesley
and the vertical words
python
, loops
, computer
, and science
, but it will not find
cs111
.
In this problem, two-dimensional text grids are represented
as a list of strings of the same length. Each string represents
one row of the grid, and the length of each row string is the
number of columns. For example, the above CS puzzle is
the value of the variable TEST_PUZZLE
in wordSearch.py
:
TEST_PUZZLE = [
"----s-------",
"----center--",
"p---i--r----",
"yelsellew---",
"t-o-n--v----",
"h-o-c--u---1",
"o-p-e--p--1-",
"nested-m-1--",
"-------os---",
"-------c----"
]
The words placed in this puzzle are the value of the
variable TEST_WORDS
:
TEST_WORDS =
"cs111",
"science",
"center",
"wellesley",
"python",
"computer",
"nested",
"loops"
]
As noted above, your program is not expected to find the
word `"cs111"
in this puzzle.
The starter code includes a function wordPuzzle.generatePuzzle
that generates random word search puzzles from a list of words
to hide in the puzzle. To find out more, see the
section on Word Puzzle Generation at the end of these
instructions.
Note that as usual, you must include a docstring for each function you define.
Your first goal is define a function
printGrid
that displays the text grid
for the word search puzzle. It takes a single argument, which is a list
of strings, where each string has the same length (the number of columns
in the grid). It uses
print
to display the
letters in the grid such that
These printGrid
examples
demonstrate how it should work.
Notes:
Recall that the newline character '\n
' causes a printed string to
move to the next line.
Calls to print
normally end with a newline, but this can be
overridden by the keyword argument end
. E.g., print('hello', end=' ')
will display the five characters in hello
followed by a space rather
than a newline.
Your printGrid
function must use a nested
loop
You can test printGrid
and the other wordSearch functions
by running the file test_wordSearch.py
.
Although we have represented the text grid as a list of rows, words
may also be hidden in columns. To make it easier to find these words,
define a function getColumns
that
takes a list of row strings as a parameter, and return a list of
column strings, where the c
th column string is the characters
of the c
th column of the given row strings.
For example, getColumns( ["abcd", "efgh", "ijkl" ] )
should
return the list of column strings ["aei", "bfj", "cgk", dhl"]
.
These getColumns
examples give more examples
how it should work.
getColumns
basically flips the the orientation of the grid
across the diagonal that goes from the upper left to the lower right,
causing input columns to become output rows and input rows to become
output columns. In mathematics, this operation is known as a
transposition when applied to matrices.
Notes:
Make sure your function works with different puzzle sizes!
You can test getColumns
and the other wordSearch functions
by running the file test_wordSearch.py
.
Define a function
findHorizontal(rows,word)
that
finds a single word that is hidden in the puzzle in a horizontal
orientation. It should find words both
in the forward and backward direction. The first parameter, rows
, is a
list of strings representing the puzzle text grid, and word
is the word
to find hidden in the grid.
This function returns a list of positions that indicate where the target word was found (note there might be more than one copy of it). Each location entry is a tuple with 2 components:
When there are multiple matches, they should be ordered according to their row and then column values (matches in earlier rows first, and within a row, matches in earlier columns first).
For example, for the findHorizontal(TEST_PUZZLE, 'center')
,
the resulting list of tuples should be:
[(1, 4)]
because 'center'
appears horizontally in TEST_PUZZLE
once at row 1
starting in column 4.
If instead we had the grid:
selfish = [
'-meme',
'me---'
]
and we ran findHorizontal(selfish, 'me')
we should get the following
list of matches (without the commentary):
[
(0, 1), # first 'me' in row 0. Row 0 comes before row 1.
(0, 2), # start of backwards 'em' that's part of 'meme'
(0, 3), # second 'me' in row 0
(1, 0), # the 'me' in row 1 (second row)
]
These findHorizontal
examples provide more
demonstrations of how findHorizontals
must work.
Notes:
If a word matches both forwards and backwards starting at a particular location (e.g., 'racecar'), we only count that as one match. Because of this, it is not possible for this function to ever return a list containing duplicate positions.
If the word is not found anywhere in the grid, return an empty list.
findHorizontal
must use a nested
loop.
You can test findHorizontal
and the other wordSearch functions
by running the file test_wordSearch.py
.
To count as a match, the letters of a word must appear next to each other in the correct order (or exactly backwards). Letters that are spaced out with other letters in between don't count as a match, even if they all appear in the right order.
Define a function
findWords(rows, wordlist)
that
finds words in wordlist
that are hidden in the puzzle either in a
horizontal or a vertical orientation.. As in
findHorizontal
the first parameter, rows
,
is a list of strings representing the puzzle text grid. wordlist
is a list words (strings) to find.
This function returns a list of location entries that indicate
which words were found and where. Note these are not the same as the
positions findHorizontals
returns. Each location entry is a tuple
with 3 components:
These location entry tuples must be ordered as follows:
findHorizontal
orders them.findHorizontal
will order them when applied to columns
instead of rows.For example, for findWords(TEST_PUZZLE, TEST_WORDS)
,
the result tuples should be:
[
('science', 0, 4),
('center', 1, 4),
('wellesley', 3, 0),
('python', 0, 2),
('computer', 2, 7),
('nested', 7, 0),
('loops', 3, 2)
]
These findWords
examples provide more
demonstrations of how findWords
must work.
Notes:
To find vertical matches, you can simply apply findHorizontal
to
columns instead of rows. Use the getColumns
function you wrote
earlier to get the columns. Your code must call getColumns
at
least once and
must call findHorizontal
at least
twice.
getColumns
result really means you found a vertical word
in column 1 of the actual puzzle.If you order your loops correctly, no extra code is necessary to achieve correct ordering of the final result list.
You can test findWords
and the other wordSearch functions
by running the file test_wordSearch.py
.
The starter code includes a function wordPuzzle.generatePuzzle
that generates random word search puzzles from a list of words
to hide in the puzzle. If you're interested, you can use this
function to generate other puzzles to experiment with.
wordPuzzle.generatePuzzle
takes four arguments:
the number of rows for the puzzle (defaults to 10)
the number of columns for the puzzle (defaults to 20)
a list of words to hide in the puzzle (defaults to a list of words related to tea).
a boolean that indicates whether all words should be
hidden only in the forward and downward orientation.
If True
, the orientation will be restricted to
forward and downward; if False
, the orientation
can be any direction, including backward, upward,
and diagonally.
By default, generatePuzzle
produces a 10x20 text grid with a list of
tea-themed words hidden within it, and where all hidden words are
forward or downward. However, you can supply parameters to change the
default parameters. For instance, to create a puzzle with 5 rows, 10
columns, and some coffee-themed words that can be in any orientation,
you could call:
wordPuzzle.generatePuzzle(
numRow=5, numCols=10,
words=["latte","espresso", "bean", "mocha"],
onlyForwardOrDownward=False
)
wordPuzzle.generatePuzzle
returns a tuple with three values:
numRows
strings, each of length numCols
that represents the rows of a text gridwords
that were successfully
placed in the puzzlewords
that were not
able to be placed in the puzzle.printGrid
examples
These examples demonstrate how printGrid
should work.
In []:PrintsprintGrid(['abcd', 'efgh', 'ijkl'])
a b c d e f g h i j k lIn []:PrintsprintGrid(['ab', 'cd', 'ef', 'gh', 'ij'])
a b c d e f g h i jIn []:PrintsprintGrid( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ] )
- - - - s - - - - - - - - - - - c e n t e r - - p - - - i - - r - - - - y e l s e l l e w - - - t - o - n - - t - - - - h - o - c - - u - - - 1 o - p - e - - p - - 1 - n e s t e d - m - 1 - - - - - - - - - o s - - - - - - - - - - c - - - -
getColumns
examples
These examples demonstrate how getColumns
should work.
In []:Out[]:getColumns(['abcd', 'efgh', 'ijkl'])
In []:['aei', 'bfj', 'cgk', 'dhl']
Out[]:getColumns(['ab', 'cd', 'ef', 'gh', 'ij'])
In []:['acegi', 'bdfhj']
Out[]:getColumns( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ] )
[ '--python--', '---e---e--', '---loops--', '---s---t--', 'sciencee--', '-e-l---d--', '-n-l------', '-tretupmoc', '-e-w----s-', '-r-----1--', '------1---', '-----1----', ]
findHorizontal
examples
These examples demonstrate how findHorizontal
should work. Note how it finds both forwards and backwards matches, but NOT vertical matches.
In []:Out[]:findHorizontal(['----', 'find', '-me-'], 'find')
In []:[(1, 0)]
Out[]:findHorizontal(['----', 'find', '-me-'], 'me')
In []:[(2, 1)]
Out[]:findHorizontal(['dnif', '-e--', '-m--'], 'find')
In []:[(0, 0)]
Out[]:findHorizontal(['dnif', '-e--', '-m--'], 'me')
In []:[]
Out[]:findHorizontal(['-meme', 'me--', '-em-'], 'me')
In []:[(0, 1), (0, 2), (0, 3), (1, 0), (2, 1)]
Out[]:findHorizontal(['find', 'i--n', 'n--i', 'dnif'], 'find')
In []:[(0, 0), (3, 0)]
Out[]:findHorizontal(['find', 'i--n', 'n--i', 'dnif'], 'dnif')
In []:[(0, 0), (3, 0)]
Out[]:findHorizontal( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ], 'wellesley' )
In []:[(3, 0)]
Out[]:findHorizontal( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ], 'center' )
In []:[(1, 4)]
Out[]:findHorizontal( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ], 'science' )
In []:[]
Out[]:findHorizontal( [ 'soacbykymduioaaiylyf', 'tghvnekchamomileztfd', 'arggfqavbkettleigedv', 'chonunnrvipeetsxzafc', 'jgbornnslrehucoqopjh', 'pcwliewixggevzdxyova', 'czpombclperkhlyeztti', 'wayoriouihiexqizxyrm', 'jmgyfngsaioryztcysax', 'ilrovurzcskenimsajny', ], 'kettle' )
In []:[(2, 9)]
Out[]:findHorizontal( [ 'soacbykymduioaaiylyf', 'tghvnekchamomileztfd', 'arggfqavbkettleigedv', 'chonunnrvipeetsxzafc', 'jgbornnslrehucoqopjh', 'pcwliewixggevzdxyova', 'czpombclperkhlyeztti', 'wayoriouihiexqizxyrm', 'jmgyfngsaioryztcysax', 'ilrovurzcskenimsajny', ], 'jasmine' )
In []:[(9, 11)]
Out[]:findHorizontal( [ 'soacbykymduioaaiylyf', 'tghvnekchamomileztfd', 'arggfqavbkettleigedv', 'chonunnrvipeetsxzafc', 'jgbornnslrehucoqopjh', 'pcwliewixggevzdxyova', 'czpombclperkhlyeztti', 'wayoriouihiexqizxyrm', 'jmgyfngsaioryztcysax', 'ilrovurzcskenimsajny', ], 'oolong' )
[]
findWords
examples
These examples demonstrate how findWords
should work.
In []:Out[]:findWords(['----', 'find', '-me-'], ['find', 'me'])
In []:[('find', 1, 0), ('me', 2, 1)]
Out[]:findWords(['-f-', '-im', '-ne', '-d-'], ['find', 'me'])
In []:[('find', 0, 1), ('me', 1, 2)]
Out[]:findWords(['f--', 'i--', 'nme', 'd--'], ['find', 'me'])
In []:[('find', 0, 0), ('me', 2, 1)]
Out[]:findWords( [ '----s-------', '----center--', 'p---i--r----', 'yelsellew---', 't-o-n--t----', 'h-o-c--u---1', 'o-p-e--p--1-', 'nested-m-1--', '-------os---', '-------c----', ], [ 'cs111', 'science', 'center', 'wellesley', 'python', 'computer', 'nested', 'loops', ] )
In []:[ ('science', 0, 4), ('center', 1, 4), ('wellesley', 3, 0), ('python', 2, 0), ('computer', 2, 7), ('nested', 7, 0), ('loops', 3, 2), ]
Out[]:findWords( [ 'soacbykymduioaaiylyf', 'tghvnekchamomileztfd', 'arggfqavbkettleigedv', 'chonunnrvipeetsxzafc', 'jgbornnslrehucoqopjh', 'pcwliewixggevzdxyova', 'czpombclperkhlyeztti', 'wayoriouihiexqizxyrm', 'jmgyfngsaioryztcysax', 'ilrovurzcskenimsajny', ], [ 'chai', 'oolong', 'earlgrey', 'rooibos', 'saucer', 'teapot', 'chamomile', 'jasmine', 'kettle', 'steep', ] )
[ ('chai', 3, 19), ('oolong', 2, 3), ('teapot', 1, 17), ('chamomile', 1, 7), ('jasmine', 9, 11), ('kettle', 2, 9), ('steep', 3, 10), ]
getColumns
must return the correct result
getColumns
function is run must match the solution result.findHorizontal
must return the correct result
findHorizontal
function is run must match the solution result.findHorizontal
must return the correct result
findHorizontal
function is run must match the solution result.findWords
must return the correct result
findWords
function is run must match the solution result.findWords
must return the correct result
findWords
function is run must match the solution result.printGrid
must print the correct output
printGrid
function is run must match the solution output.printGrid
def
to define printGrid
printGrid
, use any kind of loop in at least one place.printGrid
, use any kind of loop in at least one place.print
printGrid
, call print
in at least one place.getColumns
def
to define getColumns
getColumns
, use any kind of loop in at least one place.return
statement
getColumns
, use return _
in at least one place.findHorizontal
def
to define findHorizontal
findHorizontal
, use any kind of loop in at least one place.findHorizontal
, use any kind of loop in at least one place.return
statement
findHorizontal
, use return _
in at least one place.findWords
def
to define findWords
getColumns
findWords
, call getColumns
in exactly one place.findHorizontal
findWords
, call findHorizontal
in exactly 2 places.findWords
def
to define findWords
getColumns
findWords
, call getColumns
in at least one place.findHorizontal
findWords
, call findHorizontal
in at least 2 places.findWords
, use any kind of loop in at least one place.return
statement
findWords
, use return _
in at least one place.