Module:Shogi diagram

local shogiobject = {}

--- -- internal functions ---

-- returns a japanese character for a roman letter abbreviation -- called by the shogiboard function local function piecesymbol(abbreviation) -- the abbreviation argument is a string of 1-3 letters that stand for the English names of the shogi pieces -- the abbreviation is extracted out of a longer string by the processString function -- letter to character mapping (hash table) local piecenames = { p = '歩', t = 'と', l = '香', pl = '杏', n = '桂', pn = '圭', s = '銀', ps = '全', g = '金', b = '角', h = '馬', r = '飛', d = '龍', gyoku = '玉', ou = '王', tx = '个', plx = '仝', pnx = '今', dx = '竜', e = '象', a = '太' }	-- spit out the character corresponding to abbreviation -- if the abbreviation string is empty, then spit out nobreak space (for html tables) piece = piecenames[abbreviation] or ' ' return string.format( piece ) end

-- 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 function processString(ss) -- strip whitespace ss = mw.text.trim(ss) -- get the last character of the string local lastchar = mw.ustring.sub(ss, -1) -- chop off last character of string local restofstring = mw.ustring.sub(ss, 1, -2)

-- 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 boldness = 'normal' if lastchar == 'l' then boldness = 'bold' lastchar = mw.ustring.sub(restofstring, -1) restofstring = mw.ustring.sub(restofstring, 1, -2) end -- the side is either 'g' for 'gote' or 's' for 'sente' -- it's the last character in the string (and if the string ended) local side = lastchar -- the leftover string is the shogi piece abbreviation local pieceabbr = restofstring -- default is black font -- if the piece is promoted (one the abbreviations below), then the piece should be red local color = 'black' if pieceabbr == 't' or pieceabbr == 'pl' or pieceabbr == 'pn' or pieceabbr == 'ps' or pieceabbr == 'h' or pieceabbr == 'd' then color = 'red' end -- 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' and side == 'g' then pieceabbr = 'ou' end if pieceabbr == 'k' and side == 's' then pieceabbr = 'gyoku' end -- similar to above exception, reverse default if pieceabbr == 'ak' and side == 's' then pieceabbr = 'ou' end if pieceabbr == 'ak' and side == 'g' then pieceabbr = 'gyoku' end -- convert abbreviation to Japanese character local piecechar = piecesymbol(pieceabbr) -- special matches for arrows (n = north, s = south, etc.) -- NOTE: ddl, ddr, dul, and dur are named incorrectly -- yellow square     gray square      eastward arrow     westward arrow     northward arrow    southward arrow if ss:match('yy') or ss:match('gr') or ss:match('rat') or ss:match('lat') or ss:match('uat') or ss:match('dat') or		-- horizontal line    mid-to-w line      mid-to-e line      vertical line      mid-to-s line      mid-to-n line ss:match('lra') or ss:match('las') or ss:match('ras') or ss:match('uda') or ss:match('das') or ss:match('uas') or       -- sw-to-ne line     sw-to-ne arrow     ne-to-sw arrow      mid-to-ne line      mid-to-sw line      nw-to-se line ss:match('da') or ss:match('dau') or ss:match('dad') or ss:match('daus') or ss:match('dads') or ss:match('daa') or       --  nw-to-se arrow      se-to-nw arrow      mid-to-nw line       mid-to-sw line       s-to-e arrow       s-to-w arrow ss:match('daad') or ss:match('daau') or ss:match('daaus') or ss:match('daads') or ss:match('kar') or ss:match('kal') or       --   n-to-e arrow        n-to-w arrow      mid-to-e arrow     mid-to-w arrow     mid-to-s arrow     mid-to-n arrow ss:match('kadr') or ss:match('kadl') or ss:match('rah') or ss:match('lah') or ss:match('dah') or ss:match('uah') or       -- mid-to-ne arrow     mid-to-nw arrow     mid-to-se arrow     mid-to-sw arrow      s-to-ne line       s-to-nw line ss:match('durh') or ss:match('dulh') or ss:match('ddrh') or ss:match('ddlh') or ss:match('ddl') or ss:match('ddr') or       --  n-to-se line       n-to-sw line ss:match('dul') or ss:match('dur') then piecechar = '' side = 'arrow' color = 'arrow' boldness = 'arrow' end local result = {piecechar, side, color, boldness} return result 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 function makeTD(stringarg) -- got to process the string argument into its informational bits -- this processedstring is an array (or whatever the equivalent is in Lua) local processedstring = processString(stringarg) -- saving the pieces of the array as separate objects to be referred to below local piecechar = processedstring[1] local side = processedstring[2] local color = processedstring[3] local bold = processedstring[4] -- i guess one needs a root node? local root = mw.html.create('') -- the default local td = root:tag('td') td:css('border', 'black 1px solid') td:css('width', '20px') td:css('height', '20px') td:css('padding', '0') td:css('line-height', '0') td:css('font-family', '"Hiragino Mincho ProN", serif') if not side:match('arrow') then td:wikitext( piecechar ) end -- g = gote -- gote should be upside down text if side:match( 'g' ) then td:css('transform', 'rotate(180deg)') end -- for promoted pieces if color:match( 'red' ) then -- this is a darkish reddish color td:css('color', '#E00303') end

-- for bold pieces if bold:match( 'bold' ) then td:css('font-weight', 'bolder') -- traditionally bold type is gothic (sans serif) in Japanese typesetting of shogi diagrams within Japanese shogi books td:css('font-family', ' HiraginoSans-W5, sans-serif') end -- for arrow svgs if side:match('arrow') then td:css('padding', '0') td:css('width', '20px') td:css('height', '20px') td:css('font-size', '1px') td:css('line-height', '0') td:wikitext( piecechar ) end return tostring(root) end

-- function makes the shogi diagram -- this is basically a enclosing a .css wrapper with a inside function shogiboard(args) -- special args local special = {} if args[87] then -- a list of arguments separated by spaces for w in string.gmatch(args[87], "%w+") do			if string.sub(w, 1, 1) == "f" then -- flipped board special.flip = true elseif string.sub(w, 1, 1) == "j" then -- japanese row labeling special.jprows = true end end end -- these are the column coordinate labels 9-1 local colLabels if special.flip then colLabels = {'1', '2', '3', '4', '5', '6', '7', '8', '9', ' '} else colLabels = {'9', '8', '7', '6', '5', '4', '3', '2', '1', ' '} end -- these are the row coordinate labels local rowLabels if special.jprows then if special.flip then rowLabels = {'九', '八', '七', '六', '五', '四', '三', '二', '一'} else rowLabels = {'一', '二', '三', '四', '五', '六', '七', '八', '九'} end else if special.flip then rowLabels = {'9', '8', '7', '6', '5', '4', '3', '2', '1'} else rowLabels = {'1', '2', '3', '4', '5', '6', '7', '8', '9'} end end local headerarg = args[2] local toppieceinhandarg = args[3] local root = mw.html.create('div')

-- wrapper local shogiboardwrapper = root:tag('div') :addClass('shogiboardwrapper') :css('padding-left', '4px') :css('padding-bottom', '2px') -- the diagram header/caption local headerstring = mw.text.trim(headerarg) local header = shogiboardwrapper:tag('div') header:css('padding', '0') header:wikitext(headerstring) header:css('font-size', '14px')

-- this is the 'piece-in-hand' argument for gote -- strip whitespace local strippedpieceinhandtop = mw.text.trim(toppieceinhandarg) or '' -- put it in a with .css formating local pieceinhandtopdiv = shogiboardwrapper:tag('div') pieceinhandtopdiv:css('padding', '0') pieceinhandtopdiv:css('font-size', '12px') if special.flip then pieceinhandtopdiv:wikitext('☗ pieces in hand: ') else pieceinhandtopdiv:wikitext('☖ pieces in hand: ') end -- i was going to put the actual argument text into conditional .css formating, but i couldn't get the logical test in an if/else structure right... local piecesinhandtopspan = pieceinhandtopdiv:tag('span') piecesinhandtopspan:css('font-size', '13px') piecesinhandtopspan:wikitext(strippedpieceinhandtop) -- the shogi table local shogitable = shogiboardwrapper:tag('table') :addClass('shogitable') :attr('border', '1') :css('border-collapse', 'collapse') :css('border', 'none') :css('padding-top', '0') :css('background-color', 'white') -- font size for the shogi piece text piecefontsize = '17px' -- font size for the column/row piece coordinate labels (9-1) and (a-i) colrowfontsize = '11px' -- padding amount for the row piece coordinate labels (a-i) padrowlab = '1px' -- the row for the column coordinate labels local columnlabelrow = shogitable:tag('tr') :css('font-size', colrowfontsize) :css('background-color', '#f9f9f9') -- iterating over the column label to put each label in a 	for i,v in ipairs(colLabels) do 		local td = columnlabelrow:tag('td') :css('border', 'none') :css('width', '20px') :css('height', '5px') :wikitext( v ) end -- iterate over the 81 shogi piece arguments (left to right, top to bottom) -- 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 nx = 3 -- loop for all rows for icols = 1,9 do		local trow = shogitable:tag('tr') :css('font-size', piecefontsize) -- put a single piece into a 		-- iterate over 9 pieces in the row from offset -8 to 0 for irow = (icols*9)-8,(icols*9) do			trow:wikitext( makeTD(args[(irow+nx)]) ) end -- add row coordinate label local rowlabel = trow:tag('td') :css('border', 'none') :css('font-size', colrowfontsize) :css('padding-left', padrowlab) :css('padding-top', '0') :css('padding-bottom', '0') :css('background-color', '#f9f9f9') :wikitext( rowLabels[icols] ) end -- this is the 'piece-in-hand' argument for sente (same as above for gote) local strippedpieceinhandbottom = mw.text.trim(args[81+1+nx]) or '' local pieceinhandbottomdiv = shogiboardwrapper:tag('div') pieceinhandbottomdiv:css('padding', '0') pieceinhandbottomdiv:css('font-size', '12px') if special.flip then pieceinhandbottomdiv:wikitext('☖ pieces in hand: ') else pieceinhandbottomdiv:wikitext('☗ pieces in hand: ') end local piecesinhandbottomspan = pieceinhandbottomdiv:tag('span') piecesinhandbottomspan:css('font-size', '13px') piecesinhandbottomspan:wikitext(strippedpieceinhandbottom) return tostring(root) end

--- -- main function ---

function shogiobject.board(frame) -- need to use getParent.args for reasons i dont understand local args = frame:getParent.args return shogiboard(args) end

return shogiobject