モジュール:Shogi diagram

require('strict')
-- these are the column coordinate labels 9-1
local colLabels = {'9', '8', '7', '6', '5', '4', '3', '2', '1', ' '}
-- these are the row coordinate labels 1-9 (Japanese notation)
local rowLabels = {'一', '二', '三', '四', '五', '六', '七', '八', '九'}
-- letter to character mapping (hash table)
local pieces = {
	p = {'歩'},
	t = {'と', true},
	l = {'香'},
	pl = {'杏', true},
	n = {'桂'},
	pn = {'圭', true},
	s = {'銀'},
	ps = {'全', true},
	g = {'金'},
	b = {'角'},
	h = {'馬', true},
	r = {'飛'},
	d = {'龍', true},
	gyoku = {'玉'},
	ou = {'王'},
	tx = {'个', true},
	plx = {'仝', true},
	pnx = {'今', true},
	dx = {'竜', true},
	e = {'象'},
	a = {'太', true},
ai = {'合'}
}
local arrows = {'yy', 'gr', 'rat', 'lat', 'uat', 'dat', 
'lra', 'las', 'ras', 'uda', 'das', 'uas', 
'da', 'dau', 'dad', 'daus', 'dads', 'daa', 
'daad', 'daau', 'daaus', 'daads', 'kar', 'kal', 
'kadr', 'kadl', 'rah', 'lah', 'dah', 'uah', 
'durh', 'dulh', 'ddrh', 'ddlh', 'ddl', 'ddr', 
'dul', 'dur'}
-- function separates out the piece, the side, and the boldness info present in the string argument
-- it returns an array with these three values plus the color (for promoted pieces)
-- this info is passed to the makeTD() function
local function processString(ss)
	-- 先頭・末尾の空白文字類（全角空白なども含む）を除去する
	ss = mw.text.trim(ss or , '%s')
	if ss ==  then
		return ' '
	end
	-- 'da', 'ddl', 'dul', 'gr', 'kal' に対しては69行以下の判定が正しく動作しないため、ここで個別に判定
	if ss == 'da' then
		return '22px'
	end
	if ss == 'ddl' then
		return '22px'
	end
	if ss == 'dul' then
		return '22px'
	end
	if ss == 'gr' then
		return '22px'
	end
	if ss == 'kal' then
		return '22px'
	end
	-- get the last character of the string
	local lastchar = mw.ustring.sub(ss, -1)
	
	-- default is normal font
	-- but if the string ends with 'l' for 'last move', 
	-- then the font should be bold and we need to get a new string with the this 'l' chopped off (with a new last character)
	local bold = false
	local side = lastchar
	local pieceabbr = mw.ustring.sub(ss, 1, -2)
	if lastchar == 'l' then
		bold = true
		side = mw.ustring.sub(ss, -2, -2)
		pieceabbr = mw.ustring.sub(ss, 1, -3)
	end
	local gote = (side == 'g')
	
	-- this is an exceptional bit:
	-- gote's king is usually 王 instead of 玉 by convention, 
	-- but it's convenient to use the 'k' code for both sente and gote and let the default character be side-dependent
	if pieceabbr == 'k' then
		if gote then
			pieceabbr = 'ou'
		else
			pieceabbr = 'gyoku'
		end
	elseif pieceabbr == 'ak' then
		if gote then
			pieceabbr = 'gyoku'
		else
			pieceabbr = 'ou'
		end
	end
	-- convert abbreviation to Japanese character
	local piece = piecespieceabbr
	if not piece then
		for _, v in ipairs(arrows) do
			if ss == v then
				return '22px'
			end
		end
		error(ss, 0)
	end
	
	return piece1, piece2, gote, bold
end
-- function makes a  containing the piece with CSS stuff
-- uses the info from processString() to customize the CSS based on which side, color, and boldness
local function makeTD(stringarg)
	-- got to process the string argument into its informational bits
	local piecechar, promoted, gote, bold = processString(stringarg)
	-- the default 
	local td = mw.html.create('td')
		td:addClass('shogi-piece')
			:wikitext( piecechar )
	
	-- g = gote
	-- gote should be upside down text
	if gote then
		td:addClass('piece-gote')
	end
	
	-- for promoted pieces
	if promoted then
		td:addClass('piece-promoted')
	end
	-- for bold pieces
	if bold then
		td:addClass('piece-bold')
	end
	
	return td
end
-- function makes the shogi diagram
-- this is basically a  enclosing a .css  wrapper with a  inside
local function shogiboard(args)
	
	--  wrapper
	local shogiboardwrapper = mw.html.create('div')
		:addClass('shogiboard-wrapper')
	
	-- the diagram header/caption
	shogiboardwrapper:tag('div')
:addClass('shogiboard-header')
		:wikitext(mw.text.trim(args2 or ))
	-- the shogi table
	local shogitable = shogiboardwrapper:tag('table')
		:addClass('shogiboard-table')
		:attr('border', '1')
		
	-- the row for the column coordinate labels
	local columnlabelrow = shogitable:tag('tr')
		:addClass('shogiboard-collabel')
	-- iterating over the column label to put each label in a 
	for _, v in ipairs(colLabels) do 
		columnlabelrow:tag('td')
			:wikitext( v )
	end
	
	-- iterate over the 81 shogi piece arguments (left to right, top to bottom)
	-- i couldn't figure out how to do this is in a clever loopy way as i couldn't figure out how to close the html tags
	-- whatever, it's repetitive, but it works
	
	-- index number displacement/offset
	-- this is just the number of arguments that precede the 81 shogi piece arguments that are in the html 
	-- i just keep the piece arguments as indexes 1-81, then add nx to the index value
	local nx = 2
	
	-- the row for the shogi pieces
	for irow = 1,9 do
		local trow = shogitable:tag('tr')
		-- put a single piece into a 
		for icol = 1, 9 do
			local result, td = pcall(makeTD, args(irow - 1) * 9 + icol + nx)
			if not result then
				return string.format(
					'%s%sの位置で不明な値"%s"が指定されました。',
					colLabelsicol,
					rowLabelsirow,
					td
					)
			end
			trow:node(td)
		end
		-- add row coordinate label 
		trow:tag('td')
			:addClass('shogiboard-rowlabel')
			:wikitext( rowLabelsirow )
	end
	
-- the diagram footer
	shogiboardwrapper:tag('div')
:addClass('shogiboard-footer', 'bold')
		:wikitext(mw.text.trim(args84 or ))
	return tostring(shogiboardwrapper)
end
local valueFunc = function(_, value)
	if value then
		return mw.text.trim(value)
	else
		return false
	end
end
-----------------------
-- output
-----------------------
return {
	board = function(frame)
		return shogiboard(frame:getParent().args)
	end
}