Модуль:Произвольная шахматная доска
Из Википедии, бесплатной энциклопедии
local p = {} function chessboard(args, size, rows, cols, offsetx, offsety, rev, trans, lightdark, altprefix, letters, numbers, header, footer, align, clear, noframe, numeration) function colchar( col ) return (col <= 26) and ( "abcdefghijklmnopqrstuvwxyz" ):sub( col, col ) or ( "abcdefghijklmnopqrstuvwxyz" ):sub( math.floor((col-1)/26), math.floor((col-1)/26) ) .. ( "abcdefghijklmnopqrstuvwxyz" ):sub( col-math.floor((col-1)/26)*26, col-math.floor((col-1)/26)*26) end function image_square(pc, row, col, offsetx, offsety, size, t, flip, altprefix, numeration) local colornames = { l = 'бел', d = 'чёрн'} local piecenames = { -- при добавлении фигур необходимо определить их грамматический род, добавив в соответствующую строку (ниже по тегу #gender) p = 'пешка', r = 'ладья', n = 'конь', b = 'слон', q = 'ферзь', k = 'король', a = 'архиепископ', c = 'канцлер', z = 'чемпион', w = 'колдун', t = 'шут', h = 'перевёрнутая пешка', m = 'перевёрнутая ладья', s = 'перевёрнутый конь', f = 'перевёрнутый король', e = 'перевёрнутый слон', g = 'перевёрнутый ферзь', G = 'жираф', U = 'единорог', Z = 'зебра' } local symnames = { xx = 'чёрный крест', ox = 'белый крест', xo = 'чёрный круг', oo = 'белый круг', ul = 'стрелка вверх-влево', ua = 'стрелка вверх', ur = 'стрелка вверх-вправо', la = 'стрелка влево', ra = 'стрелка вправо', dl = 'стрелка вниз-влево', da = 'стрелка вниз', dr = 'стрелка вниз-вправо', lr = 'стрелка влево-вправо', ud = 'стрелка вверх-вниз', db = 'стрелки вверх-вправо и вниз-влево', dw = 'стрелки вверх-влево и вниз-вправо', x0 = 'ноль', x1 = 'один', x2 = 'два', x3 = 'три', x4 = 'четыре', x5 = 'пять', x6 = 'шесть', x7 = 'семь', x8 = 'восемь', x9 = 'девять', j0 = 'чёрная шашка', j1 = 'белая шашка', D0 = 'чёрная дамка', D1 = 'белая дамка', O0 = 'чёрный круг', O1 = 'белый круг', O2 = 'красный круг', O3 = 'зелёный круг', O4 = 'синий круг', O5 = 'бирюзовый круг', O6 = 'жёлтый круг', O7 = 'розовый круг', O8 = 'коричневый круг', O9 = 'фиолетовый круг', } if (pc=='x') then pc = 'j0' end if (pc=='o') then pc = 'j1' end if (pc=='X') then pc = 'D0' end if (pc=='O') then pc = 'D1' end local color = mw.ustring.gsub( pc, '^.*(%w)(%w).*$', '%2' ) or '' local piece = mw.ustring.gsub( pc, '^.*(%w)(%w).*$', '%1' ) or '' local ld = t and 't' or ((((row + col + flip) % 2) == 0) and 'd' or 'l') local alt = '' if (numeration=='chess') then alt = alt .. colchar( col+offsetx ) .. row+offsety .. ' ' -- нумерация при наведении на клетку elseif (numeration=='continuous') then alt = alt .. col+(rows-row)*cols .. ' ' elseif (numeration=='draughts') then if (ld=='d') then alt = alt .. math.floor((col+(rows-row)*cols+1)/2) .. ' ' end elseif (numeration=='swapdraughts') then if (ld=='l') then alt = alt .. math.floor((col+(rows-row)*cols+1)/2) .. ' ' end end if ( colornames[color] and piecenames[piece] ) then -- Согласовываем род прилагательного, обозначающего цвет #gender alt = alt .. colornames[color] if (string.find('nbqkaczwtsfegGU',piece)) then alt = alt .. 'ый ' -- Коды фигур мужского рода elseif (string.find('prhmZ',piece)) then alt = alt .. 'ая ' -- Коды фигур женского рода else alt = alt ..'. ' end alt = alt .. piecenames[piece] else alt = alt .. ( symnames[piece .. color] or piece .. ' ' .. color ) end return string.format( '[[File:Chess %s%s%s45.svg|%dx%dpx|alt=%s|%s]]', piece, color, ld, size, size, alt, alt) end function letters_row( rev, num_lt, num_rt, cols, rows, offsetx, numeration, rev, lightdark, bottomline) blisblack = 1 if (lightdark==true) then blisblack = 1 - blisblack end if (((cols+rows)%2==1)and(rev==true)) then blisblack = 1 - blisblack end tlisblack = blisblack if (rows%2==0) then tlisblack = 1- blisblack end local res = '<tr style="vertical-align:middle">' .. ( num_lt and '<td style="padding:0; vertical-align:inherit"></td>' or '' ) .. '<td style="padding:0; vertical-align:inherit; height:18px">' for k = 1, cols do if (numeration=='chess') then res = res .. colchar(rev and (cols - k + 1+offsetx) or k+offsetx) -- шахматы elseif (numeration=='continuous') then -- сквозная if (rev) then res = res .. (cols-k+1)+(1-bottomline)*(rows-1)*cols else res = res .. k+bottomline*(cols*(rows-1)) end elseif (numeration=='draughts') then --черные if not(rev) then if (bottomline==0)and(k % 2 == tlisblack) then res = res .. math.floor((k+1)/2) -- верх elseif (bottomline==1)and(k % 2 == blisblack) then res = res .. math.floor((cols*(rows-1)+k+1)/2) end -- низ else if (bottomline==0)and(k % 2 == tlisblack) then res = res .. math.floor((rows*cols-k)/2)+1 -- верх elseif (bottomline==1)and(k % 2 == blisblack) then res = res .. math.floor((cols-k)/2)+1 end -- низ end elseif (numeration=='swapdraughts') then --белые if not(rev) then if (bottomline==0)and not(k % 2 == tlisblack) then res = res .. math.floor((k+1)/2) --верх elseif (bottomline==1)and not (k % 2 == blisblack) then res = res .. math.floor((cols*(rows-1)+k+1)/2) end -- низ else if (bottomline==0)and not (k % 2 == tlisblack) then res = res .. math.floor((rows*cols-k)/2)+1 -- верх elseif (bottomline==1)and not (k % 2 == blisblack) then res = res .. math.floor((cols-k)/2)+1 end -- низ end end res = res ..'</td><td style="padding:0; vertical-align:inherit">' end res = res .. '</td>' .. ( num_lt and '<td style="padding:0; vertical-align:inherit"></td>' or '' ) .. '</tr>' return res end local letters_tp = letters:match('both') or letters:match('top') local letters_bt = letters:match('both') or letters:match('bottom') local numbers_lt = numbers:match('both') or numbers:match('left') local numbers_rt = numbers:match('both') or numbers:match('right') local width = cols * size + 2 local flip = lightdark and 1 or 0 if ( numbers_lt ) then width = width + 18 end if ( numbers_rt ) then width = width + 18 end local b = '' local caption = '' if ( letters_tp ) then b = b .. letters_row(rev, numbers_lt, numbers_rt, cols, rows, offsetx, numeration, rev, lightdark, 0) .. '\n' end -- 1 - флаг верхней строки для шашечной нумерации for trow = 1,rows do local row = rev and trow or (rows - trow + 1) b = b .. '<tr style="vertical-align:middle">' if ( numbers_lt ) then b = b .. '<td style="padding:0; vertical-align:inherit; width:18px">' -- левая колонка цифр if (numeration=='chess') then b = b .. row+offsety elseif (numeration=='continuous') then if not(rev) then b = b .. (trow-1)*cols+1 else b = b .. (rows-trow+1)*cols end elseif (numeration=='draughts') then if (trow%2==tlisblack) then if not(rev) then b = b .. math.floor((trow-1)*cols/2+1) else b = b .. math.floor((cols*(rows-trow+1)+1)/2) end end elseif (numeration=='swapdraughts') then if not (trow%2==tlisblack) then if not(rev) then b = b .. math.floor((trow-1)*cols/2+1) else b = b .. math.floor((cols*(rows-trow+1)+1)/2) end end end b = b .. '</td>' end for tcol = 1,cols do local col = rev and (cols - tcol + 1) or tcol local idx = cols*(rows - row) + col + 2 if (args[idx] == nil) then args[idx] = ' ' end local img = image_square((args[idx]:match('%w%w') or args[idx]:match('%w')) or '', row, col, offsetx, offsety, size, trans, flip, altprefix, numeration) local bg = (((trow + tcol + flip) % 2) == 0) and '#ffce9e' or '#d18b47' b = b .. '<td style="padding:0; vertical-align:inherit; background-color: ' .. bg .. ';">' .. img .. '</td>' end if ( numbers_rt ) then b = b .. '<td style="padding:0; vertical-align:inherit; width:18px">' -- правая колонка цифр if (numeration=='chess') then b = b .. row+offsety elseif (numeration=='continuous') then if not(rev) then b = b .. trow*cols else b = b .. (rows-trow)*cols +1 end elseif (numeration=='draughts') then if ((trow+cols+1)%2==tlisblack) then if not(rev) then b = b .. math.floor((trow*cols+1)/2) else b = b .. math.floor((cols*(rows-trow))/2)+1 end end elseif (numeration=='swapdraughts') then if ((trow+cols)%2==tlisblack) then if not(rev) then b = b .. math.floor((trow*cols+1)/2) else b = b .. math.floor((cols*(rows-trow))/2)+1 end end end b = b .. '</td>' end end if ( letters_bt ) then b = b .. letters_row(rev, numbers_lt, numbers_rt, cols, rows, offsetx, numeration, rev, lightdark, 1) .. '\n' end -- 2 - флаг нижней строки для шашечной нумерации if footer:match('^%s*$') then else caption = '<div class="thumbcaption">' .. footer .. '</div>\n' end b = '<table cellpadding=0 cellspacing=0 style="line-height: 0; background:white; font-size:88%; border:1px #b0b0b0 solid;' .. 'padding:0; margin:auto">\n' .. b .. '\n</table>' if noframe then return b else return '<div class="thumb ' .. align .. '" style="clear:' .. clear .. '; text-align:center; width:' .. width + 8 .. 'px">' .. header .. '\n<div class="thumbinner" style="width:' .. width .. 'px;">\n' .. b .. '\n' .. caption .. '</div></div>' end end function convertFenToArgs( fen ) -- converts FEN notation to an array of positions, offset by 2 local res = {' ', ' '} -- Loop over rows, which are delimited by / for srow in string.gmatch("/" .. fen, "/%w+") do -- Loop over all letters and numbers in the row for piece in srow:gmatch( "%w" ) do if (piece:match("%d")) then -- if a digit for k=1,piece do table.insert(res,' ') end else -- not a digit local color = piece:match( '%u' ) and 'l' or 'd' piece = piece:lower() table.insert(res, piece .. color ) end end end return res end function p.board(frame) local args = frame.args local pargs = frame:getParent().args local offsetx = args.offsetx or pargs.offsetx or 0 -- смещение начала координат доски по оси Х вправо (цифры) local offsety = args.offsety or pargs.offsety or 0 -- смещение начала координат доски по оси Y вверх (буквы) local size = (args.size or pargs.size) or '26' local reverse = (args.reverse or pargs.reverse or '' ):lower() == "true" local trans = (args.transparent or pargs.transparent or '' ):lower() == "true" local lightdark = (args.lightdark or pargs.lightdark or '' ):lower() == "swap" if (offsetx+offsety %2 ==1) then lightdark = not lightdark end -- инвертирование цветов клеток доски при смещении local altprefix = args.altprefix or pargs.altprefix or '' local rows = pargs.rows or args.rows or 8 local cols = pargs.cols or args.cols or 8 local letters = ( pargs.letters or args.letters or 'both' ):lower() local numbers = ( pargs.numbers or args.numbers or 'both' ):lower() local header = mw.ustring.gsub( args[2] or pargs[2] or '', '^%s*(.-)%s*$', '%1' ) local numeration = (args.numeration or pargs.numeration or 'chess'):lower() if not (numeration:match('draughts') or numeration:match('swapdraughts') or numeration:match('continuous')) then numeration = 'chess' end -- тип нумерации клеток доски: chess - шахматный, draughts - шашечный со второй клетки, -- swapdraughts - шашечный с первой клетки, continuous - шашечный сквозной local footer = args[3 + rows*cols] or pargs[3 + rows*cols] or '' local align = ( args[1] or pargs[1] or 'tright' ):lower() local clear = ( args.clear or pargs.clear ) or ( align:match('tright') and 'right' or 'none' ) local noframe = (args.noframe or pargs.noframe or ''):lower() == "true" local fen = args.fen or pargs.fen size = mw.ustring.match(size, '[%d]+') or '26' -- remove px from size if (fen) then footer = args[3] or pargs[3] or '' return chessboard(convertFenToArgs( fen ), size, rows, cols, offsetx, offsety, reverse, trans, lightdark, altprefix, letters, numbers, header, footer, align, clear, noframe, numeration) end if args[3] then return chessboard(args, size, rows, cols, offsetx, offsety, reverse, trans, lightdark, altprefix, letters, numbers, header, footer, align, clear, noframe, numeration) else return chessboard(pargs, size, rows, cols, offsetx, offsety, reverse, trans, lightdark, altprefix, letters, numbers, header, footer, align, clear, noframe, numeration) end end return p