#!/usr/bin/env python """Sudoku puzzle downloader and printer. Uses puzzles from websudoku.com""" #Copyright (C) 2008 Patrick Tait # #This program is free software: you can redistribute it and/or modify #it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or #(at your option) any later version. # #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. # #You should have received a copy of the GNU General Public License #along with this program. If not, see . import urllib from psxml import * import string import time import sys FourWideCell = True #3 spaces + charictor, or 2 spaces + charictor. #4 looks better with 80 char width printer, 3 looks better #with 40 charicter width printer def GetPuzzle(Level): """Downloads the puzzle page, scrapes the HTML for the needed information. returns a 2d list with empty cells noted with a " ".""" puzzle = urllib.urlopen("http://show.websudoku.com/?level=%s" % Level) XMLRAW = Parse(puzzle.read()) XML = [ii for ii in XMLRAW]#psxml is meant to be a stream parser, #this lets you access the entire page. Puzzle = [] FormStart = -1 FormEnd = len(XML) TableStart = -1 TableEnd = -1 #find the range of the form. The relevant form name is board. for ii in range(len(XML)): if XML[ii].__class__ is EndTag and XML[ii] == "FORM": FormEnd = ii elif XML[ii] == "FORM": if "name" in XML[ii].Attr.keys() and \ XML[ii].Attr["name"] == "board": FormStart = ii if FormStart == -1: print "Coudn't find forum start" # XXX return False #find the range of the table for ii in range(FormStart, FormEnd): if XML[ii] == "TABLE": if XML[ii].__class__ is StartTagAttr or \ XML[ii].__class__ is StartTag: TableStart = ii elif XML[ii].__class__ is EndTag: TableEnd = ii if TableStart == -1 or TableEnd == -1: print "Coudn't find table start" # XXX return False #parse the data. The values are in "INPUT" tags. for ii in XML[TableStart:TableEnd]: if ii == "TR" and ii.__class__ is not EndTag: Puzzle.append([]) elif ii == "INPUT": if "value" in ii.Attr.keys(): Puzzle[-1].append(ii.Attr["value"]) else: Puzzle[-1].append(" ") return Puzzle def DisplayPuzzle(Puzzle): """Quick debug function to print puzzles. Blank cells have an X""" for ii in Puzzle: for jj in ii: if jj == " ": jj = "X" print " %s" % jj, print "\n", term = 0 printer = 1 def PrettyPuzzle(Puzzle, Set = term): """Formats the puzzle into printable format. Set determines the charicter set used for printing. term is for terminal output, printer is for the DPU-411 printer with the international switches set XXX. """ if Set == printer: norm = string.maketrans('', '') TLcorner = norm[152] #Top left corner TRcorner = norm[153] #Top right corner Tdiv = norm[149] #Top horizontal division TCol = norm[145] #Top columnular division BLcorner = norm[154] #Bottom Left corner BRcorner = norm[155] #Bottom Right corner Bdiv = norm[149] #Bottom horizontal division BCol = norm[144] #Bottom columnular division LBorder = norm[150] #Left vertical border LRow = norm[147] #Left row border RBorder = norm[150] #Right vertical border RRow = norm[146] #Right row border SVdiv = norm[135] #Region vertical division SHdiv = norm[135] #Region horizontal division SCdiv = norm[135] #Region Central division CVdiv = norm[150] #Cell Vertical division CHdiv = norm[149] #Cell horizontal division CCdiv = norm[143] #Cell central division elif Set == term: TLcorner = '+' #Top left corner TRcorner = '+' #Top right corner Tdiv = '-' #Top horizontal division TCol = '-' #Top columnular division BLcorner = '+' #Bottom Left corner BRcorner = '+' #Bottom Right corner Bdiv = '-' #Bottom horizontal division BCol = '-' #Bottom columnular division LBorder = '|' #Left vertical border LRow = '|' #Left row border RBorder = '|' #Right vertical border RRow = '|' #Right row border SVdiv = '#' #Region vertical division SHdiv = '#' #Region horizontal division SCdiv = '#' #Region Central division CVdiv = '|' #Cell Vertical division CHdiv = '-' #Cell horizontal division CCdiv = '+' #Cell central division Output = "" Rows = 9 Cols = 9 CurRow = 1 CurCol = 1 #Outputs the top row Output += TLcorner for ii in range(Cols): Output += Tdiv if FourWideCell: Output += Tdiv Output += Tdiv Output += Tdiv Output += TCol Output = Output[0:-1] + TRcorner Output += "\n" #step through the puzzle's rows for ii in Puzzle: Output += LBorder CurCol = 1 #step through the cells in a row for jj in ii: Output += " " Output += jj Output += " " if FourWideCell: Output += " " if CurCol % 3 == 0: #major devision, between regions Output += SVdiv else: #minor devision Output += CVdiv CurCol += 1 Output = Output[0:-1] + RBorder Output += "\n" #Output a column divider if CurRow == Rows: #Last row Output += BLcorner #Bottom Row for ii in range(Cols): Output += Bdiv Output += Bdiv if FourWideCell: Output += Bdiv Output += Bdiv Output += BCol Output = Output[0:-1] + BRcorner Output += "\n" elif CurRow % 3 == 0: #region divider Output += LRow for jj in range(Cols): Output += SHdiv Output += SHdiv if FourWideCell: Output += SHdiv Output += SHdiv Output += SCdiv Output = Output[0:-1] + RRow Output += "\n" else: Output += LRow for jj in range(Cols): Output += CHdiv if FourWideCell: Output += CHdiv Output += CHdiv Output += CHdiv if (jj + 1) % 3 == 0: Output += SCdiv else: Output += CCdiv Output = Output[0:-1] + RRow Output += "\n" CurRow += 1 return Output def SerPrint(Puzzle, port = 0): """prints the puzzle to a serial port, with a 2.5 second delay between lines. Meant to allow printing to the "DPU-411" printer. """ import serial Ser = serial.Serial(port) Ser.write(" .\n") time.sleep(2.5) Ser.flush() Output = PrettyPuzzle(Puzzle, printer) for ii in Output.split("\n"): Ser.write(ii + "\n") Ser.flush() time.sleep(2.5) Ser.write("\n\n\n") Ser.write("\n\n\n") Ser.close() if __name__ == "__main__": if len(sys.argv) > 1: Diff = sys.argv[1] if len(sys.argv) > 2: Port = int(sys.argv[2]) SerPrint(GetPuzzle(Diff), Port) else: print PrettyPuzzle(GetPuzzle(Diff), Set = term) else: print \ """Usage: sudoku.py , If no serial port is specified, it prints to stout. """