Module:Chessboard/sandbox

This is an old revision of this page, as edited by Frietjes (talk | contribs) at 20:01, 14 May 2013. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
local p = {}

function chessboard( position, size, reverse )
    local piecenames = { p = 'Pawn', r = 'Rook', n = 'Knight', b = 'Bishop', q = 'Queen', k = 'King' }
    local colornames = { l = 'White', d = 'Black' }

    function rowchar( row ) return 9 - row end
    function filechar( file ) return ( "abcdefgh" ):sub( file, file ) end
	function coord( ind ) return ( reverse and ( 8 - ind ) * size ) or ( ind - 1 ) * size end
    
    function piecediv( piece, row, file, res )
        local color = mw.ustring.gsub(piece,'^.*(%w)(%w).*$', '%2')
        piece = mw.ustring.gsub(piece,'^.*(%w)(%w).*$', '%1')
        local alt =  string.format("%s%s %s %s", filechar( file ), rowchar( row ), colornames[color], piecenames[piece] or piece)
        local img = string.format('[[File:Chess %s%st45.svg|%dx%dpx|alt=%s|%s]]', piece, color, size, size, alt, alt)
        table.insert( res, string.format('<div style="position:absolute;z-index:3;top:%dpx;left:%dpx;">%s</div>', coord( row ), coord( file ), img) )
    end

    local result = {}
	table.insert(result, string.format([=[
<div class="chess-board" style="position:relative;">
[[File:Chessboard480.png|%dx%dpx|link=]]
	]=], size * 8, size * 8))

    for row = 1,8 do
       for file = 1,8 do
          local piece = position[8*(row-1) + file]
          if piece
          then
            if (piece:match("%a%a"))
            then
              piecediv( piece, row, file, result )
            end
          end
       end
    end
    table.insert(result, '</div>')
    return result
end

function convertArgsToPosition( args )
    -- copies args[3] to args[66] into a 64 entry array of positions
    local res = {}
    for row = 1,8 do
        for col = 1,8 do
            table.insert(res, args[8*(row-1) + col + 2])
        end
    end
    
    return res
end

function convertFenToPosition( fen )
    -- converts FEN notation to 64 entry array of positions
    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

--[[
this function is to be used only from Template:Chess diagram. 
it provides part of the FEN string - the part that describes the board itself.
unfortunately, the template does not carry enough information to create the 2nd
part of the FEN, which includes information about whose turn is it, en-passant state,
castling, etc.
]]
function diagramToFen( args )
    function nullOrWhitespace( s ) return not s or s:match( '^%s*(.-)%s*$' ) == '' end
    function piece( s ) 
        return nullOrWhitespace( s ) and 1
        or s:gsub( '%s*(%a)(%a)%s*', function( a, b ) return b == 'l' and a:upper() or a end )
    end
    
    local res = ''
    for row = 0, 7 do
        for file = 0, 7 do
            res = res .. piece( args[3 + row * 8 + file] )
        end
        if row < 7 then res = res .. '/' end
    end
    return mw.ustring.gsub(res, '1+', function( s ) return #s end )
end

function p.board(frame)
    local args = frame.args
    local pargs = frame:getParent().args
    local size = (args.size or pargs.size) or '26px'
    local reverse = ( (args.reverse or pargs.reverse) or '' ):lower() == "true"
    local fen = args.fen or pargs.fen
    local position = {}

    size = mw.ustring.gsub(size, '^[^%d]*(%d[%d]*)[^%d]*$', '%1') -- remove px from size
    
    if (fen) 
      then position = convertFenToPosition( fen )
      else position = convertArgsToPosition( pargs )
    end

    return table.concat( chessboard(position, size, reverse), "\n")
end

function p.fen2ascii(frame)
    local b = convertFenToPosition( frame.args.fen )
    local res = ''
    for row = 0,7 do
        res = res .. '|' .. table.concat(b, '|', 8*row + 1, 8*row + 8) .. '|=\n'
    end
    res = mw.ustring.gsub(res,'\| \|', '|  |')
    res = mw.ustring.gsub(res,'\| \|', '|  |')
    return res
end

return p