模組:RegularTiling

本页使用了标题或全文手工转换
维基百科,自由的百科全书
文档图示 模块文档[查看] [编辑] [历史] [清除缓存]

本模組使用div、table搭配模板樣式繪製簡易的二維、三維空間密鋪色塊圖。

目前僅支援正圖形,包含下列密鋪色塊圖:

local p={}
local lib_arg={}
local yesno=require("Module:Yesno")

--二維空間填充(鑲嵌圖)生成
function p.simple_regular_tile(frame)
	local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true})
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local tile_type=args['type']or 4
    local tile_type_list={[3]=3,['3']=3,[4]=4,['4']=4,[6]=6,['6']=6,
    	tri=3,triangle=3,['三']=3,['三角']=3,['三角形']=3,
    	square=4,['方']=4,['四']=4,['四角']=4,['正方']=4,['方形']=4,['正方形']=4,['四角形']=4,['四邊形']=4,
    	hex=6,hexa=6,hexagon=6,['六']=6,['六角']=6,['六角形']=6,['六邊形']=6,
    }
    tile_type = tile_type_list[tile_type] or 4
    local arg_len,wid_len,table_list,color_map_str=0,0,{},args.color_map or args['color map']
    local color_map_in = color_map_str and mw.text.split(color_map_str,',') or {}
    for key,val in pairs(args)do if tonumber(key)or-1 > 0 then
    	if tonumber(key) > arg_len then arg_len=tonumber(key) end
    	local val_len=#(mw.text.split(val or'',','))
    	if tonumber(key)%2==0 and tile_type==6 then val_len=val_len-1 end
    	if val_len>wid_len then wid_len=val_len end
    end end
    for i=1,arg_len do
    	table_list[i]={}
	    for j=1,wid_len + ((i%2==0 and tile_type==6)and 1 or 0) do
	    	local val = mw.text.split(args[i] or'',',')
	    	table_list[i][j]=val[j]or''
	    end
    end
    local result_i=''
    for i=1,arg_len do
    	local tilerow_class = ((i%2==0 and tile_type==6)and' hex even'or'')
    	if args.tilerow_class or args['tilerow class'] then tilerow_class=tilerow_class..(args.tilerow_class or args['tilerow class']) end
    	tilerow_class=mw.text.trim(tilerow_class)
    	result_i = result_i .. '<div class="tile-row'..((tilerow_class~='')and(' '..tilerow_class)or'')..'">'
	    for j=1,wid_len + ((i%2==0 and tile_type==6)and 1 or 0) do
	    	local tile_class = {[3]='tri'..(((i+j)%2==0)and' inv'or''),[6]='hex'}
	    	local color_css_list = {[3]='border-'..(((i+j)%2==0)and'top'or'bottom')..'-color:*',[6]='border-bottom:0 solid *;border-top:0 solid *;'}
			local chk_color = mw.text.trim(table_list[i][j])
			chk_color = color_map_in[tonumber(chk_color)or-1]or color_map_in[chk_color]or chk_color
			if tonumber(chk_color:lower(),16) then chk_color='#'..chk_color end
			if chk_color==''then chk_color='transparent'end
			result_i = result_i .. '<div class="tile-cell'
			..(tile_class[tile_type]and(' '..tile_class[tile_type])or'')..'" style="'
			..(color_css_list[tile_type]or'background:*'):gsub('%*',chk_color)..';'..((args.textstyle and tile_type~=6) and (args.textstyle..';')or'')..'">'
			
			if tile_type==6 then result_i = result_i .. '<div></div><div style="background:'..chk_color..';'..(args.textstyle and (args.textstyle..';')or'')..'">'
			elseif tile_type==3 then result_i = result_i .. '<span class="center">'end

			result_i = result_i .. (args[i..','..j]or'')
			
			if tile_type==6 then result_i = result_i .. '</div><div></div>'
			elseif tile_type==3 then result_i = result_i .. '</span>'end

			result_i = result_i .. '</div>'
	    end
	    result_i = result_i .. '</div>'
    end
    local height_offset = (tile_type==6)and 30 or 0
    local width_offset = (tile_type==3)and -60 or 0
    local width_unit_list = {[3]=60,[4]=50,[6]=104}
    local height_unit_list = {[3]=104,[4]=50,[6]=90}
    local full_width = width_offset + width_unit_list[tile_type] * wid_len
    local full_height = height_offset + height_unit_list[tile_type] * arg_len
    local width_val = tonumber(mw.ustring.match(args.width or '','%-?%d+'))or full_width
	local scale_val = width_val/full_width

    local result='<div '..((mw.text.trim(args.class or '')=='')and''or('class="'..mw.text.trim(args.class or '')..'" '))
				..'style="width:'..width_val..'px;height:'..(full_height*scale_val)..'px;overflow:hidden;'..(args.style or'')..';">'
	result = result .. '<div style="position:relative;width:'..width_val..'px;height:'..width_val..'px;'
		..'"><div style="transform: scale('..scale_val..','..scale_val..');transform-origin: left top;">'
	result = result .. '<div class="tile-grid" style="width:'..(full_width+120)..'px;height:'..(full_height)..'px;">'
	result = result .. result_i
	result = result .. '</div></div></div></div>'
	return result
end

--QR碼生成
local qrrenderer={}
local qrencode=require( 'Module:EncoderUtil' )._get_libqrcode()
local color_table = require( 'Module:PeriodicTable' ).renderClassTable

--{CODE_0, CODE_1, FUNC_0, FUNC_1, OTHER}
local qr_color_table = {"F","T","F","T","F"}
local qr_color_mapping={[-2]=3,[-1]=1,[0]=5,[1]=2,[2]=4}

function p.simple_qr(frame)
	local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true})
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local input_text=args.text or args.message or args.msg or args[1] or args['1']
    local ec_level_list={l=1,m=2,q=3,h=4,[0]=1,[1]=1,[2]=2,[3]=3,[4]=4,
		low=1,medium=2,quartile=3,high=4
    }
    local ec_level = ec_level_list[(args.eclevel or''):lower()]or 1
    
    local color_map_in = args.color_map or args['color map']
    color_map_in = color_map_in and mw.text.split(color_map_in,',') or color_map_in
    
    local color_map_qr = {"T","T","T",[0]="",[-1]="",[-2]=""}
    if color_map_in then 
    	for i=-2,2 do
    		color_map_qr[i]=color_map_in[qr_color_mapping[i]]or color_map_in[''..qr_color_mapping[i]]or color_map_qr[i]
    	end 
    end
    local input_pre_data = input_text
    if yesno(args.bitstream or false) then input_pre_data = mw.text.split(input_text or '',',')end
	if not qrrenderer._CreateQRcode then qrrenderer = require( 'Module:QR' ) end
    --local ok, endata = qrencode.qrcode(input_pre_data,ec_level,nil,tonumber(args.version or args.ver))
    local ok, endata = qrrenderer._CreateQRcode(input_pre_data,ec_level,args.mode,tonumber(args.version or args.ver),tonumber(args.mask))
    if not ok then return "" end
    local full_width = 20 + 8*#endata
    local width_val = tonumber(mw.ustring.match(args.width or '','%-?%d+'))or full_width
	local scale_val = width_val/full_width
	local ten_times = scale_val * 10
	local result = '<div class="tile-grid qrcode'..((mw.text.trim(args.class or '')=='')and''or(' '..mw.text.trim(args.class or '')))
				..'" style="width:'..width_val..'px;height:'..width_val..'px;'..(args.style or'')..';">'
	result = result .. '<div style="position:relative;width:'..width_val..'px;height:'..width_val..'px;'
		..'"><div style="margin:'..ten_times..'px '..ten_times..'px '..ten_times..'px '..ten_times
		..'px;transform: scale('..scale_val..','..scale_val..');transform-origin: left top;">'
	result = result .. '<div style="width:'..(full_width-20)..'px;height:'..(full_width-20)..'px;">\n'
	result = result .. color_table("","",endata,',',color_map_qr,"")
	result = result .. '\n</div></div></div></div>'
	return result
end
function p.qr_graph(frame)
	-- For calling from #invoke.
    local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true}) --frame
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
    end
    local ec_level_list={l=1,m=2,q=3,h=4,[0]=1,[1]=1,[2]=2,[3]=3,[4]=4,
		low=1,medium=2,quartile=3,high=4
    }
    local qr_message =args.text or args.message or args.msg or args['string'] or args[1] or args['1'] or 'QR Code'
    local ec_level = ec_level_list[(args.eclevel or''):lower()]or 1
	local pxsize = tonumber(args.width or args.size or args.height or 120)
	
    local color_map_in = args.color_map or args['color map']
    color_map_in = color_map_in and mw.text.split(color_map_in,',') or color_map_in
    
    local color_map_qr = {"#000","#000","#000",[0]="#000",[-1]="#fff",[-2]="#fff"}
    if color_map_in then 
    	for i=-2,2 do
    		color_map_qr[i]=color_map_in[qr_color_mapping[i]]or color_map_in[''..qr_color_mapping[i]]or color_map_qr[i]
    	end 
    end
	
	local fun_light = args.fun_light or args.light or color_map_qr[-2]
	local message_light = args.message_light or args.light or color_map_qr[-1]
	local fun_dark = args.fun_dark or args.dark or color_map_qr[2]
	local message_dark = args.message_dark or args.dark or color_map_qr[1]
	
	if not qrrenderer._CreateQRcode then qrrenderer = require( 'Module:QR' ) end
	--local success,result = qrencode.qrcode(qr_message,ec_level,nil,tonumber(args.version or args.ver))
	local success,result = qrrenderer._CreateQRcode(qr_message,ec_level,args.mode,tonumber(args.version or args.ver),tonumber(args.mask))
	
	local w_count = #result
	local cell_width = pxsize / (w_count+2)
	local graph_data = {
		width=pxsize,
		height=pxsize,
		data={},
		padding={left=cell_width,top=cell_width,bottom=cell_width,right=cell_width},
		scales={
		    {name="x",type="linear",domain={0,w_count},range="width"},
		    {name="y",type="linear",domain={0,w_count},range="height"},
		    {name="qr",type="ordinal",domain={-2,-1,0,1,2},range={fun_light,message_light,message_light,message_dark,fun_dark}}
		},
		marks={
		    {
		      type="rect",
		      from={data="qrcode"},
		      properties={
		        enter={
		          x={scale="x",field="0"},y={scale="y",field="1"},
		          width={value=cell_width},height={value=cell_width},
		          stroke={scale="qr",field="2"},
		          fill={scale="qr",field="2"}
		        }
		      }
		    }
		 }
	}

	local qr_data = {name="qrcode",values={}}
	for x=1,w_count do
		for y=1,#(result[x]) do
			qr_data.values[#(qr_data.values)+1] = {x-1,#(result[x])-y+1,result[y][x]}
		end
	end
	graph_data.data[#(graph_data.data)+1] = qr_data
	local body = working_frame:callParserFunction{ name = '#tag:graph', args = {
    	mw.text.jsonEncode(graph_data)
	} }
	return body
end
function p.show_qr(input_text)
	local str = ""
	if type(input_text) == type(str) then
		str = input_text
	else
		if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        local args = lib_arg.getArgs(input_text, {parentFirst=true}) 
		str = args[1] or args["1"] or '{{{1}}}'
	end
	local ok, endata = qrencode.qrcode(str,4)
	if not ok then return "" end
mw.logObject(8*#endata)
	return color_table("","",endata,',',{"T","T","T",[0]="F",[-1]="F",[-2]="F"},"")
end

--魔方生成
local enum_face = {'u','d','f','b','l','r'}
local default_color_map = {'yellow','white','blue','green','orange','red','magenta','lime','cyan','black',[32768]='none',[32769]='null'}
local default_colors = {{0,0,0,0,0,0,0,0,0},{1,1,1,1,1,1,1,1,1},{2,2,2,2,2,2,2,2,2},{3,3,3,3,3,3,3,3,3},{4,4,4,4,4,4,4,4,4},{5,5,5,5,5,5,5,5,5}}
local enum_face_lookup = {u=0,d=1,f=2,b=3,l=4,r=5}
local default_text = {}
local cube_33 = {--lvl1
	{{{'u0','l0','b6'},{'u1','b7'},{'u2','r2','b8'}},--row
	{{'u3','l1'},{'u4'},{'u5','r1'}},
	{{'f0','u6','l2'},{'f1','u7'},{'f2','u8','r0'}}},
	--lvl2
	{{{'l3','b3'},{'b4'},{'r5','b5'}},
	{{'l4'},{},{'r4'}},
	{{'f3','l5'},{'f4'},{'f5','r3'}}},
	--lvl3
	{{{'d6','l6','b0'},{'d7','b1'},{'d8','r8','b2'}},
	{{'d3','l7'},{'d4'},{'d5','r7'}},
	{{'f6','d0','l8'},{'f7','d1'},{'f8','d2','r6'}}}
}
local rotate_face_lookup_if = {
		u={{{0,1,2},{0,1,2},{8,7,6},{0,1,2}},{{3,4,5},{3,4,5},{5,4,3},{3,4,5}}},
		d={{{8,7,6},{8,7,6},{0,1,2},{8,7,6}},{{5,4,3},{5,4,3},{3,4,5},{5,4,3}}},
		f={{{8,7,6},{2,5,8},{0,1,2},{6,3,0}},{{5,4,3},{1,4,7},{3,4,5},{7,4,1}}},
		b={{{0,1,2},{2,5,8},{8,7,6},{6,3,0}},{{3,4,5},{1,4,7},{5,4,3},{7,4,1}}},
		l={{{6,3,0},{6,3,0},{6,3,0},{6,3,0}},{{7,4,1},{7,4,1},{7,4,1},{7,4,1}}},
		r={{{2,5,8},{2,5,8},{2,5,8},{2,5,8}},{{1,4,7},{1,4,7},{1,4,7},{1,4,7}}},
	};
local rotate_face_lookup = {
		u={'f','r','b','l'},
		d={'f','l','b','r'},
		f={'u','l','d','r'},
		b={'u','r','d','l'},
		l={'u','b','d','f'},
		r={'u','f','d','b'},
	};
local face_center_rotate = {{2,6},{5,3},{8,0},{1,7},{-1,-1},{7,1},{0,8},{3,5},{6,2}};
local antipodes_table = {u='d',d='u',l='r',r='l',f='b',b='f'};

local function rubikCmdExpand(cmd)
	local do_string = cmd
	local old_string = do_string
	repeat
		old_string = do_string
		do_string = mw.ustring.gsub(do_string,"%(([^%(%)]*)%)%*?(%d*)",function(sub_cmd, str_count) 
			local count = tonumber(str_count) or 1
			return mw.ustring.rep(sub_cmd, count)
		end)
	until old_string == do_string
	return do_string
end

function p.initCube()
	local RubikCube = {
		color = {{0,0,0,0,0,0,0,0,0},{1,1,1,1,1,1,1,1,1},{2,2,2,2,2,2,2,2,2},{3,3,3,3,3,3,3,3,3},{4,4,4,4,4,4,4,4,4},{5,5,5,5,5,5,5,5,5}},
		text = {{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''}},
		color_map = default_color_map,
		side = 3,
		name = '',
	}
	function RubikCube:init(colors,texts,color_maps)
		self.color = {{0,0,0,0,0,0,0,0,0},{1,1,1,1,1,1,1,1,1},{2,2,2,2,2,2,2,2,2},{3,3,3,3,3,3,3,3,3},{4,4,4,4,4,4,4,4,4},{5,5,5,5,5,5,5,5,5}}
		self.color_map = default_color_map
		self.text={{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''},{'','','','','','','','',''}}
		if #colors ~= 6 then
			self.side = 3
		else
			self.side = math.sqrt(#(colors[1]))
			if self.side < 1 then self.side = 3 end
			self.color_map = color_maps or default_color_map
			local face_by2 = {0,2,6,8}
			local face_by2_inv = {0,-1,1,-1,-1,-1,2,-1,3}
			for i=0,5 do
				for j=0,8 do
					local color_id = -1
					local face_index = j
					if self.side < 3 then face_index = (self.side==1) and (j==4 and 0 or -1) or face_by2_inv[j+1]end
					self.color[i+1][j+1] = colors[i+1][face_index+1]
					self.text[i+1][j+1] = mw.text.trim((texts or {})[enum_face[i+1]..face_index]or'')
				end
			end
		end
	end
	function RubikCube:html(scale_val,style_data,class_data)
		local result,result_='',''
		local face_name = {'top','bottom','front','back','left','right'}
		local face_css = {
			'transform: rotateX(90deg) translateZ(50px);',--top
			'transform: rotateX(-90deg) translateZ(50px);',--bottom
			'transform: translateZ(50px);',--front
			'transform:  translateZ(-50px);',--back
			'transform: rotateY(-90deg) translateZ(50px);',--left
			'transform: rotateY(90deg) translateZ(50px);',--right
		}
		local col_css = {
			{"","",""},--by1
			{"transform: translateX(-50px);","","transform: translateX(50px);"},--by2
			[0]={"","transform: translateX(100px);","transform: translateX(200px);"}
		}
		local row_css = {
			{"","",""},--by1
			{"transform: translateZ(-50px);","","transform: translateZ(50px);"},--by2
			[0]={"transform: translateZ(-150px);","transform: translateZ(-50px);","transform: translateZ(50px);"}
		}
		local lvl_css = {
			{"transform: translateY(-100px) translateX(-100px);","transform: translateX(-100px);","transform: translateY(100px) translateX(-100px);"},--by1
			{"transform: translateY(-50px);","","transform: translateY(50px);"},--by2
			[0]={"","transform: translateY(100px);","transform: translateY(200px);"}
		}
		for i=#cube_33,1,-1 do local result_i=''
			for j=1,#(cube_33[i]) do local result_ij=''
				for k=1,#(cube_33[i][j]) do local result_ijk='' if self.side~=1 or (self.side==1 and #(cube_33[i][j][k])==1) then
					for l=1,#(cube_33[i][j][k]) do 
						local face_iterator_name = cube_33[i][j][k][l]:sub(1,1)
						local face_iterator = tonumber(cube_33[i][j][k][l]:sub(2,2))
						local face_enum_id = enum_face_lookup[face_iterator_name]
						local color_class_data = (self.color[face_enum_id+1][face_iterator+1]or-1)
						if (face_iterator==0 or face_iterator) and color_class_data>-1 then --self.color_map
						    result_ijk = result_ijk .. '<div class="cube-'..face_name[face_enum_id+1]..' '
						    	..self.color_map[color_class_data+1]..' '..cube_33[i][j][k][l]..'" style="'..face_css[face_enum_id+1]..'">'
						    	..self.text[face_enum_id+1][face_iterator+1]..'</div>'
						end
					end end
					result_ijk = mw.text.trim(result_ijk)
					if result_ijk~=''then
						result_ij = result_ij .. '<div class="cube col col'..k..
						'" style="transform-style: preserve-3d;'..col_css[0][k]..((col_css[self.side]or{'','',''})[k]or'')..'">' .. result_ijk .. '</div>'
					end
				end
				result_ij = mw.text.trim(result_ij)
				if result_ij~=''then
					result_i = result_i .. '<div class="row row'..j..
					'" style="transform-style: preserve-3d;'..row_css[0][j]..((row_css[self.side]or{'','',''})[j]or'')..'">' .. result_ij .. '</div>'
				end
			end
			result_i = mw.text.trim(result_i)
			if result_i~=''then
				result_ = result_ .. '<div class="lvl lvl'..i..
				'" style="transform-style: preserve-3d;'..lvl_css[0][i]..((lvl_css[self.side]or{'','',''})[i]or'')..'">' .. result_i .. '</div>'
			end
		end
		result_ = mw.text.trim(result_)
		if result_~=''then
			local cscale = tonumber(scale_val) or 1
			local fine_width = nil
			local find_px = mw.ustring.match(scale_val or '',"%d+px")
			if find_px then
				find_px = mw.ustring.match(find_px,"%d+")
				find_px = tonumber(find_px)
				if find_px then
					cscale = self.side==2 and ( -0.00355543 * (10.4658 - find_px) ) or ( -0.00234954 * (2.94521 - find_px) );
					fine_width = find_px
				end
			end
			if cscale <= 0 then cscale = 1 end
			local cwidth = self.side==2 and (10.4658 + 281.26 * cscale) or (2.94521 + 425.616 * cscale);
			local cheight = self.side==2 and (10.6849 + 294.795 * cscale) or (3.69863 + 455.89 * cscale);
			local margintop = self.side==2 and (-204.182 + 155.066*cscale + 55.8492*cscale*cscale) or (-253.44 + 113.609*cscale + 76.3805*cscale*cscale);
			local marginleft = self.side==2 and (-71.9178 + 166.575 * cscale) or (-74.0411 + 136.712 * cscale);
			result = result .. '<div '..((mw.text.trim(class_data or '')=='')and''or('class="'..mw.text.trim(class_data or '')..'" '))
				..'style="width:'..(fine_width or cwidth)..'px;height:'..cheight..'px;'..(style_data or'')..';">'
			result = result .. '<div style="width:'..(fine_width or cwidth)..'px;height:'..cheight..'px;position:relative;float:left;"><div style="width:150px;height:250px;margin-top:'
				..margintop..'px;margin-left:'..marginleft..'px;transform: scale('..cscale..', '..cscale..');">'
			result = result .. '<div class="cube-main'..(self.side<3 and(' by'..self.side)or'')
				..((mw.text.trim(self.name or '')=='')and''or(' '..mw.text.trim(self.name or '')))
				..((mw.text.trim(self.class or '')=='')and''or(' '..mw.text.trim(self.class or '')))..'" style="transform: translateZ(-50px) rotateX(335deg) rotateY(335deg) rotateZ(0deg) translateZ(50px); transform-style: preserve-3d;">'
				.. result_ .. '</div>'
			result = result .. '</div></div></div>'
		end
		return result
	end
	function RubikCube:netString()
		local result = ''
		local tmp_map = {[2]={1,3,-1,7,9},[3]={1,2,3,4,5,6,7,8,9}}
		
		result = result .. '__' .. ((self.side > 2)and'_'or'')
		result = result .. self.color[1][tmp_map[self.side][1]] .. self.color[1][tmp_map[self.side][2]]  .. ((self.side > 2)and self.color[1][tmp_map[self.side][3]]  or'') .. '\n'
		result = result .. '__' .. ((self.side > 2)and'_'or'')
		result = result .. self.color[1][tmp_map[self.side][4]]  .. self.color[1][tmp_map[self.side][5]]  .. ((self.side > 2)and self.color[1][tmp_map[self.side][6]]  or'') .. '\n'
		if self.side > 2 then result = result .. '___' .. self.color[1][7] .. self.color[1][8] .. self.color[1][9] .. '\n' end
		local prt_map = {5,3,6}
		for prt=1,#prt_map do
			for i=1,2 do result = result .. self.color[prt_map[prt]][tmp_map[self.side][i]] end 
			if self.side > 2 then result = result .. self.color[prt_map[prt]][3] end
		end
		result = result .. '\n'
		for prt=1,#prt_map do
			for i=4,5 do result = result .. self.color[prt_map[prt]][tmp_map[self.side][i]] end 
			if self.side > 2 then result = result .. self.color[prt_map[prt]][6] end
		end
		result = result .. '\n'
		if self.side > 2 then
			for prt=1,#prt_map do
				for i=7,9 do result = result .. self.color[prt_map[prt]][tmp_map[self.side][i]] end 
			end
			result = result .. '\n'
		end
		prt_map = {2,4}
		for prt=1,#prt_map do
			result = result .. '__' .. ((self.side > 2)and'_'or'')
			result = result .. self.color[prt_map[prt]][tmp_map[self.side][1]] .. self.color[prt_map[prt]][tmp_map[self.side][2]]  .. ((self.side > 2)and self.color[prt_map[prt]][tmp_map[self.side][3]] or'') .. '\n'
			result = result .. '__' .. ((self.side > 2)and'_'or'')
			result = result .. self.color[prt_map[prt]][tmp_map[self.side][4]]  .. self.color[prt_map[prt]][tmp_map[self.side][5]]  .. ((self.side > 2)and self.color[prt_map[prt]][tmp_map[self.side][6]] or'') ..'\n'
			if self.side > 2 then 
				result = result .. '___' 
				for i=7,9 do result = result .. self.color[prt_map[prt]][tmp_map[self.side][i]] end 
				result = result .. '\n'
			end
		end
		return mw.text.trim(result)
	end
	function RubikCube:turn(face,layer,cw)
		local rotate_face_lookup_it=rotate_face_lookup_if[face][layer+1]
		local face_index_id=enum_face_lookup[face]
		local face_turn_it_id=1
		if cw==1 or cw==true then face_turn_it_id=0 end
		local tmp_dom,last_color,last_text={},{},{}
		for i=0,#rotate_face_lookup_it-1 do
			local i0=i
			if cw==1 or cw==true then i0=#rotate_face_lookup_it-1-i end
			local turn_face_it = rotate_face_lookup[face][i0+1]
			local turn_face_it_id = enum_face_lookup[turn_face_it]

			for j=0,#(rotate_face_lookup_it[i0+1])-1 do
				local this_color = self.color[turn_face_it_id+1][rotate_face_lookup_it[i0+1][j+1]+1]
				local this_text = self.text[turn_face_it_id+1][rotate_face_lookup_it[i0+1][j+1]+1]
				if (this_color or -1) >= 0 then 
					if i==0 then
						tmp_dom[j+1] = {turn_face_it_id+1,rotate_face_lookup_it[i0+1][j+1]+1}
					else
						if i==#rotate_face_lookup_it-1 then 
							self.color[tmp_dom[j+1][1]][tmp_dom[j+1][2]] = this_color 
							self.text[tmp_dom[j+1][1]][tmp_dom[j+1][2]] = this_text 
						end
						self.color[turn_face_it_id+1][rotate_face_lookup_it[i0+1][j+1]+1] = last_color[j+1]
						self.text[turn_face_it_id+1][rotate_face_lookup_it[i0+1][j+1]+1] = last_text[j+1]
					end
					last_color[j+1]=this_color;
					last_text[j+1]=this_text;
				end
			end
		end
		if layer<1 then
			last_color,last_text={},{};for i=0,#face_center_rotate-1 do 
				last_color[i+1]=self.color[face_index_id+1][i+1] 
				last_text[i+1]=self.text[face_index_id+1][i+1] 
			end
			for i=0,#face_center_rotate-1 do
				local move_to = face_center_rotate[i+1][face_turn_it_id+1]
				if (move_to or -1) >= 0 then
					self.color[face_index_id+1][move_to+1]=last_color[i+1]
					self.text[face_index_id+1][move_to+1]=last_text[i+1]
				end
			end
		end
	end
	function RubikCube:turnByCommand(cmd_in)
		
		local cmd = rubikCmdExpand(cmd_in)
		cmd = mw.ustring.gsub(cmd, "[%+%-]", " " )
		cmd = mw.ustring.gsub(mw.ustring.gsub(cmd, "[Rr][Aa][Nn][Dd][Oo][Mm]", "-" ),"[Rr][Aa][Nn][Dd]","-")
		
		local parse,todo_cmd = {},{}
		mw.ustring.gsub(cmd,"[A-Za-z%-][%d']*",function(pcmd)parse[#parse+1]=pcmd end)
		if #parse<=0 then return nil end

		for i=1,#parse do
			if mw.ustring.sub(mw.text.trim(parse[i]),1,1) == '-' then
				local m_count = nil
				mw.ustring.gsub(parse[i],"%d+",function(numbers)m_count=m_count or numbers end)
				m_count = tonumber(m_count)or 1
				if m_count > 0 then for m_i=1,m_count do todo_cmd[#todo_cmd+1]="-" end end
			else
				todo_cmd[#todo_cmd+1]=parse[i]
			end
		end
		local result = {};
		for i=1,#todo_cmd do
			local turn_data = self:turnBySymbol(todo_cmd[i]);
			if turn_data ~= false then
				result[#result+1]=(turn_data~=true and turn_data or todo_cmd[i]);
			end
		end
		return result;
	end

	function RubikCube:turnBySymbol(sym)
		local chk_sym,is_rand=sym..'',false;
		if mw.ustring.sub(mw.text.trim(chk_sym),1,1)=="-" then
			local rand_sample = "udlrfbmesxyz";
			if self.side < 3 then rand_sample = "udlrfbxyz"end
			local sampling_val = math.floor(math.random() * rand_sample:len())+1
			chk_sym=rand_sample:sub(sampling_val,sampling_val);
			local rand_count=math.floor(math.random()*4);
			if math.floor(math.random()*2)==0 then chk_sym=chk_sym:lower()end
			if rand_count>1 then chk_sym=chk_sym..rand_count end
			if math.floor(math.random()*2)==0 then chk_sym=chk_sym.."'"end
			is_rand = true;
		end
		local checker = nil
		mw.ustring.gsub(chk_sym,"([UuDdLlRrFfBbMmEeSsXxYyZz])('?)(%-?%d*)('?)",function(m,inv,count,inv2)checker=checker or{m,inv,count,inv2}end)
		if checker==nil then return false end
		local turn_count=tonumber(checker[3])or 1;
		if turn_count<0 then turn_count=turn_count+(math.ceil((4-turn_count)/4)+4)*4 end
		turn_count = turn_count % 4
		local turn_count_inv=false;
		if turn_count>2 then
			turn_count=4-turn_count
			turn_count_inv=true
		end
		if turn_count==0 then return false end
		local way_test0 = (checker[2]==nil) and ""or checker[2]
		local way_test1 = (checker[4]==nil) and ""or checker[4]
		
		local inv_turn = (way_test0 ~= way_test1 and (way_test0=="'" or way_test1=="'"))
		local mid_turn = mw.ustring.match(checker[1], "[MmEeSs]")~=nil
		local all_turn = mw.ustring.match(checker[1], "[XxYyZz]")~=nil
		local single_turn = mw.ustring.upper(checker[1])==checker[1];
		if turn_count_inv then inv_turn=not inv_turn end
		local turning=function()return false end

		if mid_turn and self.side < 3 then return false end
		if single_turn and (not all_turn) or mid_turn then
			local command = mw.ustring.lower(checker[1]);
			local mid_table = {m='d',e='d',s='f'};
			command = mid_table[command] or command
			local local_do = function(this_the_cube,turn_comm,layer,turn_way)
				turning=function()
					this_the_cube:turn(turn_comm,layer,turn_way)
					return true
				end
			end
			local_do(self,command,mid_turn and 1 or 0,inv_turn and 0 or 1);
		elseif (not single_turn) or all_turn then
			local command = mw.ustring.lower(checker[1]);
			local mid_table = {x='r',y='u',z='f'};
			command = mid_table[command] or command
			local local_do = function(this_the_cube,turn_comm,every_turn,turn_way)
				turning=function()
					for vj=0,1 do this_the_cube:turn(turn_comm,vj,turn_way and 0 or 1) end
					if every_turn then this_the_cube:turn(antipodes_table[turn_comm],0,turn_way and 1 or 0)end
					return true
				end
			end
			local_do(self,command,all_turn,inv_turn);
		end
		
		local flag=false;
		for i=1,turn_count do 
			local check_flag = turning()
			flag = flag or check_flag
		end
		if is_rand then return chk_sym end
		return flag;
	end
	return RubikCube
end

function p.invertRubikCmd(cmd_in)
	local cmd = rubikCmdExpand(cmd_in)
	cmd = mw.ustring.gsub(cmd, "[%+%-]", " " )
	cmd = mw.ustring.gsub(mw.ustring.gsub(cmd, "[Rr][Aa][Nn][Dd][Oo][Mm]", " " ),"[Rr][Aa][Nn][Dd]"," ")
	
	local parse,todo_cmd = {},{}
	mw.ustring.gsub(cmd,"[UuDdLlRrFfBbMmEeSsXxYyZz][%d']*",function(pcmd)parse[#parse+1]=pcmd end)
	if #parse<=0 then return "" end
	local result = {}
	for i=#parse,1,-1 do
		local has_prime = false
		local prime_test = mw.ustring.gsub(parse[i],"'",function()
			has_prime = true
			return ''
		end)
		result[#result+1]=prime_test..((has_prime == false)and"'"or'')
	end
	return table.concat(result,' ');
end

function p.simple_cube(frame)
	local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true})
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local cube_face_data={}
    local cube_back_do={}
    local cube_side=nil
    
    for i=1,6 do 
    	local checker=args[mw.ustring.lower(enum_face[i])] or args[mw.ustring.upper(enum_face[i])]
    	cube_face_data[i]={}
    	if checker then
    		local data_array = mw.text.split(checker,',')
    		for j=1,#data_array do
    			local get_number = tonumber(mw.ustring.match(data_array[j],'%-?%d+'))
    			if not get_number then
    				if mw.text.trim(data_array[j])=='' then--no input
    					cube_face_data[i][j] = 32767
    				elseif mw.ustring.match(data_array[j],'[Nn][UuIi][Ll][Ll]?') then--指定為null
    					cube_face_data[i][j] = 32768
    				else--錯誤數值
    					cube_face_data[i][j] = -1
    				end
    			else
    				cube_face_data[i][j]=get_number
    			end
    		end
    		cube_side = cube_side or #data_array
    	else
    		cube_back_do[#cube_back_do+1]=i
    	end
    end
    if #cube_back_do >= 6 then cube_face_data = mw.clone( default_colors ) 
    else for i=1,#cube_back_do do 
		for j=1,(cube_side or 9) do
			cube_face_data[cube_back_do[i]][j]=32767
		end
    end end
    local color_map_in = args.color_map or args['color map']
    color_map_in = color_map_in and mw.text.split(color_map_in,',') or color_map_in
    if color_map_in then for i_t=32767,32769 do color_map_in[i_t]=default_color_map[i_t] end 
    	for i_key,i_val in pairs(color_map_in) do
    		color_map_in[i_key] = mw.text.trim(i_val)
    	end
    end
    local new_cube = p.initCube()
    new_cube:init(cube_face_data,args,color_map_in)
    if args.cube_class or args["cube class"] then new_cube.class = args.cube_class or args["cube class"] end
    if args.name then new_cube.class = args.name end
    local width_data = tonumber(mw.ustring.match(args.width or '','%-?%d+'))
    local scale_input = tonumber(mw.ustring.match(args.scale or '','%-?%d+'))
    local scale_data = width_data and (width_data .. 'px') or (scale_input or 1)
    if args.by_turn or args["by turn"] then
    	local cmd = args.by_turn or args["by turn"]
    	new_cube:turnByCommand(p.invertRubikCmd(cmd))
    end
    if args.turn then new_cube:turnByCommand(args.turn) end
    return new_cube:html(scale_data,args.style,args.class)
end

return p