Module:Sandbox/Fred Gandt/chessDemo

local p = {}

local getArgs = require( 'Module:Arguments' ).getArgs

local function replace( s, p, r ) return mw.ustring.gsub( s, p, r ) end

local function collapseWhitespace( s ) return replace( s, '%s*', '' ) end

local function toLower( s ) return mw.ustring.lower( s ) end

local function collapseToLower( s ) return toLower( collapseWhitespace( s ) ) end

local function splitter( s, d, p ) return mw.text.split( s, d, p or false ) end

local function join( t, d ) return table.concat( t, d or '' ) end

local function firstUpper( p ) p = toLower( p ) if p ~= 'pawn' then if p ~= 'knight' then return mw.ustring.upper( splitter( p, '' )[ 1 ] ) end return 'N'	end return '' end

local function removeAlphas( s ) if s and #s > 0 then local r = replace( s, '%D', '' ) if #r > 0 then return r		end end return nil end

local function finder( hs, n ) return mw.ustring.find( toLower( hs ), n ) end

local function buildDemo( configuration ) local function eD return mw.html.create( 'div' ) end local function eP return mw.html.create( 'p' ) end local function eB return mw.html.create( 'b' ) end local function addSpan( n, s ) local se = mw.html.create( 'span' ) se:wikitext( s ) n:node( se ) end local i = 0 local W = 'w"|'	local B = 'b"|' local aN = '\n|' local tR = aN .. '-'	local aS = ' ' local aP = ''	local aB = aS .. aP .. 'b">' local a = join( { aN, aW, 'a', aB, 'h', aS, aW, 'b', aB, 'g', aS, aW, 'c', aB, 'f', aS, aW, 'd', aB,		'e', aS, aW, 'e', aB, 'd', aS, aW, 'f', aB, 'c', aS, aW, 'g', aB, 'b', aS, aW, 'h', aB, 'a', aS, aN } ) local r = join( { rC, B, rC, W, rC, B, rC, W, rC, B, rC, W, rC, B } ) local rW = rC .. W .. r	local rB = r .. rC .. W	local T = join( { '\n{|cellpadding="0" cellspacing="0"', a, tR,		aW, '8', aB, '1', aS, rW, aW, '8', aB, '1', aS, tR, aW, '7', aB, '2', aS, rB, aW, '7', aB, '2', aS, tR,		aW, '6', aB, '3', aS, rW, aW, '6', aB, '3', aS, tR, aW, '5', aB, '4', aS, rB, aW, '5', aB, '4', aS, tR,		aW, '4', aB, '5', aS, rW, aW, '4', aB, '5', aS, tR, aW, '3', aB, '6', aS, rB, aW, '3', aB, '6', aS, tR,		aW, '2', aB, '7', aS, rW, aW, '2', aB, '7', aS, tR, aW, '1', aB, '8', aS, rB, aW, '1', aB, '8', aS, tR,		a, aN, '}' } ) local peice local board = eD local fallback = eD local chessDemo = eD local interface = eD local borderfix = eD chessDemo:attr( 'data-data', mw.text.jsonEncode( configuration.instructions ) ) chessDemo:attr( 'class', 'chessDemo' ) :addClass( 'cd-border' ) :css( { float = configuration.float,				clear = configuration.clear,				width = configuration.width.master .. 'px'			} ) if configuration.notation.notes and configuration.notation.float then chessDemo:addClass( 'cd-notation-' .. configuration.notation.float ) end if configuration.title then local n = eP n:attr( 'class', 'cd-title' ) :wikitext( configuration.title ) chessDemo:node( n ) end if configuration.info then local n = eP n:attr( 'class', 'cd-information' ) :wikitext( configuration.info ) chessDemo:node( n ) end interface:attr( 'class', 'cd-interface' ) if configuration.orientation then interface:addClass( 'cd-persp-b' ) end borderfix:attr( 'class', 'cd-border' ) :css( 'font-size', configuration.width.board .. 'px' ) board:attr( 'class', 'cd-board' ) :addClass( 'noprint' ) while i < #configuration.setup do		i = i + 1 peice = eD peice:attr( 'class', configuration.setup[ i ] ) board:node( peice ) end fallback:attr( 'class', 'cd-fallback' ) :wikitext( '' ) board:node( fallback ) borderfix:wikitext( T ) :node( board ) interface:node( borderfix ) if configuration.instructions.controls then local controls = eD controls:attr( 'class', 'cd-controls' ) interface:node( controls ) end chessDemo:node( interface ) if configuration.notation.notes then local n		local c		local m		local be		local note local pe = eP local notes = {} local alternator = 1 local notewrap = eD local notation = eD local nnp = { '...', '.' } local columns = configuration.notation.columns local notecount = configuration.notation.numbering if configuration.blackfirst then alternator = 0 nnp = { '.', '...' } end notation:attr( 'class', 'cd-notation' ) pe:attr( 'class', 'cd-title' ) :wikitext( 'Notation' ) notation:node( pe ) if configuration.notation.collapsible then notation:addClass( 'mw-collapsible' ) if configuration.notation.collapsed then notation:addClass( 'mw-collapsed' ) end notewrap:attr( 'class', 'mw-collapsible-content' ) end for index, value in ipairs( configuration.notation.notes ) do			n = value[ 1 ] c = value[ 2 ] m = index % 2 if not note then be = eB note = eP note:node( be ) if columns then notes[ #notes + 1 ] = note else notewrap:node( note ) end if notecount then be:wikitext( tostring( notecount ) .. nnp[ m + 1 ] ) end end if c then note:tag( 'br' ) addSpan( note, c ) note = nil end if m == alternator then addSpan( be, n .. ' ' ) else addSpan( be, n ) if notecount then notecount = notecount + 1 end note = nil end end if columns then columns = tonumber( columns ) local column local created = 0 local notespercolumn = math.ceil( #notes / columns ) for index, value in ipairs( notes ) do				if ( index - 1 ) % notespercolumn == 0 then column = eD column:css( 'width', configuration.notation.width .. 'px' ) notewrap:node( column ) created = created + 1 end column:node( value ) end if created < columns then chessDemo:css( 'width', tostring( tonumber( configuration.width.master ) - ( tonumber( configuration.notation.width ) + 20 ) ) .. 'px' ) end elseif configuration.notation.float then notewrap:css( 'width', configuration.notation.width .. 'px' ) end notation:node( notewrap ) chessDemo:node( notation ) end chessDemo:wikitext( '' ) return tostring( chessDemo ) end

local function _getDemo( args ) local pC = 'cd-piece-' local pF = 'cd-file-' local pR = 'cd-rank-' local pR1 = pR .. '1'	local pR2 = pR .. '2'	local pR7 = pR .. '7'	local pR8 = pR .. '8'	local pB = pC .. 'black' local pW = pC .. 'white' local configuration = { width = { master = '204', board = '20', img = '160' },		clear = args.clear or 'both', float = args.float or 'right', title = args.title, info = args.information, setup = { join( { pB, ' ', pC, 'R ', pF, 'a ', pR8 } ), join( { pB, ' ', pF, 'a ', pR7 } ), join( { pB, ' ', pC, 'N ', pF, 'b ', pR8 } ), join( { pB, ' ', pF, 'b ', pR7 } ), join( { pB, ' ', pC, 'B ', pF, 'c ', pR8 } ), join( { pB, ' ', pF, 'c ', pR7 } ), join( { pB, ' ', pC, 'Q ', pF, 'd ', pR8 } ), join( { pB, ' ', pF, 'd ', pR7 } ), join( { pB, ' ', pC, 'K ', pF, 'e ', pR8 } ), join( { pB, ' ', pF, 'e ', pR7 } ), join( { pB, ' ', pC, 'B ', pF, 'f ', pR8 } ), join( { pB, ' ', pF, 'f ', pR7 } ), join( { pB, ' ', pC, 'N ', pF, 'g ', pR8 } ), join( { pB, ' ', pF, 'g ', pR7 } ), join( { pB, ' ', pC, 'R ', pF, 'h ', pR8 } ), join( { pB, ' ', pF, 'h ', pR7 } ), join( { pW, ' ', pF, 'a ', pR2 } ), join( { pW, ' ', pC, 'R ', pF, 'a ', pR1 } ), join( { pW, ' ', pF, 'b ', pR2 } ), join( { pW, ' ', pC, 'N ', pF, 'b ', pR1 } ), join( { pW, ' ', pF, 'c ', pR2 } ), join( { pW, ' ', pC, 'B ', pF, 'c ', pR1 } ), join( { pW, ' ', pF, 'd ', pR2 } ), join( { pW, ' ', pC, 'Q ', pF, 'd ', pR1 } ), join( { pW, ' ', pF, 'e ', pR2 } ), join( { pW, ' ', pC, 'K ', pF, 'e ', pR1 } ), join( { pW, ' ', pF, 'f ', pR2 } ), join( { pW, ' ', pC, 'B ', pF, 'f ', pR1 } ), join( { pW, ' ', pF, 'g ', pR2 } ), join( { pW, ' ', pC, 'N ', pF, 'g ', pR1 } ), join( { pW, ' ', pF, 'h ', pR2 } ), join( { pW, ' ', pC, 'R ', pF, 'h ', pR1 } ) },		orientation = args.orientation, notation = { numbering = 1, columns = removeAlphas( args.columns ) },		instructions = { speed = removeAlphas( args.speed ) or '2', autostart = args.autostart or false, blackfirst = false, controls = true, moves = {} }	}	configuration.instructions.setup = configuration.setup if args.initial then local i = removeAlphas( args.initial ) if i then configuration.instructions.initial = tonumber( i ) end else configuration.instructions.initial = 0 end if args.controls then if finder( args.controls, '^min' ) then configuration.instructions.controls = 'min' elseif finder( args.controls, '^med' ) then configuration.instructions.controls = 'med' else configuration.instructions.controls = false configuration.instructions.autostart = true end end if args.width then local width = removeAlphas( args.width ) if width then width = tonumber( width ) if width >= 200 then configuration.width.master = tostring( width + 4 ) configuration.width.board = tostring( width / 10 ) configuration.width.img = tostring( ( width / 10 ) * 8 ) end end end if not args.notation or ( args.notation and args.notation ~= 'hidden' ) then local columns = tonumber( configuration.notation.columns or '1' ) configuration.notation.notes = {} configuration.notation.width = tostring( ( math.floor( tonumber( configuration.width.master ) / columns ) - 20 ) + math.floor( 20 / columns ) ) if args.notation == 'collapsible' or args.notation == 'collapsed' then configuration.notation.collapsible = true if args.notation == 'collapsed' then configuration.notation.collapsed = true end elseif args.notation then configuration.notation.float = args.notation configuration.notation.width = removeAlphas( args.columnwidth ) or '120' configuration.width.master = tostring( tonumber( configuration.width.master ) + ( tonumber( configuration.notation.width ) * columns ) + ( 20 * columns ) ) end if args.numbering then local numbering = removeAlphas( args.numbering ) if numbering then configuration.notation.numbering = tonumber( numbering ) else configuration.notation.numbering = nil end end end for index, value in ipairs( args ) do		local splitarg = splitter( value, '\n', true ) local fromto = splitter( splitarg[ 1 ], '%s+' ) local to = replace( fromto[ 2 ], 'O', '0' ) configuration.instructions.moves[ #configuration.instructions.moves + 1 ] = { fromto[ 1 ], to }		if configuration.notation.notes then configuration.notation.notes[ #configuration.notation.notes + 1 ] = { mw.text.trim( to .. ' ' .. ( fromto[ 3 ] or '' ) ), splitarg[ 2 ] }		end end if args.setup then local bits = {} local color = '' local piece = '' local pieces = {} local coords = {} local firstmovefrom = configuration.instructions.moves[ 1 ][ 1 ] local splitarg = splitter( args.setup, ',%s*' ) for index, value in ipairs( splitarg ) do			bits = splitter( value, '%s+' ) color = toLower( bits[ 1 ] ) if #bits == 3 then piece = pC .. firstUpper( bits[ 2 ] ) .. ' '				coords = splitter( toLower( bits[ 3 ] ), '' ) else piece = '' coords = splitter( toLower( bits[ 2 ] ), '' ) end if configuration.blackfirst == nil and join( coords ) == firstmovefrom then configuration.blackfirst = color == 'black' configuration.instructions.blackfirst = configuration.blackfirst end pieces[ #pieces + 1 ] = join( { pC, color, ' ', piece, pF, join( coords, ' ' .. pR ) } ) end configuration.setup = pieces configuration.instructions.setup = pieces end return buildDemo( configuration ) end

local function _getNotation( args ) local arg = '' local move = '' if args.castle then arg = args.castle move = move .. '0-0'		if arg == 'queenside' then move = move .. '-0'		end elseif args.to then if args.from then move = move .. collapseToLower( args.from ) .. ' '		end if args.piece then move = move .. firstUpper( args.piece ) end move = move .. collapseToLower( args.disambiguation or '' ) if args.capture then move = move .. 'x'		end move = move .. collapseToLower( args.to ) if args.enpassant then move = move .. 'e.p.' end if args.promotion then arg = firstUpper( args.promotion ) if #arg > 0 then move = move .. '=' .. arg end end end if args.check then if toLower( args.check ) == 'mate' then move = move .. '#'		else move = move .. '+'		end end move = move .. collapseWhitespace( args.punctuation or '' ) if args.gamescore then arg = toLower( args.gamescore ) move = move .. ' '		if arg == 'white' then move = move .. '1–0'		elseif arg == 'black' then move = move .. '0–1'		else move = move .. '½–½'		end end if args.comment then move = move .. '\n' .. args.comment end return move end

function p.getNotation( frame ) return _getNotation( getArgs( frame:getParent.args ) ) end

function p.getDemo( frame ) local args = getArgs( frame:getParent.args ) if mw.isSubsting then local r = {} for key, value in pairs( args ) do			if not tonumber( key ) then r[ #r + 1 ] = key .. ' = ' .. value end end for index, value in ipairs( args ) do r[ #r + 1 ] = tostring( index ) .. ' = ' .. value end return '' end return _getDemo( args ) end

return p