Difference between revisions of "Sliding Puzzle (CMS)"

From The Official Visionaire Studio: Adventure Game Engine Wiki
m
m
 
(20 intermediate revisions by the same user not shown)
Line 6: Line 6:
 
|}
 
|}
  
This script is used to generate & control a randomized sliding puzzle consisting of a 3x3 grid. ''Visionaire Studio 4.1+ is required to run this script''.
+
This script is used to generate & control sliding puzzle consisting of a 3x3 grid. ''Visionaire Studio 5.1.9.1 + is required to run this script''. This script is just a basic example of a sliding puzzle, you should be able to easily modify it for any grid size. It should also be possible to generate from a randomized tile order providing you provide a table of known working tile positions. You could also add a move counter, or even limit the amount of moves that can be made if you want to make the puzzle harder.
 +
 
 +
Check out this website [https://www.cs.princeton.edu/courses/archive/spring20/cos226/assignments/8puzzle/specification.php here], for more in depth information on sliding puzzle design.
  
 
== Instructions ==
 
== Instructions ==
 
1. Add the [[#Main_Script|main script]] to the Visionaire Studio Script Editor & set the script as a definition script.<br/>
 
1. Add the [[#Main_Script|main script]] to the Visionaire Studio Script Editor & set the script as a definition script.<br/>
 
2a. First thing you should do is update the t[1] to t[9] tables with the correct x, y positions for where each tile should be placed (top left pixel).
 
2a. First thing you should do is update the t[1] to t[9] tables with the correct x, y positions for where each tile should be placed (top left pixel).
<syntaxhighlight>
+
<syntaxhighlight lang="lua">
  t[1] = { .. x = 96, y = 77
+
  t[1] = { .. x = 288, y = 221
 
</syntaxhighlight>
 
</syntaxhighlight>
2b. Next you should define where each tile is allowed to slide to in the '''move''' section of each of the tables. See the diagram below for an explanation of how I determined which tiles can move where.<br/>
+
2b. The second thing you need to do is specify the initial order you want to set for the tiles, but be careful as certain tile orders can make the sliding puzzle unsolvable.
 +
<syntaxhighlight lang="lua">
 +
t[1] = { .. name = nil
 +
t[2] = { .. name = "anim_p1"
 +
t[3] = { .. name = "anim_p3"
 +
</syntaxhighlight>
 +
2c. Next you should define where each tile is allowed to slide to in the '''move''' section of each of the tables. See the diagram below for an explanation of how I determined which tiles can move where.<br/>
 
{| style="width:100%;"
 
{| style="width:100%;"
 
|-
 
|-
| <syntaxhighlight style="height:100px;">
+
| <syntaxhighlight style="height:200px;" lang="lua">
t[1] = { .. move = {2,4}
+
t[1] = { .. move = {2,4} -- grid position 1
</syntaxhighlight>
+
t[2] = { .. move = {1,3,5} } -- grid position 2
| style="width:100px;padding-left:5px;" | [[File:sliding_puzzle_grid.png|center|x100px]]
+
t[3] = { .. move = {2,6} } -- grid position 3
|}
+
t[4] = { .. move = {1,5,7} } -- grid position 4
3. Next you need to edit the animation names inside of the '''n''' table. ''All names should be the same but with a prefix number on the end. Any changes you make here will have to be changed inside of the '''puzzleState''' function.''
+
t[5] = { .. move = {2,4,6,8} } -- grid position 5
<syntaxhighlight>
+
t[6] = { .. move = {3,5,9} } -- grid position 6
n = { "anim_p1", "anim_p2", "anim_p3", "anim_p4", "anim_p5", "anim_p6", "anim_p7", "anim_p8" }
+
t[7] = { .. move = {4,8} } -- grid position 7
 +
t[8] = { .. move = {5,7,9} } -- grid position 8
 +
t[9] = { .. move = {6,8} } -- grid position 9
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
| style="width:200px;padding-left:5px;" | [[File:sliding_puzzle_grid.png|center|x200px]]
 +
|}<br/>
 +
3. Create a condition called '''puzzle_solved''', this will be used to determine if puzzle has been solved & whether or not you can move the tiles.<br/>
 
4. To check if a tile slot is empty or whether tile can be moved you should create an ''execute a script action'' inside of a ''left click (immediate)'' action containing...
 
4. To check if a tile slot is empty or whether tile can be moved you should create an ''execute a script action'' inside of a ''left click (immediate)'' action containing...
<syntaxhighlight>
+
<syntaxhighlight lang="lua">
 
canMove(i) -- replace i with the tile slot number.
 
canMove(i) -- replace i with the tile slot number.
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
5. Finally you should create a ''called by other action'' inside of the scene actions of the scene where the puzzle is located. Name it '''puzzle_solved''' & inside of this action add the actions that should be executed when the puzzle is solved, such as changing the '''puzzle_solved''' condition to true & playing a sound to indicate the puzzle was solved successfully.
  
 
== Main Script ==
 
== Main Script ==
<syntaxhighlight>
+
<syntaxhighlight lang="lua">
 
--[[
 
--[[
Sliding Puzzle (3x3) [v1] (13/11/2014)
+
Sliding Puzzle (3x3) [v4] (28/04/2022)
 
Written by AFRLme [Lee Clarke]
 
Written by AFRLme [Lee Clarke]
 
-- + --
 
-- + --
alternatingfrequencies@hotmail.com | skype @ AFRLme
+
afrlme@outlook.com | https://afrl.me | patreon.com/AFRLme | ko-fi.com/afrlme
 
-- + --
 
-- + --
 
This script is donation optional. In game credit is non-negotiable.
 
This script is donation optional. In game credit is non-negotiable.
Line 45: Line 59:
  
 
-- * tables * --
 
-- * tables * --
local n, t = {}, {} -- empty tables (see below)
+
local t = {} -- init local table for storing tile coordinates, names, & move positions
  
-- * function for randomly generating tile positions * --
+
-- * function for initializing tiles * --
function initPuzzle(c)
+
function initPuzzle()
 
  -- + initialize the grid properties + --
 
  -- + initialize the grid properties + --
 
  t[1] = { x = 96, y = 77, name = nil, move = {2,4} }
 
  t[1] = { x = 96, y = 77, name = nil, move = {2,4} }
  t[2] = { x = 246, y = 77, name = nil, move = {1,3,5} }
+
  t[2] = { x = 246, y = 77, name = "anim_p1", move = {1,3,5} }
  t[3] = { x = 396, y = 77, name = nil, move = {2,6} }
+
  t[3] = { x = 396, y = 77, name = "anim_p3", move = {2,6} }
  t[4] = { x = 96, y = 187, name = nil, move = {1,5,7} }
+
  t[4] = { x = 96, y = 187, name = "anim_p4", move = {1,5,7} }
  t[5] = { x = 246, y = 187, name = nil, move = {2,4,6,8} }
+
  t[5] = { x = 246, y = 187, name = "anim_p2", move = {2,4,6,8} }
  t[6] = { x = 396, y = 187, name = nil, move = {3,5,9} }
+
  t[6] = { x = 396, y = 187, name = "anim_p5", move = {3,5,9} }
  t[7] = { x = 96, y = 297, name = nil, move = {4,8} }
+
  t[7] = { x = 96, y = 297, name = "anim_p7", move = {4,8} }
  t[8] = { x = 246, y = 297, name = nil, move = {5,7,9} }
+
  t[8] = { x = 246, y = 297, name = "anim_p8", move = {5,7,9} }
  t[9] = { x = 396, y = 297, name = nil, move = {6,8} }
+
  t[9] = { x = 396, y = 297, name = "anim_p6", move = {6,8} }
  -- + initialize the tile names (1-8) + --
+
  -- + move tiles to correct position if in wrong position + --
n = { "anim_p1", "anim_p2", "anim_p3", "anim_p4", "anim_p5", "anim_p6", "anim_p7", "anim_p8" }
+
  for i = 2, 9 do ActiveAnimations[ t[i].name ]:to(0, { CurrentPosition = { x = t[i].x, y = t[i].y } }) end
-- + loops which are used for randomly generating the tile order & names etc + --
 
  for i = 1, (#n * #n) do
 
  c = n[8]; table.remove(n, 8); table.insert( n, math.random(8), c ) -- shuffle the tile names
 
  if i == (#n * #n) then
 
  for b = 1, 8 do t[b].name = n[b] end -- update "t" table names with shuffled "n" table names
 
  for a = 1, 8 do startObjectTween(ActiveAnimations[ t[a].name ], VAnimationCurrentPosition, ActiveAnimations[ t[a].name ].AnimationCurrentPosition, {x = t[a].x, y = t[a].y}, 200, easeLinearOut) end
 
  end
 
end
 
 
end
 
end
  
Line 75: Line 81:
 
  for i = 1, 8 do
 
  for i = 1, 8 do
 
   if t[i].name == "anim_p"..i then v = v + 1 end
 
   if t[i].name == "anim_p"..i then v = v + 1 end
   if i == 8 and v == 8 then Objects["obj_solved"]:to(1000, {ObjectVisibility = 100}, easeQuintOut); Conditions["puzzle_solved"].ConditionValue = true end
+
   if i == 8 and v == 8 then startAction( game.CurrentScene.Actions["puzzle_solved"] ) end
 
  end
 
  end
 
end
 
end
Line 81: Line 87:
 
-- * function for updating tile positions * --
 
-- * function for updating tile positions * --
 
function canMove(v)
 
function canMove(v)
   for i = 1, table.maxn(t[v]["move"]) do
+
   for i = 1, #t[v]["move"] do
   if t[ t[v]["move"][i] ].name == nil and Conditions["puzzle_solved"].ConditionValue == false then moveTile(v, t[v]["move"][i], 200, easeLinearOut); break end
+
   if t[ t[v]["move"][i] ].name == nil and not Conditions["puzzle_solved"].Value then moveTile(v, t[v]["move"][i], 200, easeLinearOut); break end
 
   end
 
   end
 
end
 
end
Line 88: Line 94:
 
-- * function that is used to move the animation from one position to another with delay & easing * --
 
-- * function that is used to move the animation from one position to another with delay & easing * --
 
function moveTile(a, b, delay, easing)
 
function moveTile(a, b, delay, easing)
  startObjectTween(ActiveAnimations[ t[a].name ], VAnimationCurrentPosition, ActiveAnimations[ t[a].name ].AnimationCurrentPosition, {x = t[b].x, y = t[b].y}, delay, easing)
+
  ActiveAnimations[ t[a].name ]:to(delay, { CurrentPosition = {x = t[b].x, y = t[b].y} }, easing)
 
  t[b].name = t[a].name; t[a].name = nil; puzzleState(0) -- update tile position names & check puzzle state
 
  t[b].name = t[a].name; t[a].name = nil; puzzleState(0) -- update tile position names & check puzzle state
 
end
 
end
Line 98: Line 104:
 
! style="text-align:left" | Name !! style="text-align:left" | Description
 
! style="text-align:left" | Name !! style="text-align:left" | Description
 
|-
 
|-
| [[:Media:sliding_puzzle.zip|sliding_puzzle.zip]] || A working example of the script in action. ''Visionaire Studio 4.1+'' required to run the included .ved file.
+
| [[:Media:3x3_sliding_puzzle_(v4).zip|3x3_sliding_puzzle_(v4).zip]] || A working example of the script in action. ''Visionaire Studio 5.1.9.1 +'' required to run the included .ved file.
 
|}{{toc}}
 
|}{{toc}}

Latest revision as of 18:03, 15 May 2023

Name Type By
Sliding Puzzle (3x3) Definition AFRLme

This script is used to generate & control sliding puzzle consisting of a 3x3 grid. Visionaire Studio 5.1.9.1 + is required to run this script. This script is just a basic example of a sliding puzzle, you should be able to easily modify it for any grid size. It should also be possible to generate from a randomized tile order providing you provide a table of known working tile positions. You could also add a move counter, or even limit the amount of moves that can be made if you want to make the puzzle harder.

Check out this website here, for more in depth information on sliding puzzle design.

Instructions

1. Add the main script to the Visionaire Studio Script Editor & set the script as a definition script.
2a. First thing you should do is update the t[1] to t[9] tables with the correct x, y positions for where each tile should be placed (top left pixel).

 t[1] = { .. x = 288, y = 221

2b. The second thing you need to do is specify the initial order you want to set for the tiles, but be careful as certain tile orders can make the sliding puzzle unsolvable.

 t[1] = { .. name = nil
 t[2] = { .. name = "anim_p1"
 t[3] = { .. name = "anim_p3"

2c. Next you should define where each tile is allowed to slide to in the move section of each of the tables. See the diagram below for an explanation of how I determined which tiles can move where.

t[1] = { .. move = {2,4} -- grid position 1
t[2] = { .. move = {1,3,5} } -- grid position 2
t[3] = { .. move = {2,6} } -- grid position 3
t[4] = { .. move = {1,5,7} } -- grid position 4
t[5] = { .. move = {2,4,6,8} } -- grid position 5
t[6] = { .. move = {3,5,9} } -- grid position 6
t[7] = { .. move = {4,8} } -- grid position 7
t[8] = { .. move = {5,7,9} } -- grid position 8
t[9] = { .. move = {6,8} } -- grid position 9
Sliding puzzle grid.png

3. Create a condition called puzzle_solved, this will be used to determine if puzzle has been solved & whether or not you can move the tiles.
4. To check if a tile slot is empty or whether tile can be moved you should create an execute a script action inside of a left click (immediate) action containing...

canMove(i) -- replace i with the tile slot number.

5. Finally you should create a called by other action inside of the scene actions of the scene where the puzzle is located. Name it puzzle_solved & inside of this action add the actions that should be executed when the puzzle is solved, such as changing the puzzle_solved condition to true & playing a sound to indicate the puzzle was solved successfully.

Main Script

--[[
Sliding Puzzle (3x3) [v4] (28/04/2022)
Written by AFRLme [Lee Clarke]
-- + --
afrlme@outlook.com | https://afrl.me | patreon.com/AFRLme | ko-fi.com/afrlme
-- + --
This script is donation optional. In game credit is non-negotiable.
You are free to: ¹ use it in your game(s). ² modify the script.
Do not remove - or edit - this comment block.
--]]

-- * tables * --
local t = {} -- init local table for storing tile coordinates, names, & move positions

-- * function for initializing tiles * --
function initPuzzle()
 -- + initialize the grid properties + --
 t[1] = { x = 96, y = 77, name = nil, move = {2,4} }
 t[2] = { x = 246, y = 77, name = "anim_p1", move = {1,3,5} }
 t[3] = { x = 396, y = 77, name = "anim_p3", move = {2,6} }
 t[4] = { x = 96, y = 187, name = "anim_p4", move = {1,5,7} }
 t[5] = { x = 246, y = 187, name = "anim_p2", move = {2,4,6,8} }
 t[6] = { x = 396, y = 187, name = "anim_p5", move = {3,5,9} }
 t[7] = { x = 96, y = 297, name = "anim_p7", move = {4,8} }
 t[8] = { x = 246, y = 297, name = "anim_p8", move = {5,7,9} }
 t[9] = { x = 396, y = 297, name = "anim_p6", move = {6,8} }
 -- + move tiles to correct position if in wrong position + --
 for i = 2, 9 do ActiveAnimations[ t[i].name ]:to(0, { CurrentPosition = { x = t[i].x, y = t[i].y } }) end
end

-- * function used to determine if player wins * --
function puzzleState(v)
 for i = 1, 8 do
  if t[i].name == "anim_p"..i then v = v + 1 end
  if i == 8 and v == 8 then startAction( game.CurrentScene.Actions["puzzle_solved"] ) end
 end
end

-- * function for updating tile positions * --
function canMove(v)
  for i = 1, #t[v]["move"] do
   if t[ t[v]["move"][i] ].name == nil and not Conditions["puzzle_solved"].Value then moveTile(v, t[v]["move"][i], 200, easeLinearOut); break end
  end
end

-- * function that is used to move the animation from one position to another with delay & easing * --
function moveTile(a, b, delay, easing)
 ActiveAnimations[ t[a].name ]:to(delay, { CurrentPosition = {x = t[b].x, y = t[b].y} }, easing)
 t[b].name = t[a].name; t[a].name = nil; puzzleState(0) -- update tile position names & check puzzle state
end

Resources

Name Description
3x3_sliding_puzzle_(v4).zip A working example of the script in action. Visionaire Studio 5.1.9.1 + required to run the included .ved file.