이 모듈은 문서 내에 마작패 이미지를 쉽게 넣기 위해 만들어졌습니다. 마작패 이미지는 그 특성상 여러 이미지를 연달아 이어넣어야 하는데, 미디어위키의 이미지 삽입 문법을 이용해 하나하나 넣게 되면 오류가 발생하기 쉽고, 수정하기 힘들며 위키텍스트를 보았을 때 그 의미를 한 눈에 알아보기 쉽지 않습니다. 이 모듈은 이러한 문제점을 해결하기 위해, 사용자 친화적인 방식으로 마작패 이미지를 넣도록 해 줍니다.
마작패 모듈에는 크게 두 가지 메인 함수와 나머지 보조 함수가 있습니다. 메인 함수 두 가지는 '파싱' 함수와 '출력' 함수입니다.
마작 자체에 대한 자세한 설명은 마작 문서를 참고합니다.이 틀의 상세한 예는 리치마작 문서에서 확인할 수 있으며, 이 틀의 설명 문서를 수정하려면 모듈:마작패/설명문서 문서를 수정합니다.
간단한 사용법[원본 편집]
{{#invoke:마작패|파싱|123456789만}}
'파싱' 이라는 함수 이름 뒤에 구분자 기호 |
를 넣고, 그 뒤에 표기법대로 원하는 마작패를 쓰면 됩니다.
마작패 모듈의 표기법[원본 편집]
모듈:마작패 에서는 간결한 표기를 위해 각 마작패의 이름에서 한글자씩을 따와 대표어로 사용합니다. 특수한 기호를 대표어 앞에 넣어 추가적인 기능을 사용할 수도 있습니다.
- 수패
- 만수패는 '만', 통수패는 '통', 삭수패는 '삭' 이라는 대표어를 씁니다. 대표어 앞에 숫자를 1부터 9까지 쓰며, 숫자 사이에 대표어를 쓸 필요는 없습니다.
111222333444만
- 자패
- 자패는 바람패와 삼원패를 각각 '동남서북백발중' 이라는 대표어로 대신합니다.
- 적도라
- 적도라는 수패 5에만 있으며, '적5'라는 대표어를 적어 표시합니다.
1234적56789통
- 뒷면
- 깡 등으로 인해 뒷면을 표기해야 할 때는 '뒤'라는 대표어를 적어 표시합니다.
뒤22만뒤
- '치', '펑' 등으로 인해 가로로 눕힌 패의 표기
- 눕혀서 표기해야 하는 패 바로 앞에
-
기호를 적어 표기합니다.북북-북
- 소명깡(가깡)을 표기하기 위한 이중 표기
- 눕혀진 패 두 개가 겹쳐져서 표기해야 하는 패 바로 앞에
/
기호를 적어 표기합니다./222삭
파싱 함수[원본 편집]
파싱 함수는 연속된 마작패 이미지를 출력합니다. '파싱'이라는 함수명 뒤에 구분자를 적고, 표기법에 따라 마작패를 적어줍니다. 중간에 띄어쓰기가 있어도 무시하게 됩니다. 다음은 각 상황에 대한 사용법의 예시입니다.
- 수패 및 적도라
{{#invoke:마작패|파싱|234적5678삭}}
- 자패
{{#invoke:마작패|파싱|동남서북백발중}}
- 가로로 눕힌 패
입력한 값 | 실제 표시되는 모습 |
---|---|
{{#invoke:마작패|파싱|-345통}} |
|
{{#invoke:마작패|파싱|발발 -발}} |
- 가깡을 위한 이중 표기
입력한 값 | 실제 표시되는 모습 |
---|---|
{{#invoke:마작패|파싱|/345통}} |
|
{{#invoke:마작패|파싱|발발 /발}} |
- 표기법 조합
입력한 값 | 실제 표시되는 모습 |
---|---|
{{#invoke:마작패|파싱|999 123통}} |
|
{{#invoke:마작패|파싱|북 123만 중}} |
|
{{#invoke:마작패|파싱|123만적589삭2통}} |
|
{{#invoke:마작패|파싱|999 99 9만}} |
출력 함수[원본 편집]
출력 함수는 파싱 함수의 확장으로, 여러 패를 구분해서 입력해야 하는 경우에 사용합니다. 특히, 펑이나 치, 깡 등을 간단하게 입력하는 데에 최적화되어 있습니다. 파싱 함수와 동일한 요령으로 여러 표기법을 제한없이 적다가, 패의 구분이 필요할 때에 구분 기호 |
를 사용하여 입력하면 됩니다. 표기법 중간에 공백이 입력되면 단순히 무시합니다.
출력 함수에서는 #마작패 모듈의 표기법에 있는 표기법 외에도 펑이나 치, 깡을 위한 추가적인 표기법을 사용할 수 있습니다. 그러나 추가 표기법은 반드시 구분 기호로 분리하여 적어야 합니다.
- 펑 표기법
- '펑'이라는 대표어 뒤에 가져온 패를 적고, 바로 이어서 소괄호 안에 누구에게 가져왔는지(상가, 대가 또는 하가) 적습니다.
{{#invoke:마작패|출력|펑4만 (대가)}}
- 치 표기법
- '치'라는 대표어 뒤에 가져온 패를 적고, 나머지 두 패를 소괄호 안에 적습니다.
{{#invoke:마작패|출력|치 8삭(79삭)}}
- 깡 표기법
- '깡'이라는 대표어 뒤에 가져온 패를 적습니다. 안깡인 경우에는 그대로 두고, 타가에게서 받아온 경우에는 펑과 마찬가지로 소괄호 안에 적습니다.
{{#invoke:마작패|출력|깡 발}}
{{#invoke:마작패|출력|깡중(하가)}}
- 가깡 표기법
- 파싱 함수의 이중 표기와 유사한 표기법을 사용하며, '펑' 또는 '깡' 대표어 뒤에
/
기호를 사용합니다.{{#invoke:마작패|출력|펑 /8통 (상가)}}
{{#invoke:마작패|출력|깡/서(하가)}}
- 표기법 조합
- 출력 함수는 표기법을 조합해서 구분자 기호를 사용해 여러 패를 동시에 적을 수 있습니다. 물론, 추가된 펑/치/깡 표기법을 사용하지 않아도 됩니다.
입력한 값 | 실제 표시되는 모습 |
---|---|
{{#invoke:마작패|출력|567만|8888통|백백| 깡 발(상가) |중}} |
|
{{#invoke:마작패|출력|깡 동|남남 / 남|깡 서 (대가)|뒤북북뒤|11통}} |
|
{{#invoke:마작패|출력|깡4만(대가)|123 만|9 통|펑 /4만(상가)}} |
|
{{#invoke:마작패|출력|938삭 726만|깡 9통(하가)}} |
기타 옵션[원본 편집]
옵션 값을 통해 출력 결과물을 조정하거나 기타 정보를 추가할 수 있습니다. 옵션의 순서는 무관하며, {옵션 이름} = {옵션 값}
형식으로 적습니다.
- 게임과 자리 표기법
- 현재 게임의 국 수와 자리를 옵션으로 표기할 수 있습니다. 옵션은 '게임'과 '자리'라는 이름을 사용합니다.
{{#invoke:마작패|출력|23만|444555666통|북북|게임=동1국|자리=남}}
- (동1국 남가)
{{#invoke:마작패|출력|서서|백백백|자리=서|999삭|234만|55통}}
- (서가)
- 도라와 쯔모, 론패 표기법
- 각각 '도라'와 '쯔모', '론'이라는 옵션을 사용합니다. 옵션의 순서는 무관합니다. 쯔모와 론 옵션은 동시에 사용할 수 없습니다.
{{#invoke:마작패|출력|서서|북북북|999만|345통|55통|자리=서|쯔모=적5통}}
- (서가) 쯔모
{{#invoke:마작패|출력|1통|111만|999만|111삭|999삭|론=1통|도라=19만19삭|자리=동|게임=남4국}}
- (남4국 동가) 론 도라
- 이미지 크기 조절
size
옵션을 사용하여 이미지의 가로 크기를 조정할 수 있습니다. 현재 업로드된 이미지는 가로 66px, 세로 90px의 이미지로서 이미지의 왜곡이 발생하지 않게 하기 위해서는 소수점이 발생하지 않는 11의 배수로 입력해야 합니다 (반드시 그래야 하는 것은 아닙니다). 기본값은 33입니다.
{{#invoke:마작패|출력|123-456만|size=22}}
{{#invoke:마작패|출력|123-456만|size=37}}
{{#invoke:마작패|출력|123-456만|size=44}}
보조 함수들[원본 편집]
보조 함수는 위 파싱 함수와 출력 함수의 단축키 역할을 합니다. 일반적으로 많이 사용될 것으로 예상되는 형태의 패를 미리 설정해 두었습니다.
입력한 값 | 실제 표시되는 모습 |
---|---|
{{#invoke:마작패|만수패}} |
|
{{#invoke:마작패|통수패}} |
|
{{#invoke:마작패|삭수패}} |
|
{{#invoke:마작패|바람패}} |
|
{{#invoke:마작패|삼원패}} |
|
{{#invoke:마작패|자패}} |
--[[
-- token 변수는 실제 사용자로부터 입력받는 글자, 또는 화면에 출력되는 글자를
-- 정의합니다. 만약 이 모듈을 포크해서 다른 위키로 가져가는 경우 이 부분을 필
-- 요에 따라 다르게 수정하면 됩니다.
--]]
local token = {
-- mw 파일 표기 prefix--
file_header = '파일:마작-',
img_side = '-누움',
ext = '.png',
-- 수패 --
man = '만', pin = '통', sou = '삭',
-- 자패 --
E = '동', S = '남', W = '서', N = '북',
white = '백', green = '발', red = '중',
-- 꽃패 --
f1 = '춘', f2 = '하', f3 = '추', f4 = '동',
f5 = '매', f6 = '난', f7 = '국', f8 = '죽',
-- 펑, 치, 깡 --
pon = '펑', chi = '치', kan = '깡',
left = '상가', face = '대가', right = '하가',
-- 뒷면 --
back = '뒤',
-- 특수표기 --
dora = '적',
side = '-',
double = '/',
-- 쯔모, 론, 도라, 게임 등의 옵션들 --
tsumo_ = '쯔모',
ron_ = '론',
dora_ = '도라',
wind_ = '자리',
side_ = '가',
game_ = '게임',
-- 에러메시지 --
error = {
default = "에러가 발생했습니다. 구문을 확인해주세요",
nofunct = "알 수 없는 함수가 호출되었습니다",
body = "패가 잘못되었습니다. 구문을 확인해주세요",
dir = "알 수 없는 방향입니다. 구문을 확인해주세요",
braket = "괄호가 없거나 잘못되었습니다. 구문을 확인해주세요"
},
-- 공백 --
space = ' '
}
-- 이미지 기본값 --
local image_default_size = 33
local image_real_width = 66
local image_real_height = 90
--[[ 헬퍼 함수들 ]]--
local ustring = mw.ustring
local image_ratio = function (x) return math.floor(x * image_real_height / image_real_width) end
-- switch-case 문을 위한 함수 --
-- from http://lua-users.org/wiki/SwitchStatement --
local function switch (t)
t.case = function (self, x)
local f = self[x] or self.default
if f then
if type(f) == "function" then
f(x, self)
else
error(tostring(x) .. ":" .. token.error.nofunct)
end
end
end
return t
end
-- mw용 이미지 문법을 생성해주는 함수 --
local function toImg ( data, width )
width = '|' .. width .. 'px'
local result = '[[' .. token.file_header .. data .. token.ext .. width ..'|link=|bottom]]'
return result
end
-- 에러 출력용 함수 --
local function err ( message, pos, func )
func = (func ~= nil) and '['..func..'] ' or ''
pos = (pos ~= nil) and 'p'..pos..': ' or ''
error(func..pos..message)
end
-- 펑/깡을 위한 방향 체크 --
local pon_dir = {
[token.left] = 1,
[token.face] = 2,
[token.right] = 3
}
local kan_dir = {
[token.left] = 1,
[token.face] = 2,
[token.right] = 4
}
-- forward declaration --
local pre_option
local post_option
--[[ 입력받은 값을 분석하는 메인 함수 ]]--
local function single_parse ( data, options )
if (data == nil) then err(token.error.default) end
local result = ""
-- parser variable --
local index = 0
local stack = {}
local pre = ""
local side = ""
local wrapper = false
clean_stack = function () index = 0 ; stack = {} end
clean_state = function () pre = "" ; side = "" ; wrapper = false end
local size = options.size or image_default_size
local token_parse = {
default = function (x) return true end
}
-- 특수표기 --
token_parse[token.dora] = function (x) pre = x end
token_parse[token.side] = function (x) side = token.img_side end
token_parse[token.double] = function (x) wrapper = true ; side = token.img_side end
-- 숫자 --
for i = 1, 9 do
token_parse[tostring(i)] = function (x)
index = index + 1
stack[index] = {}
-- 필요한 값들을 스택에 넣는다
stack[index].main = x
stack[index].pre = pre
stack[index].side = side
stack[index].wrapper = wrapper
clean_state()
end
end
-- 수패 --
local function numbers (x)
for i = 1, index do
local width = (stack[i].side ~= '') and image_ratio(size) or size
local caption = (stack[i].pre or '') .. stack[i].main .. x .. (stack[i].side or '')
if (stack[i].wrapper) then -- 이중 처리
result = result .. '<div style="display: inline-block;">'
.. '<div>' .. toImg( caption, width ) .. '</div>'
.. toImg( caption, width )
.. '</div>'
else
result = result .. toImg( caption, width )
end
end
clean_stack() ; clean_state()
end
token_parse[token.man], token_parse[token.pin], token_parse[token.sou] = numbers, numbers, numbers
-- 자패, 뒷면 --
local function strings (x)
local width = (side ~= '') and image_ratio(size) or size
if (wrapper) then -- 이중 처리
result = result .. '<div style="display: inline-block;">'
.. '<div>' .. toImg( x..side, width ) .. '</div>'
.. toImg( x..side, width )
.. '</div>'
else
result = result .. toImg( x..side, width )
end
clean_stack() ; clean_state()
end
token_parse[token.E] = strings
token_parse[token.S] = strings
token_parse[token.W] = strings
token_parse[token.N] = strings
token_parse[token.white] = strings
token_parse[token.green] = strings
token_parse[token.red] = strings
token_parse[token.back] = strings
-- 꽃패 --
token_parse[token.f1] = strings
token_parse[token.f2] = strings
token_parse[token.f3] = strings
token_parse[token.f4] = strings
token_parse[token.f5] = strings
token_parse[token.f6] = strings
token_parse[token.f7] = strings
token_parse[token.f8] = strings
-- switch 문 구성 --
token_parse = switch(token_parse)
-- utf8 문자별로 루프 진행 --
local pos = 0
while #data > 0 do
local c = ustring.match(data, ".")
data = data:sub(#c+1) ; pos = pos + 1
token_parse:case(c) -- 위 select-case 문에 따라 처리
end
return '<div class="majong" style="display:inline-block;">'..result..'</div>'
end
local function parse ( frame ) -- '파싱' 함수 entry point
return pre_option(frame.args) .. single_parse( frame.args[1]:match("^%s*(.-)%s*$"), frame.args ) .. post_option(frame.args) -- trim
end
local function single_print ( data, options )
if (data == nil) then err(token.error.default) end
local pos = 1
local op = ustring.match(data, ".") or ''
pos = pos + #op
local caption = ''
-- 치 --
if (op == token.chi) then
data = data:sub(#op+1)
local body = ustring.match(data, "%s*(%d?.)") or ''
if (#body == 0) then err(token.error.body, pos, token.chi) end
pos = pos + #body
local tail = ustring.match(data, ".*%((.-)%)") or '' -- 괄호 부분 체크
if (#tail == 0) then err(token.error.braket, pos, token.chi) end
pos = pos + #tail
caption = token.side .. body .. tail -- 치는 반드시 상가에게만 받게됨
-- 펑 --
elseif (op == token.pon) then
data = data:sub(#op+1)
local body = ustring.match(data, "%s*(/?%d?.)") or ''
if (#body == 0) then err(token.error.body, pos, token.pon) end
pos = pos + #body
local tail = ustring.match(data, ".*%((.-)%)") or '' -- 괄호 부분 체크
if (#tail == 0) then err(token.error.braket, pos, token.pon) end
pos = pos + #tail
-- 가깡 처리 --
local selector = token.side
if (body:sub(1, 1) == '/') then
body = body:sub(2)
selector = token.double
end
-- 방향에 맞게 캡션 처리 --
local dir = pon_dir[tail] or -1
if (dir == -1) then err(token.error.dir, pos, token.pon) end
for i = 1, 3 do
if (i == dir) then caption = caption .. selector end
caption = caption .. body
end
-- 깡 --
elseif (op == token.kan) then
data = data:sub(#op+1)
local body = ustring.match(data, "%s*(/?%d?.)") or ''
if (#body == 0) then err(token.error.body, pos, token.kan) end
pos = pos + #body
local tail = ustring.match(data, "%s*%((.-)%)") or '' -- 괄호 부분 체크
pos = pos + #tail
-- 안깡 --
if (#tail == 0) then
caption = token.back .. body .. body .. token.back
-- 가깡 --
elseif (body:sub(1, 1) == '/') then
local dir = pon_dir[tail] or -1
if (dir == -1) then err(token.error.dir, pos, token.kan) end
body = body:sub(2)
for i = 1, 3 do
if (i == dir) then caption = caption .. token.double end
caption = caption .. body
end
-- 대명깡 --
else
local dir = kan_dir[tail] or -1
if (dir == -1) then err(token.error.dir, pos, token.kan) end
for i = 1, 4 do
if (i == dir) then caption = caption .. token.side end
caption = caption .. body
end
end
-- 기타 --
else
caption = data
end
return single_parse(caption, options)
end
local function print ( frame ) -- '출력' 함수 entry point
local result = ''
local data = {}
for k, line in pairs(frame.args) do -- 옵션값을 제외한 나머지 입력값들을 data에 모음
if (type(k) == "number") then data[k] = line end
end
for i = 1, #data do
result = result .. single_print( data[i]:match("^%s*(.-)%s*$"), frame.args ) -- trim
if (i ~= #data) then result = result .. token.space end
end
return pre_option(frame.args) .. result .. post_option(frame.args)
end
--[[ 옵션 출력을 위한 보조 함수 ]]--
pre_option = function (options)
local result = ''
-- 게임 옵션 출력 --
if (options[token.game_] ~= nil) then
result = options[token.game_]
end
-- 자리 출력 --
if (options[token.wind_] ~= nil) then
if (result ~= '') then result = result .. token.space end
result = result .. options[token.wind_] .. token.side_
end
if (result ~= '') then result = '(' .. result .. ')' .. token.space end
return '<div class="majong-group" style="white-space:nowrap;overflow-x:auto;">' .. result
end
post_option = function (options)
local result = ''
-- 화료패 출력 --
if (options[token.tsumo_] ~= nil) then
result = token.space .. token.tsumo_ .. single_parse(options[token.tsumo_], options)
elseif (options[token.ron_] ~= nil) then
result = token.space .. token.ron_ .. single_parse(options[token.ron_], options)
end
-- 도라패 출력 --
if (options[token.dora_] ~= nil) then
if (result ~= '') then result = result .. token.space end
result = result .. token.dora_ .. single_parse(options[token.dora_], options)
end
if (result ~= '') then result = token.space .. result end
return result .. '</div>'
end
return {
['파싱'] = parse,
['출력'] = print,
-- 자주 쓰이는 함수들 --
['만수패'] = function (f) return single_parse( "123456789만", f.args ) end,
['통수패'] = function (f) return single_parse( "123456789통", f.args ) end,
['삭수패'] = function (f) return single_parse( "123456789삭", f.args ) end,
['자패'] = function (f) return single_parse( "동남서북백발중", f.args ) end,
['바람패'] = function (f) return single_parse( "동남서북", f.args ) end,
-- ['꽃패'] = function (f) return single_parse( "춘하추동매난국죽", f.args ) end,
['삼원패'] = function (f) return single_parse( "백발중", f.args ) end
}