모듈:Chess/board
보이기
< 모듈:Chess
이 모듈에 대한 설명문서는 모듈:Chess/board/설명문서에서 만들 수 있습니다
local p = {}
local function pgnToFen(pgn)
--Tries to use Pgn2fen module to convert pgn to fen.
local success, result = pcall(function()
local moves = require('Module:Pgn2fen').pgn2fen(pgn)
return moves[#moves] --returns fen if pgn2fen worked
end)
if success then
return result
else
--If it throws an error (invalid pgn), handle this gracefully and return
--an empty string
return ''
end
end
--From [[w:Module:Chessboard]] via [[Module:Chess]]
local function convertFenToArgs( 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
--takes 64 values each corresponding to a chessboard square
--and prints them out in divs to be rendered into a chessboard by css magic.
local function renderBoardFromArgs(args, size, captionText, float, border, scheme)
--sanitise optional parameters.
size = tonumber(size) or 1
local allowedFloats = {
none = true,
left = true,
right = true,
["inline-start"] = true,
["inline-end"] = true,
center = true
}
float = allowedFloats[float] and float or 'none'
local allowedSchemes = {
orange = true,
bw = true,
green = true,
brown = true
}
scheme = allowedSchemes[scheme] and scheme or 'brown'
if border == 'true' or border == '1' then
border = true
else
border = false
end
local html = mw.html.create('div')
local container
if border then
html:addClass('chessboard-frame')
:css({
['font-size'] = size .. 'em'
})
if float == "center" then
html:css({['margin'] = '0 auto'})
else
html:css({['float'] = float})
end
local marginStyles = {}
if float ~= 'none' and float ~= 'center' then
marginStyles['margin-bottom'] = '1.3em'
end
if float == 'left' then
marginStyles['margin-right'] = '1.4em'
elseif float == 'right' then
marginStyles['margin-left'] = '1.4em'
end
html:css(marginStyles)
container = html:tag('div')
:addClass('chessboard-container')
else
container = html
:addClass('chessboard-container')
:css({
['font-size'] = size .. 'em',
['width'] = 'fit-content'
})
if float == "center" then
container:css({['margin'] = '0 auto'})
else
container:css({['float'] = float})
end
local marginStyles = {}
if float ~= 'none' and float ~= 'center' then
marginStyles['margin-bottom'] = '1.3em'
end
if float == 'left' then
marginStyles['margin-right'] = '1.4em'
elseif float == 'right' then
marginStyles['margin-left'] = '1.4em'
end
container:css(marginStyles)
end
-- Top file labels
local fileTop = container:tag('div'):addClass('file-labels-top')
for _, file in ipairs({ 'a','b','c','d','e','f','g','h' }) do
fileTop:tag('div'):wikitext(file)
end
-- Left rank labels
local rankLeft = container:tag('div'):addClass('rank-labels-left')
for i = 8, 1, -1 do
rankLeft:tag('div'):wikitext(i)
end
-- Chessboard grid
local board = container:tag('div'):addClass('chess-grid')
for i = 1, 64 do
local frame = mw.getCurrentFrame()
local piece = args[i] or ''
local square = board:tag('div')
:addClass('chess-square')
:addClass(scheme)
square:tag('div')
:addClass('piece')
:addClass('piece-' .. piece)
end
-- Right rank labels
local rankRight = container:tag('div'):addClass('rank-labels-right')
for i = 8, 1, -1 do
rankRight:tag('div'):wikitext(i)
end
-- Bottom file labels
local fileBottom = container:tag('div'):addClass('file-labels-bottom')
for _, file in ipairs({ 'a','b','c','d','e','f','g','h' }) do
fileBottom:tag('div'):wikitext(file)
end
if captionText ~= '' then
if border then
html:tag('div'):addClass('chessboard-caption')
:wikitext(captionText)
else
container:tag('div'):addClass('chessboard-caption')
:wikitext(captionText)
end
end
return tostring(html)
end
local function pagename2pgn(pagename)
local path = pagename:match("^Chess Opening Theory/(.+)")
if not path then
return ""
end
local line = path:gsub("/", " ") --convert slashes to spaces
line = mw.text.trim(line)
return line
end
function p.pagename(frame) --for calling externally
local pagename = frame.args[1]
if not pagename or pagename == '' then
pagename = mw.title.getCurrentTitle().text
end
local path = pagename:match("^Chess Opening Theory/(.+)")
if not path then
return ""
end
local line = path:gsub("/", " "):gsub("[0-9]+%.%.%.", "")
line = mw.text.trim(line)
return pgnToFen(line)
end
--computeChessboard takes either a fen or a pgn (moves)
--converts them to table of 64 values each corresponding to a chessboard square
--and sends them to renderBoardFromArgs() to be rendered.
function p.computeChessboard(frame)
local fen = frame.args.fen or ''
local moves = frame.args.moves or ''
local parentArgs = frame:getParent().args
local size = parentArgs.size or '1'
local captionText = parentArgs.caption or ''
local float = parentArgs.float or 'none'
local border = parentArgs.frame or false
local scheme = parentArgs.scheme or 'brown'
--specifying moves overrides provided fen
if moves ~= '' then
fen = pgnToFen(moves)
elseif fen == '' then
local pagenameFEN = pagename2pgn(mw.title.getCurrentTitle().text)
if pagenameFEN ~= '' then fen = pgnToFen(pagenameFEN) end --defaults to page title
end
if fen == '' then
fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR' --fallback to starting pos.
end
local args = convertFenToArgs(fen)
return renderBoardFromArgs(args, size, captionText, float, border, scheme)
end
--renderChessboard allows renderBoardFromArgs() to be called indirectly
--from outside the module and passed a converted fen directly
function p.renderChessboard(frame)
--if it looks like it is being passed arguments
if frame.args[1] and frame.args[1] ~= '' then
return renderBoardFromArgs(frame.args)
else
--otherwise default to showing the starting position
return renderBoardFromArgs(convertFenToArgs('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'))
end
end
return p