Μετάβαση στο περιεχόμενο

Module:Chessboard

Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια
local p = {}
local gr_used = false

function chessboard(args, size, rev, altprefix, letters, numbers, header, footer, align, clear)
    function image_square( pc, row, col, size )
        local piecenames = {
            p = 'πιόνι',                    --σ (Τα 'δθλου' είναι δεσμευμένα για πιθανή μελλοντική χρήση)
            r = 'πύργος',                   --π
            n = 'ίππος',                    --ι
            b = 'αξιωματικός',              --α
            q = 'βασίλισσα',                --β
            k = 'βασιλιάς',                 --ρ
            a = 'αρχιεπίσκοπος',            --ς ή πριγκίπισσα, αρχηγός (archbishop, princess, chief)
            c = 'καγκελάριος',              --κ ή αυτοκράτειρα (cancelor, empress)
            z = 'πρωταθλητής',              --ω (champion)
            w = 'μάγος',                    --μ ή κιρίν (wizard, kirin)
            t = 'τρελλός',                  --τ ή τζόκερ, υπεριππότης (fool, joker, superknight)
            e = 'ελέφαντας',                --ε (elephant)
            s = 'βάρκα',                    --ψ (boat)
            h = 'ανεστραμμένο πιόνι',       --η ή αντιπιόνι, λοχίας (anti-pawn, sergeant, berolina pawn)
            m = 'ανεστραμμένος πύργος',     --ζ ή βεζίρης, τανκ, καταπέλτης (wazir, dabbaba, tank)
            N = 'ανεστραμμένος ίππος',      --ν ή καμήλα, ζέβρα, φοίνικας (camel, zebra, phoenix, nightrider, knigthmare)
            B = 'ανεστραμμένος αξιωματικός',--ξ ή ελέφαντας (elephant, alfil, ferz)
            g = 'ανεστραμμένη βασίλισσα',   --γ ή αμαζόνα, ακρίδα (amazon, grasshopper, hopper)
            f = 'ανεστραμμένος βασιλιάς',   --φ ή πρίγκιπας, άνθρωπος, πολίτης, θνητός (prince, mann, commoner)
            G = 'καμηλοπάρδαλη',            -- ή κιρίν (giraffe, kirin)
            U = 'μονόκερος',                -- (unicorn)
            Z = 'ζέβρα'                     -- (zebra)
            }
        local symnames = {
            xb = 'μπλε χι',                 --χε
            xg = 'πράσινο χι',              --χπ
            xr = 'κόκκινο χι',              --χκ
            xy = 'κίτρινο χι',              --χι
            xx = 'μαύρο χι',                --χχ
            ox = 'λευκό χι',                --οχ
            xo = 'μαύρος κύκλος',           --χο
            oo = 'λευκός κύκλος',           --οο
            ud = 'τόξο πάνω-κάτω',          --τ0
            dl = 'τόξο κάτω-αριστερά',      --τ1
            da = 'τόξο κάτω',               --τ2
            dr = 'τόξο κάτω-δεξιά',         --τ3
            la = 'τόξο αριστερά',           --τ4
            lr = 'τόξο αριστερά-δεξιά',     --τ5
            ra = 'τόξο δεξιά',              --τ6
            ul = 'τόξο πάνω-αριστερά',      --τ7
            ua = 'τόξο πάνω',               --τ8
            ur = 'τόξο πάνω-δεξιά',         --τ9
            db = 'τόξο πάνω-δεξιά και κάτω-αριστερά',
            dw = 'τόξο πάνω-αριστερά και κάτω-δεξιά',
            x0 = 'μηδέν',                   --χ0
            x1 = 'ένα',                     --χ1
            x2 = 'δύο',                     --χ2
            x3 = 'τρία',                    --χ3
            x4 = 'τέσσερα',                 --χ4
            x5 = 'πέντε',                   --χ5
            x6 = 'έξι',                     --χ6
            x7 = 'επτά',                    --χ7
            x8 = 'οκτώ',                    --χ8
            x9 = 'εννιά'                    --χ9
            }
        local colornames_m = { 
            l = 'λευκός',                   --λ
            d = 'μαύρος',                   --μ
            L = 'λευκός',                   --Λ
            D = 'μαύρος',                   --Μ
            W = 'λευκός',                   --Α
            B = 'μαύρος',                   --Γ
            r = 'κόκκινος',                 --κ
            g = 'πράσινος',                 --π
            b = 'μπλε',                     --ε
            y = 'κίτρινος',                 --ι
            u = 'αγνώστου χρώματος'
            }
        local colornames_f = { 
            l = 'λευκή',                    --λ
            d = 'μαύρη',                    --μ
            L = 'λευκή',                    --Λ
            D = 'μαύρη',                    --Μ
            W = 'λευκή',                    --Α
            B = 'μαύρη',                    --Γ
            r = 'κόκκινη',                  --κ
            g = 'πράσινη',                  --π
            b = 'μπλε',                     --ε
            y = 'κίτρινη',                  --ι
            u = 'αγνώστου χρώματος'
            }
        local colornames_u = { 
            l = 'λευκό',                    --λ
            d = 'μαύρο',                    --μ
            L = 'λευκό',                    --Λ
            D = 'μαύρο',                    --Μ
            W = 'λευκό',                    --Α
            B = 'μαύρο',                    --Γ
            r = 'κόκκινο',                  --κ
            g = 'πράσινο',                  --π
            b = 'μπλε',                     --ε
            y = 'κίτρινο',                  --ι
            u = 'αγνώστου χρώματος'
            }
        function colornames( color, piece )
            if mw.ustring.find( 'ph', piece, 1 ) then
                return colornames_u[color]
            elseif mw.ustring.find( 'sqgGZ', piece, 1 ) then
                return colornames_f[color]
            else
                return colornames_m[color]
            end
        end
        function is_color( color )
            return ( color == '' ) and nil or ( mw.ustring.find( 'ldLDWBrgbyu', color, 1 ) )
        end
        function convert_color( color )
            if color == '' then
                return ''
            else
                local i = mw.ustring.find( 'λμΛΜΑΓκπει', color, 1 ) --λευκά, μαύρα, κόκκινα, πράσινα, μπλε, κίτρινα (τα κεφαλαία για τύπο ΜΜ)
                if ( i ) then
                    return mw.ustring.sub( 'ldLDWBrgby', i, i )     --light, dark,  red,     green,   blue, yellow
                else
                    return color
                end
            end
        end
        function convert_piece( piece )
            if piece == '' then
                return ''
            else
                local i = mw.ustring.find( 'σπιαβρςκωμτηζνξγφεψ', piece, 1 ) --τα 'δλθους' είναι δεσμευμένα
                if ( i ) then
                	gr_used = true
                    return mw.ustring.sub( 'prnbqkaczwthmNBgfes', i, i ) --τα 'dilouvxy' είναι δεσμευμένα
                else
                    return piece
                end
            end
        end
        function colchar( col )
            return mw.ustring.sub( 'αβγδεζηθ', col, col )
        end

        local piece = mw.ustring.len( pc ) >= 2 and mw.ustring.sub( pc, 1 , 1 ) or ''
        local color = mw.ustring.len( pc ) >= 2 and mw.ustring.sub( pc, 2 , 2 ) or '' --το >=2 μπαίνει για να επιτρέπεται το \n στη θέση 3
        local tmp = piece .. color
        local alt = altprefix .. colchar( col ) .. row .. ' '
        local idf = 'Chess '
        local idx = mw.ustring.find( 'τ0 τ1 τ2 τ3 τ4 τ5 τ6 τ7 τ8 τ9 χε χπ χκ χι χχ χο οχ οο',
            ( piece == '' and 'x' or piece ) .. ( color == '' and 'x' or color ), 1 )

        if idx then
            piece = mw.ustring.sub( 'ud dl da dr la lr ra ul ua ur xb xg xr xy xx xo ox oo', idx, idx )
            color = mw.ustring.sub( 'ud dl da dr la lr ra ul ua ur xb xg xr xy xx xo ox oo', idx + 1, idx + 1 )
        else
            idx = mw.ustring.find( '0123456789', ( color == '' and 'x' or color ), 1 )
            if idx then
                if piece:match( 'χ' ) then piece = 'x' else idx = nil end --έλεγχος για αριθμό από χ0 έως χ9
            end
            if ( idx == nil ) then
            	piece = convert_piece( piece )
            	color = convert_color( color )
            end
        end
        if idx then gr_used = true end
        idx = 't45.svg'
        if piecenames[piece] and is_color( color ) then
            alt = alt .. colornames( color, piece ) .. ' ' .. piecenames[piece]
            if color:match( 'L' ) or color:match( 'D' ) or color:match( 'W' ) or color:match( 'B' ) then
            	idx = ( color:match( 'L' ) or color:match( 'D' ) ) and 'Fantasy ' or 'Spatial '
                idf = idf .. 'Maurizio Monge ' .. idx
                idx = piece
                piece = ( color:match( 'L' ) or color:match( 'W' ) ) and 'w' or 'b'
                color = idx
                idx = '.svg' --π.χ. λευκό πιόνι: Chess Maurizio Monge Fantasy wp.svg
            end
        else
            alt = alt .. ( symnames[piece .. color] or tmp )
            if piece:match( 'x' ) and ( color:match( 'r' ) or color:match( 'g' ) or color:match( 'b' ) or color:match( 'y' ) ) then
                idf = idf .. 'tile '
                idx = '.svg' --π.χ. κόκκινο χι: Chess tile xr.svg
            end
        end
        return string.format( '[[File:%s%s%s%s|%dx%dpx|alt=%s|%s]]', idf, piece, color, idx, size, size, alt, alt )
    end

    function letters_row( rev, num_lt, num_rt )
        local td = '<td style="padding: 0; vertical-align: inherit;height:18px;width:' .. size .. 'px;">'
       	local l = { 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ' }
       	local r = { 'θ', 'η', 'ζ', 'ε', 'δ', 'γ', 'β', 'α' }
        return '<tr style="vertical-align:middle">\n' 
                .. ( num_lt and '<td style="vertical-align: inherit; padding: 0"></td>' or '' )
                .. td
                .. table.concat( rev and r or l, '</td>' .. td ) 
                .. '</td>'
                .. ( num_rt and '<td style="vertical-align: inherit; padding: 0"></td>' or '' )
                .. '\n</tr>'
    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 = 8 * size + 2
    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 ) .. '\n' end

    b = b .. '<tr style="vertical-align:middle">'
    if ( numbers_lt ) then b = b .. '<td style="padding: 0; vertical-align: inherit; width:18px;height:' .. size .. 'px">' .. (rev and 1 or 8) .. '</td>' end
    b = b .. '<td colspan=8 rowspan=8 style="padding: 0; vertical-align: inherit;"><div class="chess-board" style="position:relative;">'
    b = b .. string.format( '[[File:Chessboard480.svg|%dx%dpx|link=]]', 8 * size, 8 * size )
    for trow = 1,8 do
        local row = rev and trow or ( 9 - trow )
        for tcol = 1,8 do
            local col = rev and ( 9 - tcol ) or tcol
            local piece = args[8 * ( 8 - row ) + col + 2] or ''
            local img = image_square(piece, row, col, size )
            b = b .. string.format(
               '<div style="position:absolute;z-index:3;top:%dpx;left:%dpx;width:' .. size .. 'px;height:' .. size .. 'px;">%s</div>\n', 
               ( trow - 1 ) * size, ( tcol - 1 ) * size, img )
        end
    end
    b = b .. '</div></td>'
    if ( numbers_rt ) then b = b .. '<td style="width:18px;height:' .. size ..'px;padding:0">' .. (rev and 1 or 8) .. '</td>' end
    if ( numbers_lt or numbers_rt ) then
       for trow = 2, 8 do
          local row = rev and trow or ( 9 - trow )
          b = b .. '<tr style="vertical-align:middle">'
          if ( numbers_lt ) then b = b .. '<td style="padding: 0; vertical-align: inherit;height:' .. size .. 'px">' .. row .. '</td>' end
          if ( numbers_rt ) then b = b .. '<td style="padding: 0; vertical-align: inherit;height:' .. size .. 'px">' .. row .. '</td>' end
          b = b .. '</tr>\n'
       end
    end

    if ( letters_bt ) then b = b .. letters_row( rev, numbers_lt, numbers_rt ) .. '\n' end

    if footer:match( '^%s*$' )
    then
    else    
        caption = '<div class="thumbcaption">' .. footer .. '</div>\n'
    end

    return '<div class="thumb ' .. align .. '" style="clear:' .. clear .. '; text-align:center;">'
        .. header .. '\n<div class="thumbinner" style="width:' .. width .. 'px;">\n' 
        .. '<table cellpadding=0 cellspacing=0 style="background:white; font-size:88%; border:1px #b0b0b0 solid; padding:0; '
        .. 'margin:auto;">\n' .. b .. '\n</table>\n' .. caption
        .. '</div></div>[[Κατηγορία:Σελίδες που χρησιμοποιούν σκακιστικό πρότυπο '
        .. ( gr_used and 'με' or 'χωρίς' ) .. ' ελληνική σημειογραφία]]'
end

function convertFenToArgs( fen )
    -- converts FEN notation to 64 entry 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 convertArgsToFen( args, offset )
    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 = ''
    offset = offset or 0
    for row = 1, 8 do
        for file = 1, 8 do
            res = res .. piece( args[8*(row - 1) + file + offset] )
        end
        if row < 8 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 '26'
    local altprefix = args.altprefix or pargs.altprefix or ''
    local reverse = ( args.reverse or pargs.reverse or '' ):lower() == "true"
    local letters = ( args.letters or pargs.letters or 'both' ):lower() 
    local numbers = ( args.numbers or pargs.numbers or 'both' ):lower() 
    local header = mw.ustring.gsub( args[2] or pargs[2] or '', '^%s*(.-)%s*$', '%1' )
    local footer = args[67] or pargs[67] 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 fen = args.fen or pargs.fen

    size = mw.ustring.match( size, '[%d]+' ) or '26' -- remove px from size
    if (fen) then
        align = args.align or pargs.align or 'tright'
        clear = args.clear or pargs.clear or ( align:match('tright') and 'right' ) or 'none'
        header = args.header or pargs.header or ''
        footer = args.footer or pargs.footer or ''
        return chessboard(convertFenToArgs( fen ), size, reverse, altprefix, letters, numbers, header, footer, align, clear)
    end
    if args[3] then
        return chessboard(args, size, reverse, altprefix, letters, numbers, header, footer, align, clear)
    else
        return chessboard(pargs, size, reverse, altprefix, letters, numbers, header, footer, align, clear)
    end
end

function p.fen2ascii(frame)
    -- {{#invoke:Chessboard|fen2ascii|fen=...}}
    local b = convertFenToArgs( frame.args.fen )
    local res = '|=\n'
    local offset = 2
    for row = 1,8 do
        local n = (9 - row)
        res = res .. n .. ' |' .. 
            table.concat(b, '|', 8*(row-1) + 1 + offset, 8*(row-1) + 8 + offset) .. '|=\n'
    end
    res = mw.ustring.gsub( res,'\| \|', '|  |' )
    res = mw.ustring.gsub( res,'\| \|', '|  |' )
    res = res .. '   α  β  γ  δ  ε  ζ  η  θ'
    return res
end

function p.ascii2fen( frame )
    -- {{#invoke:Chessboard|ascii2fen|kl| | |....}}
    return convertArgsToFen( frame.args, frame.args.offset or 1 )
end

return p