Thanks very much, @PMunch!
I've learnt a lot.
But for the 2nd algo, in the Python slice g[i::j][:L] is to loop from index i
to end with step j. Not i to j => g[i:j].
Python has this [start:end:step] slice.
Hence, I don't know how to convert this in nim.
#-------------------------------------------------------------------------------
# Name: WordSearch.nim
# Purpose: Find word in a grid of letters in any directions.
#-------------------------------------------------------------------------------
import std/[strutils, strformat, enumerate, sugar, tables, algorithm]
# Implement divmod for nim-lang.
proc divmod(a, b: int): (int, int) =
let
res = a div b # integer division
rem = a mod b # integer modulo operation
(res, rem)
# Procedure to print the grid of letters with row numbers & column letters.
proc print_grid(puzzle: string) =
var lastRow: string
let newGrid = puzzle.replace(" ", "")
for i, row in enumerate(1, newGrid.split('\n')):
# Print top column letters heading.
if i == 1:
stdout.write " "
for m in 0 ..< len(row):
stdout.write fmt"{chr(ord('a')+m)} "
echo()
stdout.write " +"
stdout.write "-".repeat(2 * len(row) + 1)
echo "+"
# Print row numbers heading.
stdout.write fmt"{i:02}| "
for m in row:
stdout.write fmt"{m} "
echo(fmt"|{i:02}")
# row is out of scope after the for-loop in Nim.
# Need a var lastRow to store the last value.
lastRow = row
# Print bottom column letters heading.
stdout.write " +"
stdout.write "-".repeat(2 * len(lastRow) + 1)
echo "+"
stdout.write " "
for m in 0 ..< len(lastRow):
stdout.write fmt"{chr(ord('a')+m)} "
echo()
# Algo1: Procedure to find word in grid of letters using Table.
proc solve_puzzle(puzzle: string; clues: seq) =
let
newGrid = puzzle.replace(" ", "")
length = newGrid.find('\n') + 1
# Make a list of tuples containing each letter and its row and column.
letters = collect(newSeq):
for index, letter in enumerate(newGrid): (letter, divmod(index,
length))
# Reorder the list to represent each reading direction,
# and add them all to a dictionary.
var lines = initTable[string, typeof(letters)]()
let offsets = {"down": 0, "left down": -1, "right down": 1}.toTable
for direction, offset in offsets:
lines[direction] = @[] # Empty seq.
for i in 0 ..< length:
for j in countup(i, letters.high, length + offset):
lines[direction].add(letters[j])
lines[direction].add(('\n', (0, 0)))
lines["right"] = letters
lines["left"] = letters.reversed
lines["up"] = lines["down"].reversed
lines["left up"] = lines["right down"].reversed
lines["right up"] = lines["left down"].reversed
# Make strings from the letters, find the words in them and retrieve
# their original locations.
var nc = 0
for direction, tup in lines:
let myStr = block:
var x = ""
for line in tup: x &= line[0]
x
for word in clues:
if word.toUpper() in myStr:
nc = nc + 1
var location = tup[myStr.find(word.toUpper())][1]
echo fmt"{word.toUpper()}: row[{location[0] + 1:02}]
col[{chr(ord('a') + location[1])}] {direction}"
if (nc mod 5) == 0 and nc < clues.len:
echo "-".repeat 35
# Algo2: Function to find word in grid of letters using Array.
proc find_word(puzzle: string; word: string) =
echo(fmt"{word}:")
let newGrid = puzzle.replace(" ","")
let w = newGrid.find("\n")+1
let L = word.len
var res: seq[(int, int)]
for i in 0 ..< len(newGrid):
for j in @[-w-1, -w, -w+1, -1, 1, w-1, w, w+1]:
for x in i ..< i+(L-1)*j:
if newGrid[i..j][0..L] == word.toUpper():
res.add((x div (w + 1), (x mod w) + 1))
for t in res:
echo " --> ".join("Row[t[0]:02] Col[{chr(ord('a') + t[1] - 1)}]")
when is_main_module:
# Define the puzzle.
let puzzle = """I U W S S W E D E N F Q S M V R P B
B M I D F I N D I A H I S P W Y Y L
H T E N I G E R I A I O N V A M C P
Y Y H X R L E B E T G R J L O I A A
H N X A I U E Z F R A N C E A E N N
V R O T I C S N B E L G I U M N A A
N F R R Y L O S G I C V M N V E D M
W N X F W V A I I L T O Z I H A A A
G H A N A A M N X A A A F B K I N B
G R E E C E Y A D A D N L Z U D F Z
T P K P Q J A P A N T Q D Y D L V I
V K A M E R I C A D C H I N A B C X"""
let clues = @["Belgium", "Greece", "Canada", "Japan", "England",
"Italy", "France", "Panama", "India", "Mexico",
"Norway", "Spain", "China", "Thailand", "Sweden",
"Ghana", "Russia", "Finland", "Nigeria", "America"]
# Print the grid.
print_grid(puzzle)
# Find the words.
echo()
echo "=".repeat 40
solve_puzzle(puzzle, clues)
echo "=".repeat 40
# Another algo to find words.
echo()
echo "=".repeat 40
var nw: int = 0
for word in clues:
nw = nw + 1
find_word(puzzle, word)
if nw mod 5 == 0 and nw < len(clues):
echo "-".repeat 35
else:
if nw!=len(clues):
echo()
echo "=".repeat 40
echo()
Run
I renamed the 2nd algo procedure to find_word().
Running this, I hit this runtime error:
========================================
Belgium:
/usercode/in.nim(141) in
/usercode/in.nim(103) find_word
/playground/nim/lib/system.nim(2566) []
/playground/nim/lib/system/fatal.nim(53) sysFatal
Error: unhandled exception: index 2 not in 0 .. 1 [IndexDefect]