Module:Chessboard/sandbox
| This is the module sandbox page for Module:Chessboard (diff). |
| This template is currently being merged with Module:Chessboard mxn. This template is being merged with another template, after which it will be redirected or deleted. Please check Wikipedia:Templates for discussion/Holding cell for any additional instructions. The decision to merge this template was made following this discussion initiated on 22 December 2025 at Templates for discussion. Note: Please review this template's instructions at Wikipedia:Templates for discussion/Holding cell before proceeding with any type of merging. |
| This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing. |
| This module uses TemplateStyles: |
Implements {{Chess diagram}}.
Usage
{{#invoke:Chessboard|function_name}}
local p = {}
local cfg, nrows, ncols
local function innerboard(args, size, rev)
pattern = cfg.pattern or '%w%w'
local root = mw.html.create('div')
root:addClass('chess-pieces notheme')
:css('position', 'relative')
:wikitext(cfg.image_board(size))
for trow = 1,nrows do
local row = rev and trow or ( 1 + nrows - trow )
for tcol = 1,ncols do
local col = rev and ( 1 + ncols - tcol ) or tcol
local piece = args[ncols * ( nrows - row ) + col + 2] or ''
if piece:match( pattern ) then
local img = cfg.image_square(piece:match(pattern), row, col, size )
root:tag('div')
:css('top', tostring(( trow - 1 ) * size) .. 'px')
:css('left', tostring(( tcol - 1 ) * size) .. 'px')
:wikitext(img)
end
end
end
return tostring(root)
end
function chessboard(args, size, rev, letters, numbers, header, footer, align, clear)
function letters_row( rev, num_lt, num_rt )
local letters = cfg.letters()
local root = mw.html.create('')
if num_lt then
root:tag('td')
end
for k = 1,ncols do
root:tag('td')
:css('height', '18px')
:css('width', size .. 'px')
:wikitext(rev and letters[1+ncols-k] or letters[k])
end
if num_rt then
root:tag('td')
end
return tostring(root)
end
local letters_top = letters:match( 'both' ) or letters:match( 'top' )
local letters_bottom = letters:match( 'both' ) or letters:match( 'bottom' )
local numbers_left = numbers:match( 'both' ) or numbers:match( 'left' )
local numbers_right = numbers:match( 'both' ) or numbers:match( 'right' )
local width = ncols * size + 2
if ( numbers_left ) then width = width + 18 end
if ( numbers_right ) then width = width + 18 end
local root = mw.html.create('div')
:addClass('chessboard')
:addClass('thumb')
:addClass('noviewer')
:addClass(align)
if( header and header ~= '' ) then
root:tag('div')
:addClass('center')
:css('line-height', '130%')
:css('margin', '0 auto')
:css('max-width', (width + ncols) .. 'px')
:wikitext(header)
end
local div = root:tag('div')
:addClass('thumbinner')
:css('width', width .. 'px')
local b = div:tag('table')
:attr('cellpadding', '0')
:attr('cellspacing', '0')
if ( letters_top ) then
b:tag('tr')
:wikitext(letters_row( rev, numbers_left, numbers_right ))
end
local tablerow = b:tag('tr')
if ( numbers_left ) then
tablerow:tag('td')
:css('width', '18px')
:css('height', size .. 'px')
:wikitext(rev and 1 or nrows)
end
local td = tablerow:tag('td')
:attr('colspan', ncols)
:attr('rowspan', nrows)
:wikitext(innerboard(args, size, rev))
if ( numbers_right ) then
tablerow:tag('td')
:css('width', '18px')
:css('height', size .. 'px')
:wikitext(rev and 1 or nrows)
end
if ( numbers_left or numbers_right ) then
for trow = 2, nrows do
local idx = rev and trow or ( 1 + nrows - trow )
tablerow = b:tag('tr')
if ( numbers_left ) then
tablerow:tag('td')
:css('height', size .. 'px')
:wikitext(idx)
end
if ( numbers_right ) then
tablerow:tag('td')
:css('height', size .. 'px')
:wikitext(idx)
end
end
end
if ( letters_bottom ) then
b:tag('tr')
:wikitext(letters_row( rev, numbers_left, numbers_right ))
end
if footer and mw.text.trim(footer)~='' then
div:tag('div')
:addClass('thumbcaption')
:wikitext(footer)
end
return tostring(root) ..
mw.getCurrentFrame():extensionTag( 'templatestyles', '', { src = 'Module:Chessboard/sandbox/styles.css' } )
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 style = args.style or pargs.style or 'Chess'
cfg = require('Module:Chessboard/' .. style .. '/sandbox')
nrows, ncols = cfg.dims()
local size = args.size or pargs.size or '26'
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 = args[2] or pargs[2] or ''
local footer = args[nrows*ncols + 3] or pargs[nrows*ncols + 3] or ''
local align = ( args[1] or pargs[1] or 'floatright' ):lower()
local clear = args.clear or pargs.clear or ( align:match('floatright') and 'right' ) or 'none'
local fen = args.fen or pargs.fen
local pgn = args.pgn or pargs.pgn
size = mw.ustring.match( size, '[%d]+' ) or '26' -- remove px from size
if (pgn) then
local pgnModule = require('Module:Pgn')
metadata, moves = pgnModule.main(pgn)
fen = moves[#moves]
end
if (fen) then
align = args.align or pargs.align or 'floatright'
clear = args.clear or pargs.clear or ( align:match('floatright') and 'right' ) or 'none'
header = args.header or pargs.header or ''
footer = args.footer or pargs.footer or ''
return chessboard( convertFenToArgs( fen ), size, reverse, letters, numbers, header, footer, align, clear )
end
if args[3] then
return chessboard(args, size, reverse, letters, numbers, header, footer, align, clear)
else
return chessboard(pargs, size, reverse, letters, numbers, header, footer, align, clear)
end
end
-- Generates an HTML board of a specific size
function p.htmlBoard(frame)
local args = require("Module:Arguments").getArgs(frame)
local width = tonumber(args.width or '8')
local light = args.light or '#FFFFFF00'
local dark = args.dark or '#808080'
local tbl = mw.html.create('table')
tbl:css('table-layout', 'fixed'):css('border', 'none'):css('border-collapse', 'collapse'):css('width', '30%'):css('aspect-ratio', '1 / 1'):css('cellspacing', '0'):css('cellpadding', '0'):css('margin:0px')
local rank = width + 2
local file = 1
local numberedarg = 1
local alignment = args[numberedarg] or ''
local root = mw.html.create('div')
:addClass('chessboard')
:addClass('thumb')
:addClass('noviewer')
:addClass(alignment)
numberedarg = numberedarg + 1
local title = args[numberedarg] or ''
numberedarg = numberedarg + 1
while rank > 0 do
local row = tbl:tag('tr')
while file <= width + 2 do
if (rank == 1 or rank == width + 2) and (file == 1 or file == width + 2) then
row
:tag('th')
:css('min-width', (1 / (width + 2) * 100) .. "%")
:css('max-width', (1 / (width + 2) * 100) .. "%")
:css('height', 'auto')
:css('aspect-ratio', '1 / 1')
:wikitext('')
elseif (rank == 1 or rank == width + 2) then
-- get letter corresponding to file
local alphabet = "abcdefghijklmnopqrstuvwxyz"
local fileLetter = alphabet:sub(math.mod(file - 2, 26) + 1, math.mod(file - 2, 26) + 1)
local toadd = ''
for n=1, math.ceil(file / 26), 1 do
toadd = toadd .. fileLetter
end
row
:tag('th')
:css('min-width', (1 / (width + 2) * 100) .. "%")
:css('max-width', (1 / (width + 2) * 100) .. "%")
:css('overflow', 'hidden')
:css('aspect-ratio', '1 / 1')
:wikitext(toadd)
:done()
elseif (file == 1 or file == width + 2) then
row
:tag('th')
:css('min-width', (1 / (width + 2) * 100) .. "%")
:css('max-width', (1 / (width + 2) * 100) .. "%")
:css('overflow', 'hidden')
:css('aspect-ratio', '1 / 1')
:wikitext(rank - 1)
else
-- get the HTML chess piece specified for this square
-- currently supports standard chess set
-- @todo specify appropriate font especially one that supports fairy chess pieces
local pieceArg = args[numberedarg] or ''
local pieceLetter = pieceArg:sub(1, 1)
local pieceColor = pieceArg:sub(2, 2)
local pieceDec = 9811
if pieceLetter == "p" then
pieceDec = pieceDec + 6
elseif pieceLetter == "n" then
pieceDec = pieceDec + 5
elseif pieceLetter == "b" then
pieceDec = pieceDec + 4
elseif pieceLetter == "r" then
pieceDec = pieceDec + 3
elseif pieceLetter == "q" then
pieceDec = pieceDec + 2
elseif pieceLetter == "k" then
pieceDec = pieceDec + 1
end
if (pieceDec > 9811 and pieceColor == "d") then
pieceDec = pieceDec + 6
end
-- color the chessboard appropriately
if (math.mod(file, 2) == math.mod(rank, 2)) then
row
:tag('td')
:css('background-color', dark)
:css('color', 'inherit')
:css('min-width', (1 / (width + 2) * 100) .. "%")
:css('max-width', (1 / (width + 2) * 100) .. "%")
:css('overflow', 'hidden')
:css('aspect-ratio', '1 / 1')
:css('border-width', '0px')
:css('font-family', 'monospace')
:wikitext('<div style="display: flex;justify-content: center;align-items: center;font-size: 2em;">' .. (pieceDec == 9811 and ' ' or '&#' .. pieceDec .. ';︎') .. '</div>')
else
row
:tag('td')
:css('background-color', light)
:css('color', 'inherit')
:css('min-width', (1 / (width + 2) * 100) .. "%")
:css('max-width', (1 / (width + 2) * 100) .. "%")
:css('overflow', 'hidden')
:css('aspect-ratio', '1 / 1')
:css('border-width', '0px')
:css('font-family', 'monospace')
:wikitext('<div style="display: flex;justify-content: center;align-items: center;font-size: 2em;">' .. (pieceDec == 9811 and ' ' or '&#' .. pieceDec .. ';︎') .. '</div>')
end
numberedarg = numberedarg + 1
end
file = file + 1
end
file = 1
rank = rank - 1
end
local caption = args[numberedarg]
root
:tag('div')
:addClass('center')
:wikitext(title)
:done()
:wikitext(tostring(tbl))
:tag('div')
:addClass('thumbcaption')
:wikitext(caption)
:done()
return root
end
return p
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.