Newsgroup: it.comp.lang.javascript
Titolo: Trascinamento immagini

Ho appena dissezionato lo script qui in basso e lo trovo davvero
"intrigante".
Semplicità e solida determinazione.
Spero vi diverta come ha divertito me.
Ciao
    Luca
<HTML>
<HEAD>
<TITLE>Images Drag'n'Drop</TITLE>
<SCRIPT LANGUAGE="JScript">
<!--
var DragEl, tempval, HotEl;
if(document.all){
 document.onmousedown=DragStart;
 document.onmouseup=DragEnd;
 document.onmousemove=DoDrag;
}
function getRealPos(i,which) {
 iPos = 0
 while (i!=null) {
   iPos += i["offset" + which]
  i = i.offsetParent
 }
 return iPos
}
function DragStart(){
 el=event.srcElement;
 if(el.parentElement.className=='dnd'){
   DragEl=el;
   InitLeft=event.clientX;
   InitTop=event.clientY;
   InitElTop=getRealPos(el, "Top");
   InitElLeft=getRealPos(el, "Left");
   floater.style.pixelTop=InitElTop;
   floater.style.pixelLeft=InitElLeft;
   floater.children[0].src=el.src;
   el.src='blank.gif';
   floater.style.visibility='visible';
 }
}
function DoDrag(){
 if (DragEl) {
  floater.style.pixelLeft=event.clientX+InitElLeft-InitLeft;
  floater.style.pixelTop=event.clientY+InitElTop-InitTop;
  return false;
 }
}
function DragEnd() {
 if (!DragEl) return;
 X1= floater.style.pixelLeft;
 Y1= floater.style.pixelTop;
 MaxArea= 0;
 TargetElem= null;
 Targets= document.all;
 for (i=0; i<Targets.length; i++)
  if (Targets[i].className=="dnd") {
   X2=getRealPos(Targets[i].children[0],"Left");
   Y2=getRealPos(Targets[i].children[0],"Top");
   hOverlap=floater.offsetWidth-Math.abs(X2-X1);
   vOverlap=floater.offsetHeight-Math.abs(Y2-Y1);
   areaOverlap=((hOverlap>0) && (vOverlap>0)) ? hOverlap * vOverlap: 0;
   if (areaOverlap>MaxArea) {
    MaxArea=areaOverlap;
    TargetElem=Targets[i];
   }
  }
 floater.style.visibility='hidden';
 if (TargetElem) {
  // Swap
  DragEl.src=TargetElem.children[0].src;
  TargetElem.children[0].src=floater.children[0].src;
 }
 else {
  // Restore
  DragEl.src=floater.children[0].src;
  return;
 }
 DragEl=null;
}
//-->
</SCRIPT>
</HEAD>
<BODY>
<DIV CLASS="dnd">
1 : <IMG SRC="image1.jpg" WIDTH=100 HEIGHT=100 BORDER=0>
</DIV>
<DIV CLASS="dnd">
2 : <IMG SRC="image2.jpg" WIDTH=100 HEIGHT=100 BORDER=0>
</DIV>
<DIV CLASS="dnd">
3 : <IMG SRC="image3.jpg" WIDTH=100 HEIGHT=100 BORDER=0>
</DIV>
<DIV ID="floater" STYLE="visibility:hidden; position:absolute">
 <IMG SRC="blank.gif" WIDTH=100 HEIGHT=100 BORDER=0>
</DIV>
</BODY>
</HTML>

Bello! Ci si può inventare un puzzle! Che ne dici?


Solo se "Lo famo strano", pero.
Hai gia qualcosa in mente?

mmmm, non saprei...
Si può fare una bella paginetta che apre diversi puzzle a tema...
Così ognuno si fa quello che gli interessa di più!
Chissà quale sarà il più richiesto..... :-)


Per le immagini non ci sono problemi: ne faccio di graziose.
Dai un'occhiata al tutorial in allegato e prova ad immaginare che giochino
potrebbe venir fuori da un'eventuale mescolanza.
Ciao
    Luca

 file://-->


--------------------------Inizio Pagina Esempio--------------------------
<HTML>
<HEAD>
<TITLE>Mysterious Maze</TITLE>
<STYLE TYPE="TEXT/CSS">
<!--
BODY {font: 10pt Arial}
H1 {color:red}
#TMaze {font: 12pt Arial;font-weight: bold;}
.copy {font: 8pt Arial}
-->
</STYLE>
<SCRIPT LANGUAGE="JScript">
<!--
// Copyright 1999 Rajeev Hariharan. All Rights Reserved.
file://Constants
BOTTOMWALL = 0
RIGHTWALL = 1
VISITED = 2
var Maze=new Array();
var mRows=21;
var mCols=21;
visitedCells=0;
totalCells=0;
Score=0;
var UserRow=0;
var UserCol=0;
var GameOver=true;
Smarts=new Array(
"Huh! Don't think you're too smart.",
"I'm gonna give you a real toughie now.",
"That was good. You some kind of genius, or something?",
"Wow, I'm impressed!",
"Hey, gimme a break! Lose a game or two!",
"Well, seems like both of us got nothing better to do.",
"You could go get a life, or ",
"That was just a test. Now for the real thing."
)
file://*****************************************
file://****** Navigate - Go through Maze
file://*****************************************
function Navigate(){
if(GameOver){return;}
switch(event.keyCode){
case 37: file://Left
if(UserCol>0){
if(Maze[UserRow][UserCol-1][RIGHTWALL]==0)
{UserCol--;ChangeCell('L');}
}
event.cancelBubble=true;break;
case 38://Up
if(UserRow>0){
if(Maze[UserRow-1][UserCol][BOTTOMWALL]==0)
{UserRow--;ChangeCell('U');}
}
event.cancelBubble=true;break;
case 39://Right
if(UserCol<mCols-1){
if(Maze[UserRow][UserCol][RIGHTWALL]==0)
{UserCol++;ChangeCell('R');}
}
event.cancelBubble=true;break;
case 40://Down
if(UserRow<mRows-1){
if(Maze[UserRow][UserCol][BOTTOMWALL]==0)
{UserRow++;ChangeCell('D');}
}
event.cancelBubble=true;break;
}
}
function ChangeCell(fromDir){
if(TMaze.rows[UserRow].cells[UserCol].style.backgroundColor=='')
{TMaze.rows[UserRow].cells[UserCol].style.backgroundColor='gray'}
else{
switch(fromDir){
case 'L':
TMaze.rows[UserRow].cells[UserCol+1].style.backgroundColor='';break;
case 'R':
TMaze.rows[UserRow].cells[UserCol-1].style.backgroundColor='';break;
case 'U':
TMaze.rows[UserRow+1].cells[UserCol].style.backgroundColor='';break;
case 'D':
TMaze.rows[UserRow-1].cells[UserCol].style.backgroundColor='';break;
}
Score--;
ScoreDiv.innerHTML='SCORE : '+Score;
}
if((UserRow==mRows-1)&&(UserCol==mCols-1)){
Score+=5;
ScoreDiv.innerHTML='SCORE : '+Score;
if(Score>=20){
alert('Congrats, Master Mazer. You have finished the game');
GameOver=true;
StatDiv.innerHTML='GAME OVER';
Level.value=0;
}
else{
RandNo=(Math.random()*100)%(Smarts.length-1);
RandNo=Math.round(RandNo)
SmartStr=Smarts[RandNo];
alert(SmartStr+' Click on OK to continue');
StatDiv.innerHTML='GENERATING MAZE...';
MazeDiv.innerHTML='';
setTimeout("Loader()",10);
}
}
}
file://*****************************************
file://****** MakeMaze - Define Maze Structure
file://*****************************************
function MakeMaze(){
file://Set up the hedge array - initially all walls intact
for(i=0;i<mRows;i++){
Maze[i]=new Array();
for(j=0;j<mCols;j++){
Maze[i][j]=new Array();
Maze[i][j][BOTTOMWALL]=1;
Maze[i][j][RIGHTWALL]=1;
Maze[i][j][VISITED]=false;
}
}
file://Choose a random starting point
currCol=(Math.random()*100)%(mCols-1);
currCol=Math.round(currCol);
currRow=(Math.random()*100)%(mRows-1);
currRow=Math.round(currRow);
file://Recursively Remove Walls - Depth First Algorithm
visitedCells=0;
totalCells=mRows*mCols;
MakePath(currRow,currCol);
}//***END MakeMaze
file://*****************************************
file://****** MakePath - Recursive Maze Generation
file://*****************************************
function MakePath(R,C,D){
file://Knock out wall bxn this and previous cell
visitedCells++;
Maze[R][C][VISITED]=true;
if(D=="N"){Maze[R][C][BOTTOMWALL]=0;}
else
if(D=="S"){Maze[R-1][C][BOTTOMWALL]=0;}
else
if(D=="E"){Maze[R][C-1][RIGHTWALL]=0;}
else
if(D=="W"){Maze[R][C][RIGHTWALL]=0;}
file://build legal directions array
var directions=new Array();
if(R>0){directions[directions.length]="N"}
if(R<mRows-1){directions[directions.length]="S"}
if(C>0){directions[directions.length]="W"}
if(C<mCols-1){directions[directions.length]="E"}
file://Shuffle the directions array randomly
var DirLen=directions.length;
for(i=0;i<DirLen;i++){
j=(Math.random()*100)%(DirLen-1);
j=(Math.round(j));
temp=directions[i];
directions[i]=directions[j];
directions[j]=temp;
}
var d=0;
file://Call the function recursively
for(d=0;d<directions.length;d++){
if(directions[d]=="N"){if(Maze[R-1][C][VISITED]==false){MakePath(R-1,C,"N")}
}
else
if(directions[d]=="S"){if(Maze[R+1][C][VISITED]==false){MakePath(R+1,C,"S")}
}
else
if(directions[d]=="E"){if(Maze[R][C+1][VISITED]==false){MakePath(R,C+1,"E")}
}
else
if(directions[d]=="W"){if(Maze[R][C-1][VISITED]==false){MakePath(R,C-1,"W")}
}
else {alert('bug:you should never reach here')}
}
}//***END MakePath
file://*****************************************
file://****** DrawMaze - Draw Maze Table
file://*****************************************
function DrawMaze(){
HTMLStr = '<TABLE ID="TMaze" CELLSPACING=0 CELLPADDING=0>';
for(i=0;i<mRows;i++){
HTMLStr+='<TR>';
for(j=0;j<mCols;j++){
HTMLStr+='<TD ALIGN="CENTER" WIDTH=20 style="';
if(i==0){HTMLStr+='BORDER-TOP: 2px black solid;'}
if(i==mRows-1){HTMLStr+='BORDER-BOTTOM: 2px black solid;'}
if(j==0){HTMLStr+='BORDER-LEFT: 2px black solid;'}
if(j==mCols-1){HTMLStr+='BORDER-RIGHT: 2px black solid;'}
if(Maze[i][j][BOTTOMWALL]==1){HTMLStr+='BORDER-BOTTOM: 2px black solid;'}
if(Maze[i][j][RIGHTWALL]==1){HTMLStr+='BORDER-RIGHT: 2px black solid;'}
HTMLStr+='">';
if((i==0)&&(j==0)){HTMLStr+='S';}
else
if((i==mRows-1)&&(j==mCols-1)){HTMLStr+='E'}
else {HTMLStr+='&nbsp;'}
HTMLStr+='</TD>';
}
HTMLStr+='</TR>';
file://alert(HTMLStr);
}
HTMLStr+='</TABLE>';
MazeDiv.innerHTML=HTMLStr;
}//***END DrawMaze
function StartGame(){
if(Level.value==0){
alert('You must select a difficulty level!');
return;
}
Score=0;
switch(Level.value){
case '1':mRows=13;mCols=13;break;
case '2':mRows=17;mCols=17;break;
case '3':mRows=21;mCols=21;break;
}
StatDiv.innerHTML='GENERATING MAZE...';
ScoreDiv.innerHTML='SCORE : 0';
MazeDiv.innerHTML='';
setTimeout("Loader()",10);
}
function Loader(){
MakeMaze();
DrawMaze();
StatDiv.innerHTML='READY';
TMaze.rows[0].cells[0].style.backgroundColor='gray';
UserRow=0;
UserCol=0;
GameOver=false;
}
file://-->
document.onkeydown =Navigate
</SCRIPT>
<TABLE CELLPADDING=20 CELLSPACING=0 WIDTH="100%" BORDER=0 >
<TR>
<TD WIDTH="70%" ALIGN="CENTER">
<DIV ID="MazeDiv">
</DIV>
</TD>
<TD WIDTH="30%" ALIGN="CENTER" VALIGN="TOP">
<H1>Mysterious<BR>Maze</H1>
<SMALL>
Use the 4 arrow keys to navigate the maze from 'S' to 'E'.
You start off
with 0 points, and get 1 negative point everytime you
turn back. You gain 5 points everytime you solve a maze.
You win the game when you get 20 points. Mazes are generated
randomly, so you should never see the same maze twice.
Choose a difficulty level to start the game.
</SMALL>
<BR>
<DIV ID='ScoreDiv' style='background-color:gray;color:yellow'>
SCORE : 0
</DIV>
<BR>
<DIV ID='StatDiv' style='background-color:gray;color:yellow'>
WAITING...
</DIV>
<P>
<SELECT ID="Level">
<OPTION VALUE=0>(Select a difficulty level)</OPTION>
<OPTION VALUE=1>Kid Stuff - 13 x 13</OPTION>
<OPTION VALUE=2>Tough Guy - 17 x 17</OPTION>
<OPTION VALUE=3>Monster - 21 x 21</OPTION>
</SELECT>
<P>
<INPUT ID='Start' TYPE="button" VALUE="Start New Game"
ONCLICK="StartGame()">
</TD>
</TR>
</TABLE>
<TABLE WIDTH="100%">
<TR>
<TD WIDTH="50%" style='text-align: left'>
<P class=start>
<FONT FACE="geneva,arial" SIZE=-1>
<A HREF="page3.asp">Prev : Maze Generation</A>
</FONT>
</TD>
<TD WIDTH="50%" style='text-align: right'>
<P class=start>
<FONT FACE="geneva,arial" SIZE=-1>
<A HREF="backtrack.zip">Download Files</A>
</FONT>
</TD>
</TR>
</TABLE>
<DIV class='copy'>
Copyright &copy; 1999 Rajeev Hariharan. All Rights Reserved.
</DIV>
</BODY>
</HTML>
--------------------------Fine Pagina Esempio--------------------------

.
For other games and algorithms, do visit
the awesome <A HREF="ftp://x2ftp.oulu.fi:/pub/msdos/programming/">X2FTP
</A>game programming site.
<BR><BR>
<H3>Chapter 3 : Maze Generation</H3>
<P class=start>In this chapter, we will look at how the 'Mysterious Maze'
program
creates random mazes.  The class of mazes that the program generates
are referred to as <I>Perfect mazes</I>, because any two cells of the maze
are connected by a single unique path.  The program uses the top left
cell as the start and the bottom right cell as the finish, but any two
randomly selected cells could be chosen as start and finish. Perfect mazes
do not contain any <I>dead zones</I>, areas which are inaccessible by any
path.  They also differ from <I>Cyclic mazes</I>, in which more than one
solution
to the maze is possible.  A depth-first search algorithm is used to generate
the maze.
<H4>The Algorithm</H4>
<P class=start>The program, like most maze generators, starts off by
building a maze
with all the walls between the cells intact.  It then chooses a random
cell as it's starting point and proceeds to knock
down the walls using the following recursive algorithm.
<PRE>
Mark the current cell as 'Visited';
If the current cell has any neighbours which have not been visited
 {
  Choose one of the unvisited neighbours;
  Push the current cell on the stack;
  Knock down the wall between the current
                   cell and the chosen cell;
  Make the chosen cell the current cell;
  Recursively call this function;
 }
else
 {
  Pop the last current cell off the stack;
  Backtrack to the previous execution of this function;
 }
</PRE>
<P class=start>This algorithm is topology independent - it will work for
both 2D and 3D mazes, and the cells could be square, hexagonal,
or whatever shape you choose.  It does have a major problem
though, the mazes it generates are comparatively easy to
solve because it tends to produce long winding paths with
little or no branching.  Although there are many better
maze generating algorithms, this one was chosen because
of it's relative simplicity and it's use of backtracking.
<H4>The Data Structure</H4>
<P class=start>The maze is represented internally by the program as a
three-dimensional
array of cells, with the first and second dimensions being the Row and
Column of the cell respectively, and the third dimension representing the
attributes
of the cell. Each cell in the maze has 3 binary attributes, BOTTOMWALL,
which is 0 if the cell has no bottom wall and 1 if it does, RIGHTWALL,
which similarly represents whether the cell has a right wall or not,
and VISITED, which is used by the maze generation algorithm.
<P>
<CENTER>
<TABLE cellPadding=0 cellSpacing=0 style='border: 2px black solid'>
<TR>
<TD width=20 style='border-bottom: 2px black solid'>&nbsp;</TD>
<TD width=20 style='border-right: 2px black solid'>&nbsp;</TD>
<TD width=20>&nbsp;</TD>
</TR>
<TR>
<TD style='border-right: 2px black solid'>&nbsp;</TD>
<TD style='border-right: 2px black solid'>&nbsp;</TD>
<TD>&nbsp;</TD>
</TR>
<TR>
<TD>&nbsp;</TD>
<TD>&nbsp;</TD>
<TD>&nbsp;</TD>
</TR>
</TABLE>
</CENTER>
<P>
Thus, the maze above would be internally represented as -
<PRE>
Maze[0][0][RIGHTWALL]=0;    Maze[0][0][BOTTOMWALL]=1;
Maze[0][1][RIGHTWALL]=1;    Maze[0][1][BOTTOMWALL]=0;
Maze[0][2][RIGHTWALL]=1;    Maze[0][2][BOTTOMWALL]=0;
Maze[1][0][RIGHTWALL]=1;    Maze[1][0][BOTTOMWALL]=0;
Maze[1][1][RIGHTWALL]=1;    Maze[1][1][BOTTOMWALL]=0;
Maze[1][2][RIGHTWALL]=1;    Maze[1][2][BOTTOMWALL]=0;
Maze[2][0][RIGHTWALL]=0;    Maze[2][0][BOTTOMWALL]=1;
Maze[2][1][RIGHTWALL]=0;    Maze[2][1][BOTTOMWALL]=1;
Maze[2][2][RIGHTWALL]=1;    Maze[2][2][BOTTOMWALL]=1;
</PRE>
<H4>The Code</H4>
<P class=start>We will now look at the code that uses the depth-first
search algorithm on the maze data structure in order to
generate the maze.
<P>
The program calls the MakeMaze function to begin the maze
generation.  This function initializes the RIGHTWALL and
BOTTOMWALL attributes of all the cells to 1 (remember the
algorithm starts out with all walls intact). It also
initializes all VISITED attributes to false. It then
chooses a random cell as it's starting point, and proceeds
to call the MakePath function with the Row and Column of
this chosen cell as parameters.
<P>
MakePath is a backtracking function which takes 3 parameters,
the Row and the Column of the cell it is currently evaluating,
and the Direction that the previous execution of the algorithm
had taken.  It uses this Direction parameter to decide which
wall to break down.  Of course, when it is called initially
by the MakeMaze function, the Direction parameter is blank,
therefore no walls are broken. The first thing that
the MakePath function does is to mark the current cell as
visited (Maze[R][C][VISITED]=true).
<P>
The function then builds an array of the possible directions
it can take (N,S,E or W), goes through  these directions one
by one, calling itself with the Row and Column of the cell
in that direction, with the direction itself as the third
parameter. Of course, it will only go in that direction
if the cell in that direction has not already been visited.
<P>
A word of warning here, before we move on to see the
program itself. Variables within recursive procedures like
the MakePath function <B>must</B> be declared with the var
statement.  This is because undeclared variables do not
revert to their previous values when the procedure backtracks
to a previous execution.  To understand what I mean, open
the Mysterious Maze program in a text editor, and remove the
word <B>var</B> wherever it occurs in the function.  Then
try running the program.  You will find that the maze
will have only been partially generated, and that the
MakePath function stopped executing the first time it
tried to backtrack.  On to the program now, and have fun.
<BR><BR>
<P align=right CLASS=copyright>
<FONT FACE=verdana STYLE='font-size: 8pt' SIZE=-2>
&copy; 1997-99 InsideDHTML.com, LLC. All rights reserved.
</FONT>
</P>
</BODY>
</HTML>
--------------------------Fine Tutorial--------------------------
Buon divertimento.
Ciao
    Luca