221 lines
4.6 KiB
Lua
221 lines
4.6 KiB
Lua
-- Rubik Cube
|
|
|
|
if not init then init = true
|
|
self.listen_punch(self.pos())
|
|
pname = find_player(5); if not pname then say("no players!");self.remove() end; pname = pname[1];
|
|
player = minetest.get_player_by_name(pname)
|
|
say("rubik cube. rotation is indicated by your view direction")
|
|
|
|
n=3;
|
|
-- top left first
|
|
|
|
yz1 = { -- size n^2, side looking toward x-
|
|
7,1,8,
|
|
1,1,1,
|
|
9,1,1
|
|
}
|
|
|
|
yz2 = { -- size n^2, side looking toward x+
|
|
7,2,8,
|
|
2,2,2,
|
|
9,2,2
|
|
}
|
|
|
|
xy1 = { -- size n^2, side looking toward z-
|
|
7,3,8,
|
|
3,3,3,
|
|
9,3,3
|
|
}
|
|
|
|
xy2 = { -- size n^2, side looking toward z+
|
|
7,4,8,
|
|
4,4,4,
|
|
9,4,4,
|
|
}
|
|
|
|
xz1 = { -- size n^2, side looking toward y-
|
|
7,5,8,
|
|
5,5,5,
|
|
9,5,5,
|
|
}
|
|
|
|
xz2 = { -- size n^2, side looking toward y+
|
|
7,6,8,
|
|
6,6,6,
|
|
9,6,6,
|
|
}
|
|
|
|
surfdata = {
|
|
["yz1"]={
|
|
rotations = {
|
|
[0] = "face cw",
|
|
[1] = "face ccw",
|
|
[2] = "horizontal +",
|
|
[3] = "horizontal -",
|
|
[4] = "vertical +",
|
|
[5] = "vertical -",
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
blocks = {
|
|
"basic_robot:button808080",
|
|
"basic_robot:buttonFF8080",
|
|
"basic_robot:button80FF80",
|
|
"basic_robot:button8080FF",
|
|
"basic_robot:buttonFFFF80",
|
|
"basic_robot:buttonFFFFFF",
|
|
"basic_robot:button_48", --7
|
|
"basic_robot:button_49", --8
|
|
"basic_robot:button_50", --9
|
|
}
|
|
|
|
render_cube = function()
|
|
local p = self.pos();
|
|
for y=1,n do
|
|
for z=1,n do
|
|
minetest.swap_node({x=p.x+1,y=p.y+y+1,z=p.z+z},{name = blocks[yz1[n*(y-1)+z]]})
|
|
end
|
|
end
|
|
for y=1,n do
|
|
for z=1,n do
|
|
minetest.swap_node({x=p.x+n+2,y=p.y+y+1,z=p.z+z},{name = blocks[yz2[n*(y-1)+z]]})
|
|
end
|
|
end
|
|
|
|
for x=1,n do
|
|
for y=1,n do
|
|
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z},{name = blocks[xy1[n*(x-1)+y]]})
|
|
end
|
|
end
|
|
|
|
for x=1,n do
|
|
for y=1,n do
|
|
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z+n+1},{name = blocks[xy2[n*(x-1)+y]]})
|
|
end
|
|
end
|
|
|
|
for x=1,n do
|
|
for z=1,n do
|
|
minetest.swap_node({x=p.x+x+1,y=p.y+1,z=p.z+z},{name = blocks[xz1[n*(x-1)+z]]})
|
|
end
|
|
end
|
|
|
|
for x=1,n do
|
|
for z=1,n do
|
|
minetest.swap_node({x=p.x+x+1,y=p.y+n+2,z=p.z+z},{name = blocks[xz2[n*(x-1)+z]]})
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
rotccw = function(tab)
|
|
local newtab = {}
|
|
local n = (#tab)^0.5
|
|
for i = 1,n do
|
|
for j = 1,n do
|
|
newtab[(i-1)*n+j] = tab[(j-1)*n+n-i+1]
|
|
end
|
|
end
|
|
return newtab
|
|
end
|
|
|
|
rotcw = function(tab)
|
|
local newtab = {}
|
|
local n = (#tab)^0.5
|
|
for i = 1,n do
|
|
for j = 1,n do
|
|
newtab[(j-1)*n+n-i+1] = tab[(i-1)*n+j]
|
|
end
|
|
end
|
|
return newtab
|
|
end
|
|
|
|
viewlim = 0.9; --how close to perpendicular need to look to rotate face
|
|
p = self.pos();
|
|
render_cube()
|
|
end
|
|
|
|
event = keyboard.get()
|
|
if event then
|
|
-- rotate depending where player looks, if he looks close to normal to surface rotate cw or ccw
|
|
local view = player:get_look_dir()
|
|
-- which way? face or horizontal or vertical?
|
|
local rot = 0; -- rotation mode
|
|
local face = "";
|
|
local x=1;local y=1;
|
|
|
|
if event.x == p.x+1 then
|
|
face= "yz1"
|
|
if math.abs(view.x)>viewlim then
|
|
rot = 0; -- face cw
|
|
yz1 = rotcw(yz1); -- face cw rotate
|
|
--slice x=1 rotate:
|
|
--[[{
|
|
xz2,row 1,rev
|
|
xy1,row 1,rev
|
|
xz1,row 1,ord
|
|
xy2,col 3,ord
|
|
|
|
}
|
|
note this same rotation can be reused for faces xz1,xy1,xz1,xy2
|
|
|
|
maybe:
|
|
|
|
rotslice(
|
|
{xz2,1=row mode, 1 = row index, -1 = reverse},
|
|
{xy1,1, 1, -1},
|
|
{xz1,1, 1, 1 = ordinary},
|
|
{xy2,2=col mode,3 = col index, 1}
|
|
)
|
|
|
|
--]]
|
|
elseif math.abs(view.y)<math.abs(view.z) then -- horizontal
|
|
if view.z>0 then rot = 2 else rot = 3 end
|
|
else
|
|
if view.y>0 then rot = 4 else rot = 5 end
|
|
end
|
|
|
|
self.label("face: " .. face ..", rotation: " .. surfdata[face].rotations[rot])
|
|
|
|
render_cube()
|
|
elseif event.x == p.x+n+2 then
|
|
self.label("yz2")
|
|
if math.abs(view.x)>viewlim then
|
|
yz2 = rotccw(yz2);
|
|
end
|
|
render_cube()
|
|
elseif event.z == p.z then
|
|
self.label("xy1")
|
|
if math.abs(view.z)>viewlim then
|
|
xy1 = rotcw(xy1);
|
|
end
|
|
render_cube()
|
|
elseif event.z == p.z+n+1 then
|
|
self.label("xy2")
|
|
if math.abs(view.z)>viewlim then
|
|
xy2 = rotccw(xy2);
|
|
end
|
|
render_cube()
|
|
elseif event.y == p.y+1 then
|
|
if math.abs(view.y)>viewlim then
|
|
xz1 = rotccw(xz1);
|
|
end
|
|
render_cube()
|
|
self.label("xz1")
|
|
elseif event.y == p.y+n+2 then
|
|
self.label("xz2")
|
|
if math.abs(view.y)>viewlim then
|
|
xz2 = rotcw(xz2);
|
|
end
|
|
render_cube()
|
|
end
|
|
--self.label(serialize(event))
|
|
end
|
|
|
|
-- ideas:
|
|
-- use whole full cube : array with n^3 elements, only border rendered.
|
|
-- PROS: easy to get slices then and rotate them! CONS: much more memory used for larger cubes
|
|
-- |