Jump to content

Module:Sandbox/Fred Gandt/chessDemo

From Wikipedia, the free encyclopedia
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 = '</span>'
	local aP = '<span class="cd-persp-'
	local rC = aN .. 'class="cd-square-'
	local aW = aN .. aP .. 'w">'
	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( '[[File:Ajedrez animación en passant.gif|' .. configuration.width.img .. 'x' .. configuration.width.img .. 'px]]' )
	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( '[[Category:Pages using Template chessDemo]]' )
	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 '{{User:Fred Gandt/sandbox/chessDemo\n| ' .. join( r, '\n| ' ) .. '\n}}'
	end
	return _getDemo( args )
end

return p