Chess.py:
|
Chess/PGN Manipulation
|
in Python
|
A Short
|
FunnelWeb .fw File
|
by Hugh S. Myers
|
29 January 2000
|
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. |
1. File: Chess.py={Header Material
Tabular Material
The Code
}
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
}
3. Tabular Material={taglist
lookup tables for diagonal moves
knight_moves
row(rank) and column(file) move lookup tables
}
4. taglist={taglist = [
'Event','Site','Date','Round','White',
'Black','Result','NIC','ECO','Opening'
]
}
5. lookup tables for diagonal moves={leftdiagonal
rightdiagonal
}
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]
]
}
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]
]
}
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]]
}
9. row(rank) and column(file) move lookup tables={rank
file
}
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]
]
}
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]
]
}
12. The Code={PGN to XML functions
Position Classification functions
Miscellaneous
}
13. PGN to XML functions={PGN2XML
PrintAllXML
PrintGameXML
}
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])
}
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>'
}
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>'
}
17. Position Classification functions={Get a Database Object
Get a Recordset Object
Get an Opening name or code
}
18. Get a Database Object={def db(path):
dbEngine = Dispatch('DAO.DBEngine.35')
db = dbEngine.OpenDatabase(path)
return db
}
19. Get a Recordset Object={def Recordset(db,Which):
rs = db.OpenRecordset(Which)
rs.Index = 'FEN'
return rs
}
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
}
21. Miscellaneous={Grid
}
22. Grid={def Grid():
for i in range(56,-1,-8):
for j in range(i,i + 8):
print "%02d" % (j),
print
}