|
|
|
|
|
|
|
|
|
import re |
|
from helper_functions import lengthenFEN |
|
from message_template import * |
|
|
|
|
|
|
|
|
|
def isPotentialChessboardTopic(sub): |
|
"""if url is imgur link, or url ends in .png/.jpg/.gif""" |
|
if sub.url == None: |
|
return False |
|
return ('imgur' in sub.url |
|
or any([sub.url.lower().endswith(ending) for ending in ['.png', '.jpg', 'jpeg', '.gif']])) |
|
|
|
def invert(fen): |
|
return ''.join(reversed(fen)) |
|
|
|
def generateMessage(fen, certainty, side, visualize_link): |
|
"""Generate response message using FEN, certainty and side for flipping link order""" |
|
vals = {} |
|
|
|
|
|
|
|
if fen == '8/8/8/8/8/8/8/8': |
|
|
|
vals['unaligned_fen_img_link'] = 'http://i.stack.imgur.com/YxP53.gif' |
|
else: |
|
vals['unaligned_fen_img_link'] = 'http://www.fen-to-image.com/image/60/%s.png' % fen |
|
vals['certainty'] = certainty*100.0 |
|
vals['pithy_message'] = getPithyMessage(certainty) |
|
|
|
if side == 'b': |
|
|
|
fen = invert(fen) |
|
|
|
inverted_fen = invert(fen) |
|
|
|
|
|
castle_status = getCastlingStatus(fen) |
|
inverted_castle_status = getCastlingStatus(inverted_fen) |
|
|
|
|
|
vals['fen_w'] = "%s w %s -" % (fen, castle_status) |
|
vals['fen_b'] = "%s b %s -" % (fen, castle_status) |
|
vals['inverted_fen_w'] = "%s w %s -" % (inverted_fen, inverted_castle_status) |
|
vals['inverted_fen_b'] = "%s b %s -" % (inverted_fen, inverted_castle_status) |
|
|
|
vals['lichess_analysis_w'] = 'https://www.lichess.org/analysis/%s_w_%s' % (fen, castle_status) |
|
vals['lichess_analysis_b'] = 'https://www.lichess.org/analysis/%s_b_%s' % (fen, castle_status) |
|
vals['lichess_editor_w'] = 'https://www.lichess.org/editor/%s_w_%s' % (fen, castle_status) |
|
vals['lichess_editor_b'] = 'https://www.lichess.org/editor/%s_b_%s' % (fen, castle_status) |
|
|
|
vals['inverted_lichess_analysis_w'] = 'https://www.lichess.org/analysis/%s_w_%s' % (inverted_fen, inverted_castle_status) |
|
vals['inverted_lichess_analysis_b'] = 'https://www.lichess.org/analysis/%s_b_%s' % (inverted_fen, inverted_castle_status) |
|
vals['inverted_lichess_editor_w'] = 'https://www.lichess.org/editor/%s_w_%s' % (inverted_fen, inverted_castle_status) |
|
vals['inverted_lichess_editor_b'] = 'https://www.lichess.org/editor/%s_b_%s' % (inverted_fen, inverted_castle_status) |
|
|
|
vals['visualize_link'] = visualize_link |
|
|
|
return MESSAGE_TEMPLATE.format(**vals) |
|
|
|
|
|
|
|
|
|
def getPithyMessage(certainty): |
|
pithy_messages = [ |
|
'*[\[ ◕ _ ◕\]^*> ... \[⌐■ _ ■\]^*](http://i.imgur.com/yaVftzT.jpg)*', |
|
'A+ ✓', |
|
'✓', |
|
'[Close.](http://i.imgur.com/SwKKZlD.jpg)', |
|
'[WAI](http://gfycat.com/RightHalfIndianglassfish)', |
|
'[:(](http://i.imgur.com/BNwca4R.gifv)', |
|
'[I tried.](http://i.imgur.com/kmmp0lc.png)', |
|
'[Wow.](http://i.imgur.com/67fZDh9.webm)'] |
|
pithy_messages_cutoffs = [0.999995, 0.99, 0.9, 0.8, 0.7, 0.5, 0.2, 0.0] |
|
|
|
for cuttoff, pithy_message in zip(pithy_messages_cutoffs, pithy_messages): |
|
if certainty >= cuttoff: |
|
return pithy_message |
|
|
|
return "" |
|
|
|
def getSideToPlay(title, fen): |
|
"""Based on post title return 'w', 'b', or predict from FEN""" |
|
title = title.lower() |
|
|
|
if 'black' in title: |
|
if 'white to' in title: |
|
return 'w' |
|
return 'b' |
|
elif 'white' in title: |
|
if 'black to' in title: |
|
return 'b' |
|
return 'w' |
|
else: |
|
|
|
return predictSideFromFEN(fen) |
|
|
|
def predictSideFromFEN(fen): |
|
"""Returns which side it thinks FEN is looking from. |
|
Checks number of white and black pieces on either side to determine |
|
i.e if more black pieces are on 1-4th ranks, then black to play""" |
|
|
|
|
|
fen = re.sub('\d','',fen) |
|
|
|
|
|
parts = fen.split('/') |
|
top = list(''.join(parts[:4])) |
|
bottom = list(''.join(parts[4:])) |
|
|
|
|
|
|
|
|
|
top_count_white = sum(list(map(lambda x: ord(x) <= ord('Z'), top))) |
|
bottom_count_white = sum(list(map(lambda x: ord(x) <= ord('Z'), bottom))) |
|
|
|
top_count_black = sum(list(map(lambda x: ord(x) >= ord('a'), top))) |
|
bottom_count_black = sum(list(map(lambda x: ord(x) >= ord('a'), bottom))) |
|
|
|
|
|
if (top_count_white > bottom_count_white or top_count_black < bottom_count_black): |
|
return 'b' |
|
|
|
|
|
return 'w' |
|
|
|
def getCastlingStatus(fen): |
|
"""Check FEN to see if castling is allowed based on initial positions. |
|
Returns 'KQkq' variants or '-' if no castling.""" |
|
|
|
fen = lengthenFEN(fen) |
|
|
|
|
|
|
|
status = ['','','',''] |
|
|
|
if fen[4] == 'k': |
|
|
|
if fen[0] == 'r': |
|
status[3] = 'q' |
|
if fen[7] == 'r': |
|
status[2] = 'k' |
|
|
|
if fen[63+4] == 'K': |
|
|
|
if fen[63+0] == 'R': |
|
status[1] = 'Q' |
|
if fen[63+7] == 'R': |
|
status[0] = 'K' |
|
|
|
status = ''.join(status) |
|
return status if status else '-' |
|
|
|
def getFENtileLetter(fen,letter,number): |
|
"""Given a fen string and a rank (number) and file (letter), return piece letter""" |
|
l2i = lambda l: ord(l)-ord('A') |
|
piece_letter = fen[(8-number)*8+(8-number) + l2i(letter)] |
|
return ' KQRBNPkqrbnp'.find(piece_letter) |
|
|