Chess.py:

Chess/PGN Manipulation

in Python

A Short

FunnelWeb .fw File


by Hugh S. Myers

29 January 2000




1. Table of Contents

1. Table of Contents
2. A collection of functions
     2.1. Chess.py
               2.1.1. The necessary inclusions and imports
               2.1.2. The library tables
                    2.1.2.1. Standard set of PGN Tags
                    2.1.2.2. All possible diagonal moves
                         2.1.2.2.1. Diagonal from upper left to lower right
                         2.1.2.2.2. Diagonal from lower left to upper right
                    2.1.2.3. All posible knight moves
                    2.1.2.4. All vertical and horizontal moves
                         2.1.2.4.1. Row (rank) from left to right
                         2.1.2.4.2. File (column) from bottom to top
               2.1.3. The library code, objects, and methods
                    2.1.3.1. Convert from PGN to XML
                         2.1.3.1.1. Get games and convert to XML
                         2.1.3.1.2. Convert games and write to stdout
                         2.1.3.1.3. Convert game and write to stdout
                    2.1.3.2. Functions for chess taxonomy
                         2.1.3.2.1. The connection to a database of chess opening names
                         2.1.3.2.2. The connection to a particular table of chess opening names
                         2.1.3.2.3. Given a list of positions, return a name
                    2.1.3.3. Routines hard to classify
                         2.1.3.3.1. Display chart to stdout


2. A collection of functions

This is a small collection of functions useful for parsing PGN (chess games scores in Portable Game Notation) files. These routines perform a variety of services for the user/player.


2.1. Chess.py

1. File: Chess.py={Header Material
Tabular Material
The Code
}
This macro is attached to an output file.


2.1.1. The necessary inclusions and imports

These are the python modules the chess library uses.

2. Header Material={import gtparse
import re
import string
from types import *
from win32com.client.dynamic import Dispatch
}
This macro is invoked in definition 1.


2.1.2. The library tables

3. Tabular Material={taglist
lookup tables for diagonal moves
knight_moves
row(rank) and column(file) move lookup tables
}
This macro is invoked in definition 1.


2.1.2.1. Standard set of PGN Tags

4. taglist={taglist = [
  'Event','Site','Date','Round','White',
  'Black','Result','NIC','ECO','Opening'
  ]
}
This macro is invoked in definition 3.


2.1.2.2. All possible diagonal moves

5. lookup tables for diagonal moves={leftdiagonal
rightdiagonal
}
This macro is invoked in definition 3.


2.1.2.2.1. Diagonal from upper left to lower right

6. leftdiagonal={leftdiagonal = [
  [8,1],[16,9,2],[24,17,10,3],[32,25,18,11,4],
  [40,33,26,19,12,5],[48,41,34,27,20,13,6],
  [56,49,42,35,28,21,14,7],[57,50,43,36,29,22,15],
  [58,51,44,37,30,23],[59,52,45,38,31],[60,53,46,39],
  [61,54,47],[62,55]
  ]
}
This macro is invoked in definition 5.


2.1.2.2.2. Diagonal from lower left to upper right

7. rightdiagonal={rightdiagonal = [
  [48,57],[40,49,58],[32,41,50,59],[24,33,42,51,60],
  [16,25,34,43,52,61],[8,17,26,35,44,53,62],
  [0,9,18,27,36,45,54,63],[1,10,19,28,37,46,55],
  [2,11,20,29,38,47],[3,12,21,30,39],[4,13,22,31],
  [5,14,23],[6,15]
  ]
}
This macro is invoked in definition 5.


2.1.2.3. All posible knight moves

8. knight_moves={knight_moves = [
  [17,10],
  [16,18,11],
  [8,17,19,12],
  [9,18,20,13],
  [10,19,21,14],
  [11,20,22,15],
  [12,21,23],
  [13,22],
  [25,18,2],
  [24,26,19,3],
  [0,16,25,27,20,4],
  [1,17,26,28,21,5],
  [2,18,27,29,22,6],
  [3,19,28,30,23,7],
  [4,20,29,31],
  [5,21,30],
  [1,10,26,33],
  [0,2,11,27,34,32],
  [1,8,24,33,35,28,12,3],
  [2,9,25,34,36,29,13,4],
  [3,10,26,35,37,30,14,5],
  [4,11,27,36,38,31,15,6],
  [5,12,28,37,39,7],
  [6,13,29,38],
  [9,18,34,41],
  [8,10,19,35,42,40],
  [9,16,32,41,43,36,20,11],
  [10,17,33,42,44,37,21,12],
  [11,18,34,43,45,38,22,13],
  [12,19,35,44,46,39,23,14],
  [13,20,36,45,47,15],
  [14,21,37,46],
  [17,26,42,49],
  [16,18,27,43,50,48],
  [17,19,28,44,51,49,40,24],
  [18,20,29,45,52,50,41,25],
  [19,21,30,46,53,51,42,26],
  [20,22,31,47,54,52,43,27],
  [21,23,55,53,44,28],
  [22,54,45,29],
  [25,34,50,57],
  [24,26,35,51,58,56],
  [25,27,36,52,59,57,48,32],
  [26,28,37,53,60,58,49,33],
  [27,29,38,54,61,59,50,34],
  [28,30,39,55,62,60,51,35],
  [29,31,63,61,52,36],
  [30,37,53,62],
  [33,42,58],
  [32,34,43,59],
  [33,35,44,60,56,40],
  [34,36,45,61,57,41],
  [35,37,46,62,58,42],
  [36,38,47,63,59,43],
  [37,39,60,44],
  [38,61,45],
  [41,50],
  [40,42,51],
  [41,43,52,48],
  [42,44,53,49],
  [43,45,54,50],
  [44,46,55,51],
  [45,47,52],
  [46,53]]
}
This macro is invoked in definition 3.


2.1.2.4. All vertical and horizontal moves

9. row(rank) and column(file) move lookup tables={rank
file
}
This macro is invoked in definition 3.


2.1.2.4.1. Row (rank) from left to right

10. rank={rank = [
  [0,1,2,3,4,5,6,7],
  [8,9,10,11,12,13,14,15],
  [16,17,18,19,20,21,22,23],
  [24,25,26,27,28,29,30,31],
  [32,33,34,35,36,37,38,39],
  [40,41,42,43,44,45,46,47],
  [48,49,50,51,52,53,54,55],
  [56,57,58,59,60,61,62,63]
  ]
}
This macro is invoked in definition 9.


2.1.2.4.2. File (column) from bottom to top

11. file={file = [
  [0,8,16,24,32,40,48,56],
  [1,9,17,25,33,41,49,57],
  [2,10,18,26,34,42,50,58],
  [3,11,19,27,35,43,51,59],
  [4,12,20,28,36,44,52,60],
  [5,13,21,29,37,45,53,61],
  [6,14,22,30,38,46,54,62],
  [7,15,23,31,39,47,55,63]
  ]
}
This macro is invoked in definition 9.


2.1.3. The library code, objects, and methods

12. The Code={PGN to XML functions
Position Classification functions
Miscellaneous
}
This macro is invoked in definition 1.


2.1.3.1. Convert from PGN to XML

13. PGN to XML functions={PGN2XML
PrintAllXML
PrintGameXML
}
This macro is invoked in definition 12.


2.1.3.1.1. Get games and convert to XML

14. PGN2XML={def PGN2XML(gamepath,dbpath):
  ChessDB = db(dbpath)
  rsNIC = Recordset(ChessDB,'NIC')
  rsECO = Recordset(ChessDB,'ECO')
  rsOpening = Recordset(ChessDB,'Opening')
  games = GetGames(gamepath)
  PrintAllXML(games,[rsNIC,rsECO,rsOpening])
}
This macro is invoked in definition 13.


2.1.3.1.2. Convert games and write to stdout

15. PrintAllXML={def PrintAllXML(g,rs):
  print '<?xml version="1.0" encoding="UTF-8"?>'
  print '<?xml-stylesheet type="text/xsl" href="pgn.xsl"?>'
  print '<!DOCTYPE CHESSGAMES SYSTEM "pgn.dtd">'
  print '<CHESSGAMES>'
  for game in g:
    PrintGameXML(game,rs)
  print '</CHESSGAMES>'
}
This macro is invoked in definition 13.


2.1.3.1.3. Convert game and write to stdout

16. PrintGameXML={def PrintGameXML(g,rs):
  TaxonomyList = ['NIC','ECO','Opening']
  b = Board()
  f = b.Test(g[1],0)
  l = string.split(b.Diagram(),'\n')[:-1]
  print '\t<GAME>'
  print '\t\t<TAGLIST>'
  for tag in taglist:
    if tag == 'Date':
      datelst = string.split(g[0][tag],'.')
      n = len(datelst)
      if n == 0:
        print '\t\t\t<DATE YEAR="?" MONTH="?" DAY="?"/>'
      elif n == 1:
        print '\t\t\t<DATE YEAR="' + datelst[0] + '" MONTH="?" DAY="?"/>'
      elif n == 2:
        print '\t\t\t<DATE YEAR="' + datelst[0] + '" MONTH="' + datelst[1] + '" DAY="?"/>'
      elif n == 3:
        print '\t\t\t<DATE YEAR="' + datelst[0] + '" MONTH="' + datelst[1] + '" DAY="' + datelst[2] + '"/>'
    elif tag == 'Result':
      if g[0][tag] == '0-1':
        print '\t\t\t<RESULT GAMERESULT="BLACKWIN"/>'
      elif g[0][tag] == '1-0':
        print '\t\t\t<RESULT GAMERESULT="WHITEWIN"/>'
      elif g[0][tag] == '1/2-1/2':
        print '\t\t\t<RESULT GAMERESULT="DRAW"/>'
      elif g[0][tag] == '*':
        print '\t\t\t<RESULT GAMERESULT="UNKNOWN"/>'
    elif tag in TaxonomyList and g[0][tag] == '?':
      OpeningCode = FindFEN(f,rs[TaxonomyList.index(tag)])
      if OpeningCode:
        g[0][tag] = OpeningCode
      print '\t\t\t<%s>%s</%s>' % (string.upper(tag),g[0][tag],string.upper(tag))
    else:
      print '\t\t\t<%s>%s</%s>' % (string.upper(tag),g[0][tag],string.upper(tag))
  print '\t\t</TAGLIST>'
  print '\t\t<GAMETEXT>'
  movetext = ''
  movenumber = 1
  whitetomove = 1
  for move in g[1]:
    if not gtparse.ismove(move[0]):
      themove = move
    else:
      if move in ['1-0','0-1','1/2-1/2','*']:
        themove = '<GAMETERMINATION>' + move + '</GAMETERMINATION>'
      elif whitetomove and 1:
        themove = '<MOVENUMBER>%d</MOVENUMBER>' % (movenumber) + '<MOVE>' + move + '</MOVE>'
        movenumber = movenumber + 1
      else:
        themove = '<MOVE>' + move + '</MOVE>'
      whitetomove = not whitetomove
    if len(movetext) + len(themove) <= 80:
      movetext = movetext + themove
    else:
      print '\t\t\t\t' + movetext
      movetext = themove
  print '\t\t\t\t' + movetext
  print '\t\t</GAMETEXT>'
  print '\t\t<POSITION>'
  print '\t\t\t<TOP>'+l[0]+'</TOP>'
  print '\t\t\t<R8>'+l[1]+'</R8>'
  print '\t\t\t<R7>'+l[2]+'</R7>'
  print '\t\t\t<R6>'+l[3]+'</R6>'
  print '\t\t\t<R5>'+l[4]+'</R5>'
  print '\t\t\t<R4>'+l[5]+'</R4>'
  print '\t\t\t<R3>'+l[6]+'</R3>'
  print '\t\t\t<R2>'+l[7]+'</R2>'
  print '\t\t\t<R1>'+l[8]+'</R1>'
  print '\t\t\t<BOTTOM>'+l[9]+'</BOTTOM>'
  print '\t\t</POSITION>'
  print '\t</GAME>'
}
This macro is invoked in definition 13.


2.1.3.2. Functions for chess taxonomy

17. Position Classification functions={Get a Database Object
Get a Recordset Object
Get an Opening name or code
}
This macro is invoked in definition 12.


2.1.3.2.1. The connection to a database of chess opening names

18. Get a Database Object={def db(path):
  dbEngine = Dispatch('DAO.DBEngine.35')
  db = dbEngine.OpenDatabase(path)
  return db
}
This macro is invoked in definition 17.


2.1.3.2.2. The connection to a particular table of chess opening names

19. Get a Recordset Object={def Recordset(db,Which):
  rs = db.OpenRecordset(Which)
  rs.Index = 'FEN'
  return rs
}
This macro is invoked in definition 17.


2.1.3.2.3. Given a list of positions, return a name

20. Get an Opening name or code={def FindFEN(f,rs):
  result = ''
  lst = f[:]
  lst.reverse()
  for fen in lst:
    rs.Seek('=',fen)
    if not rs.NoMatch:
      result = rs.Fields[1].Value
      break;
  return result
}
This macro is invoked in definition 17.


2.1.3.3. Routines hard to classify

21. Miscellaneous={Grid
}
This macro is invoked in definition 12.


2.1.3.3.1. Display chart to stdout

22. Grid={def Grid():
  for i in range(56,-1,-8):
    for j in range(i,i + 8):
      print "%02d" % (j),
    print
}
This macro is invoked in definition 21.


End Of File