Modulo:Scacchiera

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca

Il modulo:Scacchiera permette di generare diagrammi scacchistici. È richiamato nelle voci tramite alcuni template, come template:diagramma scacchi e simili, contenuti in questa categoria. Permette inoltre di convertire una stringa FEN nel corrispondente codice per i template e, viceversa, il codice wiki nella stringa FEN corrispondente.

La funzione principale del modulo è board. Oltre ai parametri per rappresentare la posizione nella scacchiera (vedi template:diagramma scacchi) accetta come argomenti:

  • size: dimensione del diagramma (lato della singola casa in px), il valore predefinito è 26.
  • reverse: booleano, se è vero il diagramma viene generato ribaltato.
  • header: titolo del diagramma.
  • footer: descrizione del diagramma.
  • align: allineamento orizzontale del diagramma nella pagina, il valore predefinito è tright.
  • fen: stringa FEN.
  • background: tipo di scacchiera (scacchi o chaturanga), il valore predefinito è scacchi.

La funzione fen2ascii permette di convertire una stringa FEN nella sintassi wiki corrispondente.


local p = {}

local function image_square( pc, row, col, size )
	local colornames = {
		l = 'del bianco',
		d = 'del nero',
		r = 'del rosso',
		g = 'del verde',
		y = 'del giallo'
	}
	local piecenames = { 
		p = 'pedone', 
		r = 'torre', 
		n = 'cavallo', 
		b = 'alfiere', 
		q = 'donna', 
		k = 're', 
		a = 'arcivescovo',
		c = 'cancelliere', 
		z = 'campione', 
		w = 'mago', 
		t = 'giullare', 
		h = 'pedone capovolto', 
		m = 'torre capovolta', 
		s = 'barca', 
		f = 're capovolto',  
		e = 'elefante', 
		g = 'grillo', 
		N = 'nottambulo', 
		B = 'alfiere capovolto',
	}
	local symnames = { 
		xx = 'croce nera', 
		ox = 'croce bianca', 
		xo = 'cerchio nero', 
		oo = 'cerchio bianco',
		ul = 'freccia verso sinistra in alto', 
		ua = 'freccia verso l\'alto', 
		ur = 'freccia verso destra in alto', 
		la = 'freccia verso sinistra', 
		ra = 'freccia verso destra',
		dl = 'freccia verso sinistra in basso', 
		da = 'freccia verso il basso', 
		dr = 'freccia verso destra in basso', 
		lr = 'freccia verso sinistra e destra', 
		ud = 'freccia verso l\'alto e il basso',
		x0 = 'zero', 
		x1 = 'uno', 
		x2 = 'due', 
		x3 = 'tre', 
		x4 = 'quattro', 
		x5 = 'cinque', 
		x6 = 'sei', 
		x7 = 'sette', 
		x8 = 'otto', 
		x9 = 'nove',
	}
	local colchar = {'a','b','c','d','e','f','g','h'}
	local color = mw.ustring.gsub( pc, '^.*(%w)(%w).*$', '%2' ) or ''
	local piece = mw.ustring.gsub( pc, '^.*(%w)(%w).*$', '%1' ) or ''
	local alt = colchar[col] .. row .. ' '

	if colornames[color] and piecenames[piece] then
		alt = alt .. piecenames[piece] .. ' ' .. colornames[color]
	else
		alt = alt .. ( symnames[piece .. color] or piece .. ' ' .. color )
	end

	return string.format( '[[File:Chess %s%st45.svg|%dpx|alt=%s|%s|link=]]', piece, color, size, alt, alt )

end

local function innerboard(args, size, rev, background)

	local bg_filename = ''
	if background == 'chaturanga' then
		bg_filename = 'Chaturanga489.png'
	else
		bg_filename = 'Chessboard480.svg'
	end

	local root = mw.html.create('div')
	root:addClass('chess-board')
	:css('position', 'relative')
	:wikitext(string.format( '[[File:%s|%dpx|link=]]', bg_filename, 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 ''
			if piece:match( '%w%w' ) then
				local img = image_square(piece:match('%w%w'), row, col, size )
				root:tag('div')
				:css('position', 'absolute')
				:css('z-index', '3')
				:css('top', tostring(( trow - 1 ) * size) .. 'px')
				:css('left', tostring(( tcol - 1 ) * size) .. 'px')
				:css('width', size .. 'px')
				:css('height', size .. 'px')
				:wikitext(img)
			end
		end
	end

	return tostring(root)
end

function chessboard(args, size, rev, letters, numbers, header, footer, align, clear, background)
	function letters_row( rev, num_lt, num_rt )
		local letters = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
		local root = mw.html.create('')
		if num_lt then
			root:tag('td')
			:css('vertical-align', 'inherit')
			:css('padding', '0')
		end
		for k = 1,8 do
			root:tag('td')
			:css('padding', '0')
			:css('vertical-align', 'inherit')
			:css('height', '18px')
			:css('width', size .. 'px')
			:wikitext(rev and letters[9-k] or letters[k])
		end
		if num_rt then
			root:tag('td')
			:css('vertical-align', 'inherit')
			:css('padding', '0')
		end
		return tostring(root)
	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 root = mw.html.create('div')
	:addClass('thumb')
	:addClass(align)
	:css('clear', clear)
	:css('text-align', 'center')
	:css('width', width .. 'px')
	:wikitext(header)
	local div = root:tag('div')
	:addClass('thumbinner')
	:css('width', width .. 'px')
	local b = div:tag('table')
	:attr('cellpadding', '0')
	:attr('cellspacing', '0')
	:css('background', 'white')
	:css('font-size', '88%')
	:css('border' , '1px #b0b0b0 solid')
	:css('padding', '0')
	:css('margin', 'auto')

	if ( letters_tp ) then
		b:tag('tr')
		:css('vertical-align', 'middle')
		:wikitext(letters_row( rev, numbers_lt, numbers_rt ))
	end
	local tablerow = b:tag('tr'):css('vertical-align','middle')
	if ( numbers_lt ) then 
		tablerow:tag('td')
		:css('padding', '0')
		:css('vertical-align', 'inherit')
		:css('width', '18px')
		:css('height', size .. 'px')
		:wikitext(rev and 1 or 8) 
	end
	local td = tablerow:tag('td')
	:attr('colspan', 8)
	:attr('rowspan', 8)
	:css('padding', '0')
	:css('vertical-align', 'inherit')
	:wikitext(innerboard(args, size, rev, background))

	if ( numbers_rt ) then 
		tablerow:tag('td')
		:css('padding', '0')
		:css('vertical-align', 'inherit')
		:css('width', '18px')
		:css('height', size .. 'px')
		:wikitext(rev and 1 or 8) 
	end
	if ( numbers_lt or numbers_rt ) then
		for trow = 2, 8 do
			local idx = rev and trow or ( 9 - trow )
			tablerow = b:tag('tr')
			:css('vertical-align', 'middle')
			if ( numbers_lt ) then 
				tablerow:tag('td')
				:css('padding', '0')
				:css('vertical-align', 'inherit')
				:css('height', size .. 'px')
				:wikitext(idx)
			end
			if ( numbers_rt ) then 
				tablerow:tag('td')
				:css('padding', '0')
				:css('vertical-align', 'inherit')
				:css('height', size .. 'px')
				:wikitext(idx)
			end
		end
	end
	if ( letters_bt ) then
		b:tag('tr')
		:css('vertical-align', 'middle')
		:wikitext(letters_row( rev, numbers_lt, numbers_rt ))
	end

	if (footer and footer ~= '') then
		div:tag('div')
		:addClass('thumbcaption')
		:wikitext(footer)
	end

	return tostring(root)
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 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[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
		local background = args.background or pargs.background or 'checks'

		size = mw.ustring.match( size, '[%d]+' ) or '26' -- remove px from size
		if (args['soluzione'] or pargs['soluzione']) then
			footer = footer .. "\n----\n''Soluzione'':<br />" .. (args['soluzione'] or pargs['soluzione'])
		end

		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, letters, numbers, header, footer, align, clear, background)
		end
		if args[3] then
			return chessboard(args, size, reverse, letters, numbers, header, footer, align, clear, background)
		else
			return chessboard(pargs, size, reverse, letters, numbers, header, footer, align, clear, background)
		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 .. '|' .. 
				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,'\| \|', '|  |' )
		return res
	end

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

	return p