|
@@ -1,104 +1,22 @@
|
|
-function inicio (QntityDisks){
|
|
|
|
- nDisks=QntityDisks;
|
|
|
|
- optimalSolution= Math.pow(2,QntityDisks)-1;
|
|
|
|
- var x = 0;
|
|
|
|
- var y = 549.5;
|
|
|
|
- var w = 330;
|
|
|
|
- startOfMove=Date.now();
|
|
|
|
- for (var i = 0; i < QntityDisks; i++) {
|
|
|
|
- var disk = new Disk(x,y,w,40,colors[i]);
|
|
|
|
- towerA.push(disk);
|
|
|
|
- x+=20; //moves to the right
|
|
|
|
- y-=41; //moves up, +1 to separate disks
|
|
|
|
- w-=40; //reduces disk width
|
|
|
|
- }
|
|
|
|
- drawScene();
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-class Disk{
|
|
|
|
- constructor(x,y,w,h,fill){
|
|
|
|
- this.x=x;
|
|
|
|
- this.y=y;
|
|
|
|
- this.w=w;
|
|
|
|
- this.h=h;
|
|
|
|
- this.fill=fill;
|
|
|
|
- }
|
|
|
|
- draw(){//(ctx, x, y, width, height, radius, fill, stroke)
|
|
|
|
- context.fillStyle = this.fill;
|
|
|
|
- context.strokeStyle = "black";
|
|
|
|
- roundRect(context, this.x, this.y, this.w, this.h, 20, 20, true);
|
|
|
|
- }
|
|
|
|
- clear(){
|
|
|
|
- context.clearRect(this.x, this.y, this.w, this.h);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-function reinicio (){
|
|
|
|
- towerA.splice(0,towerA.length);
|
|
|
|
- towerB.splice(0,towerB.length);
|
|
|
|
- towerC.splice(0,towerC.length);
|
|
|
|
- moves.splice(0,moves.length);
|
|
|
|
- nMovements=0;
|
|
|
|
- idF = " ";
|
|
|
|
- idT=" ";
|
|
|
|
- toMove=null;
|
|
|
|
- inicio(nDisks);
|
|
|
|
-}
|
|
|
|
-function drawTowers (){
|
|
|
|
- context.beginPath();
|
|
|
|
- context.fillStyle = pat;
|
|
|
|
- <!-- torre 1 -->
|
|
|
|
- roundRect(context, 160, 260, 20, 340, 5, pat, false);//ctx, x, y, largura, altura, radius, fill, stroke(T/F)
|
|
|
|
-
|
|
|
|
- <!--Base t1-->
|
|
|
|
- roundRect(context, 0, 590, 330, 20, 5, pat, false);
|
|
|
|
-
|
|
|
|
- <!-- torre 2 -->
|
|
|
|
- roundRect(context, 505, 260, 20, 340, 5, pat, false);
|
|
|
|
-
|
|
|
|
- <!--Base t2-->
|
|
|
|
- roundRect(context, 345, 590, 330, 20, 5, pat, false);
|
|
|
|
-
|
|
|
|
- <!-- torre 3 -->
|
|
|
|
- roundRect(context, 850, 260, 20, 340, 5, pat, false);
|
|
|
|
-
|
|
|
|
- <!--Base t3-->
|
|
|
|
- roundRect(context, 690, 590, 330, 20, 5, pat, false);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function drawDisks (){
|
|
|
|
- for(i=0; i<towerA.length; i++){
|
|
|
|
- towerA[i].draw();
|
|
|
|
- }
|
|
|
|
- for(i=0; i<towerB.length; i++){
|
|
|
|
- towerB[i].draw();
|
|
|
|
- }
|
|
|
|
- for(i=0; i<towerC.length; i++){
|
|
|
|
- towerC[i].draw();
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function drawScene (){
|
|
|
|
- context.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
- drawTowers();
|
|
|
|
- drawDisks();
|
|
|
|
- drawFromTo();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function buttonClick (id){
|
|
|
|
- if(toMove == null && getTower(id).length>0){
|
|
|
|
- toMove = id;
|
|
|
|
- idF= String.fromCharCode(65+id);
|
|
|
|
- idT= " ";
|
|
|
|
- drawScene();
|
|
|
|
-
|
|
|
|
- } else if(toMove != null && toMove != id){
|
|
|
|
- idT = String.fromCharCode(65+id);
|
|
|
|
- moveDisk(toMove, id);
|
|
|
|
- toMove=null;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
|
|
+var isMoving = false, diskOrigin, diskDestiny, movements;
|
|
|
|
+var nWrongMoves = 0;
|
|
|
|
+var moves = [], totalMoves = []; //vector to save movements
|
|
|
|
+var acertou=0;
|
|
|
|
+var optimalSolution;
|
|
|
|
+var redo = false, undo = false;
|
|
|
|
+var textDict = {disk0: "stroked0",
|
|
|
|
+ disk1: "stroked1",
|
|
|
|
+ disk2: "stroked2",
|
|
|
|
+ disk3: "stroked3",
|
|
|
|
+ disk4: "stroked4",
|
|
|
|
+ disk5: "stroked5",
|
|
|
|
+ stroked0: "disk0",
|
|
|
|
+ stroked1: "disk1",
|
|
|
|
+ stroked2: "disk2",
|
|
|
|
+ stroked3: "disk3",
|
|
|
|
+ stroked4: "disk4",
|
|
|
|
+ stroked5: "disk5"}
|
|
|
|
+//To know which tower was selected
|
|
function getTower (id){
|
|
function getTower (id){
|
|
switch(id){
|
|
switch(id){
|
|
case 0:
|
|
case 0:
|
|
@@ -110,112 +28,163 @@ function getTower (id){
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function drawFromTo (){
|
|
|
|
- context.font = "50px Arial";
|
|
|
|
- context.fillStyle = "black";
|
|
|
|
- context.fillText("Move from "+idF+" to "+idT, 50, 50);
|
|
|
|
- context.fillText("Movements: "+nTotalMovements, 50, 100);
|
|
|
|
|
|
+function selectA (){
|
|
|
|
+ if (!isMoving){
|
|
|
|
+ if(towerA.length>0){
|
|
|
|
+ diskOrigin = 0;
|
|
|
|
+ isMoving = true;
|
|
|
|
+ towerA[towerA.length-1].setTexture(textDict[towerA[towerA.length-1].texture.key]);
|
|
|
|
+ }
|
|
|
|
+ } else{
|
|
|
|
+ if(diskOrigin!=0){
|
|
|
|
+ moveFromTo(diskOrigin, 0);
|
|
|
|
+ } else{
|
|
|
|
+ towerA[towerA.length-1].setTexture(textDict[towerA[towerA.length-1].texture.key]);
|
|
|
|
+ isMoving=false;
|
|
|
|
+ nMoves.text++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
-function moveDisk (origin, destiny){
|
|
|
|
- var originTower = getTower(origin), destinyTower = getTower(destiny), topDiskOrigin, topDiskDestiny;
|
|
|
|
- moveTime = Math.floor( (Date.now()- startOfMove) /1000);
|
|
|
|
- startOfMove = Date.now();//update start of movement
|
|
|
|
- if(nMovements< moves.length){
|
|
|
|
- moves.splice(nMovements, moves.length- nMovements);
|
|
|
|
- }
|
|
|
|
- moves.push(origin+" "+destiny);
|
|
|
|
-
|
|
|
|
- //console.log(moves);
|
|
|
|
- nMovements++;
|
|
|
|
- finishMove(origin, destiny);
|
|
|
|
- if(towerC.length == nDisks && nDisks!=0){
|
|
|
|
- acertou=1;
|
|
|
|
- totalTime= Date.now() - start;
|
|
|
|
- if(nTotalMovements==optimalSolution){
|
|
|
|
- alert("You Won in the least amount of movements!!!\nCongratulations!!!");
|
|
|
|
- }else{
|
|
|
|
- alert("You Won!!!\nCongratulations!!");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+function selectB (){
|
|
|
|
+ if (!isMoving){
|
|
|
|
+ if(towerB.length>0){
|
|
|
|
+ diskOrigin = 1;
|
|
|
|
+ isMoving = true;
|
|
|
|
+ towerB[towerB.length-1].setTexture(textDict[towerB[towerB.length-1].texture.key]);
|
|
|
|
+ }
|
|
|
|
+ } else{
|
|
|
|
+ if(diskOrigin!=1){
|
|
|
|
+ moveFromTo(diskOrigin, 1);
|
|
|
|
+ } else{
|
|
|
|
+ towerB[towerB.length-1].setTexture(textDict[towerB[towerB.length-1].texture.key]);
|
|
|
|
+ isMoving=false;
|
|
|
|
+ nMoves.text++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
|
|
|
|
- if (typeof stroke == "undefined" ) {
|
|
|
|
- stroke = true;
|
|
|
|
- }
|
|
|
|
- if (typeof radius === "undefined") {
|
|
|
|
- radius = 5;
|
|
|
|
|
|
+function selectC (){
|
|
|
|
+ if (!isMoving){
|
|
|
|
+ if(towerC.length>0){
|
|
|
|
+ diskOrigin = 2;
|
|
|
|
+ isMoving = true;
|
|
|
|
+ towerC[towerC.length-1].setTexture(textDict[towerC[towerC.length-1].texture.key]); //levantar o disco
|
|
|
|
+ }
|
|
|
|
+ } else{
|
|
|
|
+ if(diskOrigin!=2){
|
|
|
|
+ moveFromTo(diskOrigin, 2);
|
|
|
|
+ } else{
|
|
|
|
+ towerC[towerC.length-1].setTexture(textDict[towerC[towerC.length-1].texture.key]);
|
|
|
|
+ isMoving=false;
|
|
|
|
+ nMoves.text++;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- ctx.beginPath();
|
|
|
|
- ctx.moveTo(x + radius, y);
|
|
|
|
- ctx.lineTo(x + width - radius, y);
|
|
|
|
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
|
|
|
- ctx.lineTo(x + width, y + height - radius);
|
|
|
|
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
|
|
|
- ctx.lineTo(x + radius, y + height);
|
|
|
|
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
|
|
|
- ctx.lineTo(x, y + radius);
|
|
|
|
- ctx.quadraticCurveTo(x, y, x + radius, y);
|
|
|
|
- ctx.closePath();
|
|
|
|
- if (stroke) {
|
|
|
|
- ctx.stroke();
|
|
|
|
- }
|
|
|
|
- if (fill) {
|
|
|
|
- ctx.fill();
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-function undo(){
|
|
|
|
- if(nMovements>0){
|
|
|
|
- var res = moves[nMovements-1].split(" ");
|
|
|
|
- nMovements--;
|
|
|
|
- if (nMovements>1){
|
|
|
|
- var res2 = moves[nMovements-2].split(" ");
|
|
|
|
- idf = res2[0];
|
|
|
|
- idt = res2[1];
|
|
|
|
- } else{
|
|
|
|
- idf = "";
|
|
|
|
- idt = "";
|
|
|
|
|
|
+
|
|
|
|
+function moveFromTo (origin, destiny){
|
|
|
|
+ var originTower = getTower(origin), destinyTower = getTower(destiny);
|
|
|
|
+ var topDiskOrigin = originTower[originTower.length-1], topDiskDestiny;
|
|
|
|
+ if (!undo && !redo) {
|
|
|
|
+ topDiskOrigin.setTexture(textDict[topDiskOrigin.texture.key]);
|
|
|
|
+ }
|
|
|
|
+ if (destinyTower.length>0){
|
|
|
|
+ //movement to a tower with a disk in it
|
|
|
|
+ topDiskDestiny = destinyTower[destinyTower.length-1];
|
|
|
|
+ if(topDiskOrigin.displayWidth<=topDiskDestiny.displayWidth){
|
|
|
|
+ topDiskOrigin.x += 435*(destiny-origin);
|
|
|
|
+ topDiskOrigin.y += 28*(originTower.length-destinyTower.length-1);
|
|
|
|
+ originTower.pop();
|
|
|
|
+ destinyTower.push(topDiskOrigin);
|
|
|
|
+ //control variables
|
|
|
|
+ nMoves.text++;
|
|
|
|
+ totalMoves.push(origin+" "+destiny);
|
|
|
|
+ if (!undo){
|
|
|
|
+ //if it is either a redo or a new move we must add new moves to the current sequence for possible 'undos'
|
|
|
|
+ if(!redo){
|
|
|
|
+ //if it is a new move, we clean all possible "redos"
|
|
|
|
+ moves.splice(nCurrentMoves, moves.length- nCurrentMoves);
|
|
|
|
+ moves.push(origin+" "+destiny);
|
|
|
|
+ }
|
|
|
|
+ nCurrentMoves++;
|
|
|
|
+ undoButton.setInteractive({useHandCursor: true});
|
|
|
|
+ undoButton.setTexture('undo');
|
|
|
|
+ if(nCurrentMoves==moves.length){
|
|
|
|
+ redoButton.disableInteractive();
|
|
|
|
+ redoButton.setTexture('redoDisabled');
|
|
|
|
+ }
|
|
|
|
+ redo=false;
|
|
|
|
+ }else{
|
|
|
|
+ nCurrentMoves--;
|
|
|
|
+ undo=false;
|
|
|
|
+ redoButton.setInteractive({useHandCursor: true});
|
|
|
|
+ redoButton.setTexture('redo');
|
|
|
|
+ if(nCurrentMoves==0){
|
|
|
|
+ undoButton.disableInteractive();
|
|
|
|
+ undoButton.setTexture('undoDisabled');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ //move to a tower without a disk in it
|
|
|
|
+ topDiskOrigin.x += 435*(destiny-origin);
|
|
|
|
+ topDiskOrigin.y += 28*(originTower.length-destinyTower.length-1);
|
|
|
|
+ originTower.pop();
|
|
|
|
+ destinyTower.push(topDiskOrigin);
|
|
|
|
+ //control variables
|
|
|
|
+ nMoves.text++;
|
|
|
|
+ totalMoves.push(origin+" "+destiny);
|
|
|
|
+ if (!undo){
|
|
|
|
+ //if it is either a redo or a new move we must add new moves to the current sequence for possible 'undos'
|
|
|
|
+ if(!redo){
|
|
|
|
+ //if it is a new move, we clean all possible "redos" and add the new move to the list
|
|
|
|
+ moves.splice(nCurrentMoves, moves.length- nCurrentMoves);
|
|
|
|
+ moves.push(origin+" "+destiny);
|
|
|
|
+ }
|
|
|
|
+ nCurrentMoves++;
|
|
|
|
+ if(nCurrentMoves==moves.length){
|
|
|
|
+ redoButton.disableInteractive();
|
|
|
|
+ redoButton.setTexture('redoDisabled');
|
|
|
|
+ }
|
|
|
|
+ undoButton.setInteractive({useHandCursor: true});
|
|
|
|
+ undoButton.setTexture('undo');
|
|
|
|
+ redo=false;
|
|
|
|
+ }else{
|
|
|
|
+ nCurrentMoves--;
|
|
|
|
+ undo=false;
|
|
|
|
+ redoButton.setInteractive({useHandCursor: true});
|
|
|
|
+ redoButton.setTexture('redo');
|
|
|
|
+ if(nCurrentMoves==0){
|
|
|
|
+ undoButton.disableInteractive();
|
|
|
|
+ undoButton.setTexture('undoDisabled');
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- finishMove(parseInt(res[1]), parseInt(res[0]));
|
|
|
|
|
|
+ }
|
|
|
|
+ movements+=origin+" "+destiny+"\n"
|
|
|
|
+ isMoving=false;
|
|
|
|
+ if (towerC.length == diskQntity){
|
|
|
|
+ gameWonMsg.text = "Você terminou de mover a torre!!! Parabéns!!"
|
|
|
|
+ }else{
|
|
|
|
+ gameWonMsg.text ='';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function redo(){
|
|
|
|
- if (nMovements < moves.length){
|
|
|
|
- var res = moves[nMovements].split(" ");
|
|
|
|
- nMovements++;
|
|
|
|
- finishMove(parseInt(res[0]), parseInt(res[1]));
|
|
|
|
|
|
+function redoMove(){
|
|
|
|
+ if (nCurrentMoves < moves.length){
|
|
|
|
+ var res = moves[nCurrentMoves].split(" ");
|
|
|
|
+ redo=true;
|
|
|
|
+ moveFromTo(parseInt(res[0]), parseInt(res[1]));
|
|
|
|
+ if(nCurrentMoves==moves.length) redoButton.setInteractive({useHandCursor: false});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function finishMove(origin, destiny){
|
|
|
|
- nTotalMovements++;
|
|
|
|
- var originTower = getTower(origin), destinyTower = getTower(destiny), topDiskOrigin, topDiskDestiny;
|
|
|
|
- topDiskOrigin = originTower[originTower.length-1];
|
|
|
|
- totalMoves.push(origin+" "+destiny+" "+moveTime);
|
|
|
|
- if(destinyTower.length>0){
|
|
|
|
- topDiskDestiny = destinyTower[destinyTower.length-1];
|
|
|
|
- if(topDiskOrigin.w<topDiskDestiny.w){
|
|
|
|
- topDiskOrigin.x += 345*(destiny-origin);
|
|
|
|
- topDiskOrigin.y += 42*(originTower.length-destinyTower.length-1);
|
|
|
|
- originTower.pop();
|
|
|
|
- destinyTower.push(topDiskOrigin);
|
|
|
|
- drawScene();
|
|
|
|
- } else{
|
|
|
|
- nWrongMoves++;
|
|
|
|
- alert("Movimento Inválido");
|
|
|
|
- idF =" ";
|
|
|
|
- idT =" ";
|
|
|
|
- drawScene();
|
|
|
|
- }
|
|
|
|
- }else{
|
|
|
|
- topDiskOrigin.x += 345*(destiny-origin);
|
|
|
|
- topDiskOrigin.y += 42*(originTower.length-destinyTower.length-1);
|
|
|
|
- originTower.pop();
|
|
|
|
- destinyTower.push(topDiskOrigin);
|
|
|
|
- drawScene();
|
|
|
|
|
|
+function undoMove(){
|
|
|
|
+ if(nCurrentMoves>0){
|
|
|
|
+ var res = moves[nCurrentMoves-1].split(" ");
|
|
|
|
+ undo=true;
|
|
|
|
+ moveFromTo(parseInt(res[1]), parseInt(res[0]));
|
|
|
|
+ if(nCurrentMoves==0) undoButton.setInteractive({useHandCursor: false});
|
|
|
|
+ redoButton.setInteractive({useHandCursor: true});
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+}
|