Skip to content

Instantly share code, notes, and snippets.

@schoblaska
Created March 11, 2012 20:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save schoblaska/2017981 to your computer and use it in GitHub Desktop.
Save schoblaska/2017981 to your computer and use it in GitHub Desktop.
Chess FEN plugin for Anki, modified to display the board from black's perspective if it is his turn to move: http://uucode.com/blog/2011/06/27/chess-fen-plugin-for-anki/
# chess fen
# Anki plugin to generate chess diagramms
# ===========================================================
#
# The plugin converts "fen" tag to a corresponding image.
#
# The original text:
#
# :: Do you like this position?
# :: [fen]rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1[/fen]
#
# After processing:
#
# :: <img src="xxxxx" width="nn" height="nn" border="1" /><br />
# :: <b style="color:gray;font-size:50%;">[fen]rnbqkbnr/pppppppp
# :: /8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1[/fen]</b>
#
# The images are generated and stored in the deck's media directory.
# An image is generated only if it does not exist. The plugin never
# deletes images. It is possible to test diagramm generation from
# the command line, see the comments inside "chess_fen.py".
#
# Installation
# -----------------------------------------------------------
#
# Install the fen plugin from the anki plugins repository.
#
# While it is not available there, unpack the archive into
# the anki's plugin folder. Under Linux is it
# $HOME/.anki/plugins
#
# License
# -----------------------------------------------------------
#
# The GNU General Public License
#
# Author
# -----------------------------------------------------------
#
# Oleg Parashchenko, olpa@ http://uucode.com/
import os, sys, re
import hashlib
import PyQt4.QtCore
import PyQt4.QtGui
# To execute a command-line test:
# export TEST_ANKI_FEN='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
# python chess_fen.py
# In anki mode, this enables a few verbose messages
# export TEST_ANKI_FEN_VERBOSE=1
# Some settings
px_cell_width = 45
white_cell_color = (0xc6, 0xc3, 0x63)
black_cell_color = (0x73, 0xa2, 0x6b)
# With fen-string as input, visit each cell of the chessboard and
# return the figure for each cell and its coordinates
class gen_next:
def __init__(self, s_fen, px_step):
self.s_fen = s_fen
self.px_step = px_step
self.s_idx = 0
self.n_empty = 0
self.x = 0
self.y = 0
def get_next(self):
fig = '?'
if not self.n_empty:
if self.s_idx < len(self.s_fen):
fig = self.s_fen[self.s_idx]
if '/' != fig:
self.s_idx = self.s_idx + 1
self.n_empty = '12345678'.find(fig) + 1
if self.n_empty:
self.n_empty = self.n_empty - 1
fig = '?'
cur_x = self.x
self.x = cur_x + self.px_step
return (fig, cur_x, self.y)
def eol(self):
self.s_idx = self.s_fen.find('/', self.s_idx) + 1
self.x = 0
self.y = self.y + self.px_step
#
# Images of figures. See chess_fen_media/README.
#
letter_to_picture = {}
def load_figures(media_dir):
def load_figure(ch, path_part):
png_file = os.path.join(media_dir, 'Chess_'+path_part+'45.png')
letter_to_picture[ch] = PyQt4.QtGui.QPixmap(png_file)
for ch in ('k', 'q', 'r', 'b', 'n', 'p'):
load_figure(ch.upper(), ch+'lt')
load_figure(ch, ch+'dt')
#
# From FEN to a picture
#
def generate_board(s_fen):
px_width = px_cell_width * 8
pixmap = PyQt4.QtGui.QPixmap(px_width, px_width)
p = PyQt4.QtGui.QPainter()
p.begin(pixmap)
c = PyQt4.QtGui.QColor(*white_cell_color)
p.fillRect(0, 0, px_width, px_width, c)
pe = p.pen()
pe.setColor(PyQt4.QtCore.Qt.black)
pe.setWidth(2)
p.setPen(pe)
c = PyQt4.QtGui.QColor(*black_cell_color)
g = gen_next(s_fen, px_cell_width)
black_cell = 0
for i in range(0,8):
for j in range(0,8):
(letter, x, y) = g.get_next()
if black_cell:
p.fillRect(x, y, px_cell_width, px_cell_width, c)
black_cell = not black_cell
pic = letter_to_picture.get(letter, None)
if pic:
p.drawPixmap(x, y, pic)
g.eol()
black_cell = not black_cell
px_offset = 0
for i in range(0,9):
p.drawLine(px_offset, 0, px_offset, px_width)
p.drawLine(0, px_offset, px_width, px_offset)
px_offset = px_offset + px_cell_width
p.end()
return pixmap
#
# FEN to file
#
def fen_to_file(s_fen, out_dir, stdout):
s_file = hashlib.md5(s_fen).hexdigest()
s_file = os.path.join(out_dir, s_file + '.png')
if os.path.isfile(s_file):
if stdout:
print >>stdout, 'Already exists:', s_file
return s_file # return
if not os.path.isdir(out_dir):
os.mkdir(out_dir)
pixmap = generate_board(s_fen)
pixmap.save(s_file)
if stdout:
print >>stdout, 'Created:', s_file
return s_file
#
# Command-line (test) mode
#
s_fen = os.environ.get('TEST_ANKI_FEN', '').strip()
if s_fen:
print >>sys.stdout, 'fen:', s_fen
app = PyQt4.QtGui.QApplication(sys.argv)
load_figures('chess_fen_media')
fen_to_file(s_fen, '.', sys.stdout)
sys.exit(0) # exit
stdout = None
if os.environ.get('TEST_ANKI_FEN_VERBOSE', 0):
stdout = sys.stdout
#
# Anki mode
#
from ankiqt import mw
orig_mqa = mw.bodyView.mungeQA
load_figures(os.path.join(mw.pluginsFolder(), 'chess_fen_media'))
def fen_mungeQA(deck, txt):
s = orig_mqa(deck, txt)
tmp_s = s.lower()
pos1 = tmp_s.find('[fen]')
if -1 == pos1:
return s # return
pos2 = tmp_s.find('[/fen]', pos1)
if -1 == pos2:
return s # return
s_fen = s[pos1+5:pos2]
if re.compile('.* b .*').match(s_fen):
split = s_fen.split(' ')
split[0] = split[0][::-1]
s_fen = ' '.join(split)
s_file = fen_to_file(s_fen, deck.mediaDir(create=1), stdout)
px_width = 8 * px_cell_width
s_img = '<img src="%s" width="%d" height="%d" border="1" />' % (s_file, px_width, px_width)
pos2 = pos2 + 6
s = s[:pos1] + s_img + '<br /><b style="color:gray;font-size:50%;">[fen]' + s_fen + '[/fen]</b>' + s[pos2:]
return s
mw.bodyView.mungeQA = fen_mungeQA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment