--- /dev/null
+#!/usr/bin/python
+
+import curses
+import curses.ascii
+import locale
+import codecs
+import getopt
+import os
+import sys
+
+locale.setlocale(locale.LC_ALL, '')
+code = locale.getpreferredencoding()
+
+superscript_numbers = {}
+
+try:
+ superscript_numbers = {
+ "0": unichr(8304).encode(code),
+ "1": unichr(185).encode(code),
+ "2": unichr(178).encode(code),
+ "3": unichr(179).encode(code),
+ "4": unichr(8308).encode(code),
+ "5": unichr(8309).encode(code),
+ "6": unichr(8310).encode(code),
+ "7": unichr(8311).encode(code),
+ "8": unichr(8312).encode(code),
+ "9": unichr(8313).encode(code),
+ }
+except:
+ for number in range(0, 10):
+ superscript_numbers[str(number)] = str(number)
+
+filename = None
+
+try:
+ (options, args) = getopt.getopt(sys.argv[1:], "f:", "file=")
+except getopt.GetoptError, err:
+ print str(err)
+ sys.exit(2)
+
+for option in options:
+ if option[0] == "-f" or option[0] == "--file":
+ filename = option[1]
+
+if not filename and len(args) > 0:
+ filename = args[0]
+
+if not filename:
+ sys.stderr.write("No crossword file specified, exiting.\n")
+ sys.exit(0)
+
+if os.path.exists(filename) and os.path.isfile(filename):
+ crossworddata = codecs.open(filename, "r", "utf-8").read()
+else:
+ sys.stderr.write("Couldn't open file %s\n" %(filename))
+ sys.exit(0)
+
+def parsecrossword(crossworddata):
+ ingrid = False
+ inacross = False
+ indown = False
+ crossword = {"grid": [],
+ "across": {},
+ "down": {},
+ "grid_questions_start": [],
+ "grid_questions_end": []}
+
+ for line in crossworddata.split("\n"):
+ line = line.strip("\n")
+ if line == "GRID":
+ ingrid = True
+ inacross = False
+ indown = False
+ elif line == "ACROSS":
+ ingrid = False
+ inacross = True
+ indown = False
+ elif line == "DOWN":
+ ingrid = False
+ inacross = False
+ indown = True
+ else:
+ if ingrid:
+ if line != "":
+ crossword["grid"].append(line)
+ if inacross:
+ if line != "":
+ parts = line.split()
+ question_number = int(parts[0])
+ clue = " ".join(parts[1:])
+ crossword["across"][int(question_number)] = \
+ clue.encode(code)
+ if indown:
+ if line != "":
+ parts = line.split()
+ question_number = int(parts[0])
+ clue = " ".join(parts[1:])
+ crossword["down"][int(question_number)] = clue.encode(code)
+ num_cols = len(crossword["grid"][0])
+ num_rows = len(crossword["grid"])
+
+ current_clue_number = 1
+
+ for row in range(0, num_rows):
+ crossword["grid_questions_start"].append([])
+
+ for row in range(0, num_rows):
+ for col in range(0, num_cols):
+ have_clue = False
+ if col > 0 \
+ and crossword["grid"][row][col - 1] == "x" \
+ and crossword["grid"][row][col] != "x" \
+ and col < (num_cols - 1) \
+ and crossword["grid"][row][col + 1] != "x":
+ have_clue = True
+ if col == 0 and crossword["grid"][row][col] != "x" \
+ and crossword["grid"][row][col + 1] != "x":
+ have_clue = True
+ if row > 0 and crossword["grid"][row-1][col] == "x" \
+ and row < (num_rows - 1) \
+ and crossword["grid"][row][col] != "x" \
+ and crossword["grid"][row + 1][col] != "x":
+ have_clue = True
+ if row == 0 and crossword["grid"][row][col] != "x" \
+ and crossword["grid"][row + 1][col] != "x":
+ have_clue = True
+ if have_clue:
+ crossword["grid_questions_start"][row] \
+ .append(current_clue_number)
+ current_clue_number += 1
+ else:
+ crossword["grid_questions_start"][row].append(0)
+
+ return crossword
+
+def crossword(stdscr, crossworddata):
+ crossword = parsecrossword(crossworddata)
+ cury = 0
+ grid_length = len(crossword["grid"][0])
+ curx = 0
+ stdscr.addch(cury, curx, curses.ACS_ULCORNER)
+ curx += 1
+ while ((curx - 1) / 4) < grid_length:
+ stdscr.addch(cury, curx, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+1, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+2, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+3, curses.ACS_TTEE)
+ curx += 4
+ curx -= 1
+ stdscr.addch(cury, curx, curses.ACS_URCORNER)
+ cury += 1
+ curgridy = 0
+ for line in crossword["grid"]:
+ datastr = ""
+ curx = 0
+ curgridx = 0
+ for c in line:
+ stdscr.addch(cury, curx, curses.ACS_VLINE)
+ if curx > 0:
+ stdscr.addch(cury+1, curx, curses.ACS_PLUS)
+ else:
+ stdscr.addch(cury+1, curx, curses.ACS_LTEE)
+ stdscr.addch(cury+1, curx + 1, curses.ACS_HLINE)
+ stdscr.addch(cury+1, curx + 2, curses.ACS_HLINE)
+ stdscr.addch(cury+1, curx + 3, curses.ACS_HLINE)
+ curx += 1
+ if c == "x":
+ stdscr.addch(cury, curx, curses.ACS_BLOCK)
+ stdscr.addch(cury, curx+1, curses.ACS_BLOCK)
+ stdscr.addch(cury, curx+2, curses.ACS_BLOCK)
+ elif crossword["grid_questions_start"][curgridy][curgridx] > 0:
+ stdscr.addstr(cury, curx, \
+ ''.join( \
+ [superscript_numbers[x].decode(code) \
+ for x in str( \
+ crossword["grid_questions_start"] \
+ [curgridy][curgridx])]\
+ ).encode(code))
+ curx += 3
+ curgridx += 1
+ else:
+ stdscr.addch(cury, curx, curses.ACS_VLINE)
+ stdscr.addch(cury + 1, curx, curses.ACS_RTEE)
+ cury += 2
+ curgridy += 1
+ cury -= 1
+ curx = 0
+ stdscr.addch(cury, curx, curses.ACS_LLCORNER)
+ curx += 1
+ while ((curx - 1) / 4) < grid_length:
+ stdscr.addch(cury, curx, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+1, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+2, curses.ACS_HLINE)
+ stdscr.addch(cury, curx+3, curses.ACS_BTEE)
+ curx += 4
+ curx -= 1
+ stdscr.addch(cury, curx, curses.ACS_LRCORNER)
+ # draw the clues in
+ cury = (len(crossword["grid"]) * 2) + 1
+ curx = 0
+ stdscr.addstr(cury, curx, "Across")
+ cury += 1
+ for cluenumber in crossword["across"].keys():
+ stdscr.addstr(cury, curx, "%3s: %s" \
+ %(str(cluenumber), crossword["across"][cluenumber]))
+ cury += 1
+
+ cury += 1
+ stdscr.addstr(cury, curx, "Down")
+ cury += 1
+ for cluenumber in crossword["down"].keys():
+ stdscr.addstr(cury, curx, "%3s: %s" \
+ %(str(cluenumber), crossword["down"][cluenumber]))
+ cury += 1
+
+ curx = 3
+ cury = 1
+ gridx = 0
+ gridy = 0
+
+ while crossword["grid"][gridy][gridx] == "x":
+ curx += 4
+ gridx += 1
+
+ stdscr.move(cury, curx)
+
+ while 1:
+ c = stdscr.getch()
+ if c == curses.ascii.ESC:
+ break
+ if c == curses.KEY_RIGHT:
+ if gridx < (len(crossword["grid"][0]) - 1):
+ gridx += 1
+ curx += 4
+ while gridx < (len(crossword["grid"][0]) -1) \
+ and crossword["grid"][gridy][gridx] == "x":
+ gridx += 1
+ curx += 4
+ while crossword["grid"][gridy][gridx] == "x":
+ gridx -= 1
+ curx -= 4
+ stdscr.move(cury, curx)
+ if c == curses.KEY_LEFT:
+ if gridx > 0:
+ curx -= 4
+ gridx -= 1
+ while gridx > 0 \
+ and crossword["grid"][gridy][gridx] == "x":
+ gridx -= 1
+ curx -= 4
+ while crossword["grid"][gridy][gridx] == "x":
+ gridx += 1
+ curx += 4
+ stdscr.move(cury, curx)
+ if c == curses.KEY_UP:
+ if gridy > 0:
+ gridy -= 1
+ cury -= 2
+ while gridy > 0 \
+ and crossword["grid"][gridy][gridx] == "x":
+ gridy -= 1
+ cury -= 2
+ while crossword["grid"][gridy][gridx] == "x":
+ gridy += 1
+ cury += 2
+ stdscr.move(cury, curx)
+ if c == curses.KEY_DOWN:
+ if gridy < (len(crossword["grid"]) - 1):
+ gridy += 1
+ cury += 2
+ while gridy < (len(crossword["grid"]) - 1) \
+ and crossword["grid"][gridy][gridx] == "x":
+ gridy += 1
+ cury += 2
+ while crossword["grid"][gridy][gridx] == "x":
+ gridy -= 1
+ cury -= 2
+ stdscr.move(cury, curx)
+ if curses.ascii.isalpha(c) or c == ord(" "):
+ stdscr.addch(cury, curx, c)
+ stdscr.move(cury, curx)
+ if c == curses.KEY_BACKSPACE or c == curses.KEY_DC:
+ stdscr.addch(cury, curx, ord(" "))
+ stdscr.move(cury, curx)
+
+
+curses.wrapper(crossword, crossworddata)