Click here to Skip to main content
15,891,375 members
Articles / Web Development / XHTML

Silverlight integrated into ASP.NET AJAX Control (Fifteen Puzzle Game)

Rate me:
Please Sign up or sign in to vote.
4.28/5 (13 votes)
17 Jun 2008CPOL4 min read 80.3K   1.2K   65  
Silverlight integrated into an ASP.NET AJAX control (Fifteen Puzzle Game).
    Type.registerNamespace("Controls");
    
    Controls.FifteenPuzzle = function(element)
    {
        Controls.FifteenPuzzle.createProperty("width");
        Controls.FifteenPuzzle.createProperty("height");
        Controls.FifteenPuzzle.createProperty("xamlUrl");
        Controls.FifteenPuzzle.createProperty("imageUrl");
        Controls.FifteenPuzzle.createProperty("puzzleRenderMode");
        
        Controls.FifteenPuzzle.initializeBase(this, [element]);
        
        this.PuzzleSize = 100;
        this.FontSize = 70;
        
        this.positions = new Array();
        
        for (var nRow=0;nRow<4;nRow++)
        {
            this.positions[nRow] = new Array();
            
            for (var nCol=0;nCol<4;nCol++)
            {
                this.positions[nRow][nCol] = ((nRow*4) + nCol + 1);
            }
        }
        
    }

    Controls.FifteenPuzzle.prototype =
    {
        initialize : function()
        {
            Controls.FifteenPuzzle.callBaseMethod(this, "initialize");
            
            this._renderControl();
        },
        
        dispose : function()
        {
            Controls.FifteenPuzzle.callBaseMethod(this, "dispose");
        },
	    
	    _getContentElement : function()
	    {
	        return $get(String.format("{0}_Content", this.get_id()));
	    },
	    
	    _onXamlLoaded : function(plugIn, userContext, rootElement)
	    {
	        this._plugIn = plugIn;
	        this._rootElement = rootElement;
	        
	        this._renderNumbers();
	        this._drawShuffleButton();
	    },
	    
	    _getXPosition : function(nCol)
	    {
	        return (15 + (nCol*(this.PuzzleSize+1)))+2;
	    },
	    
	    _getYPosition : function(nRow)
	    {
	        return (65 + (nRow*(this.PuzzleSize+1)))+2;
	    },
	    
	    _drawShuffleButton : function()
	    {
	        var sb = new Sys.StringBuilder();

            sb.append(String.format('<Canvas Name="{0}_btnShuffle" Canvas.Left="140" Canvas.Top="520" Width="160" Height="45" Background="White" Cursor="Hand">', this.get_id()));
            sb.append('<Rectangle Fill="#80000000" Width="158" Height="43" Canvas.Top="2" Canvas.Left="2" RadiusX="15" RadiusY="15">');
            sb.append('</Rectangle>');
            sb.append('<Rectangle Width="160" Height="45" Canvas.Top="0" Canvas.Left="0" RadiusX="15" RadiusY="15">');
            sb.append('<Rectangle.Fill>');
            sb.append('<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">');
            sb.append('<GradientStop Offset="0" Color="Orange"/>');
            sb.append('<GradientStop Offset="0.6" Color="Red"/>');
            sb.append('</LinearGradientBrush>');
            sb.append('</Rectangle.Fill>');
            sb.append('</Rectangle>');
            sb.append('<Rectangle Width="158" Height="43" Canvas.Top="1" Canvas.Left="1" RadiusX="14" RadiusY="14">');
            sb.append('<Rectangle.Fill>');
            sb.append('<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">');
            sb.append('<GradientStop Offset="0" Color="#FFFFFFFF"/>');
            sb.append('<GradientStop Offset="1" Color="#00000000"/>');
            sb.append('</LinearGradientBrush>');
            sb.append('</Rectangle.Fill>');
            sb.append('</Rectangle>');
            sb.append('<TextBlock Canvas.Left="10" Canvas.Top="0" Canvas.ZIndex="1" Text="Shuffle" FontFamily="Verdana" FontSize="35" FontWeight="Bold"></TextBlock>');
            sb.append('</Canvas>');
            
            var buttonElement = this._plugIn.content.createFromXaml(sb.toString(), false);
            this._rootElement.children.add(buttonElement);
            
            buttonElement.AddEventListener("MouseLeftButtonDown", this._onShuffleClick)
	    },
	    
	    _drawNumber : function(nRow, nCol)
	    {
	        var n = ((nRow*4)+nCol+1);
	        
	        var sb = new Sys.StringBuilder();
	        
	        if (this.get_puzzleRenderMode()==Controls.PuzzleRenderMode.Number)
	        {
                sb.append(String.format('<Canvas Name="{0}_Cell_{1}" Canvas.Left="{2}" Canvas.Top="{3}" Canvas.ZIndex="3" Width="{4}" Height="{4}" Background="White" Cursor="Hand">', this.get_id(), n, this._getXPosition(nCol), this._getYPosition(nRow), this.PuzzleSize));
                sb.append('<Rectangle Fill="#80000000" Width="98" Height="98" Canvas.Top="2" Canvas.Left="2" RadiusX="15" RadiusY="15">');
                sb.append('</Rectangle>');
                sb.append('<Rectangle Width="100" Height="100" Canvas.Top="0" Canvas.Left="0" RadiusX="15" RadiusY="15">');
                sb.append('<Rectangle.Fill>');
                sb.append('<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">');
                sb.append('<GradientStop Offset="0" Color="Green"/>');
                sb.append('<GradientStop Offset="0.6" Color="Lime"/>');
                sb.append('</LinearGradientBrush>');
                sb.append('</Rectangle.Fill>');
                sb.append('</Rectangle>');
                sb.append('<Rectangle Width="98" Height="98" Canvas.Top="1" Canvas.Left="1" RadiusX="14" RadiusY="14">');
                sb.append('<Rectangle.Fill>');
                sb.append('<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">');
                sb.append('<GradientStop Offset="0" Color="#FFFFFFFF"/>');
                sb.append('<GradientStop Offset="1" Color="#00000000"/>');
                sb.append('</LinearGradientBrush>');
                sb.append('</Rectangle.Fill>');
                sb.append('</Rectangle>');
                sb.append(String.format('<TextBlock Name="{0}_TextBlock_{1}_{2}" Canvas.Left="25" Canvas.Top="0" Canvas.ZIndex="1" FontFamily="Verdana" FontSize="{3}" Text="{4}" FontWeight="Bold" Cursor="Hand" />', this.get_id(), nRow, nCol, this.FontSize, n));
                sb.append('</Canvas>');
            }
            else if (this.get_puzzleRenderMode()==Controls.PuzzleRenderMode.Image)
            {
                sb.append(String.format('<Image Name="{0}_Cell_{1}" Canvas.Left="{2}" Canvas.Top="{3}" Canvas.ZIndex="3" Width="{4}" Height="{4}" Cursor="Hand" Source="{5}">', this.get_id(), n, (17+nCol), (67+nRow), (this.PuzzleSize*4), this.get_imageUrl()));
                sb.append('<Image.Clip>');
                sb.append(String.format('<RectangleGeometry Rect="{0},{1},{2},{2}" RadiusX="15" RadiusY="15"></RectangleGeometry>', (nCol*this.PuzzleSize), (nRow*this.PuzzleSize), this.PuzzleSize));
                sb.append('</Image.Clip>');
                sb.append('<Image.RenderTransform>');
                sb.append(String.format('<TranslateTransform Name="{0}_Cell_{1}_Transform" X="0" Y="0" />', this.get_id(), n));
                sb.append('</Image.RenderTransform>');
                sb.append('</Image>');
            }
            
            var numberElement = this._plugIn.content.createFromXaml(sb.toString(), false);
            this._rootElement.children.add(numberElement);
            
            var elementNumber = this._rootElement.findName(String.format("{0}_Cell_{1}", this.get_id(), n));
            
            if (this.get_puzzleRenderMode()==Controls.PuzzleRenderMode.Number)
            {
                var textBlockNumber = this._rootElement.findName(String.format("{0}_TextBlock_{1}_{2}", this.get_id(), nRow, nCol));
                
                textBlockNumber["Canvas.Left"] = ((this.PuzzleSize - textBlockNumber.ActualWidth) / 2).toString();
                textBlockNumber["Canvas.Top"] = ((this.PuzzleSize - textBlockNumber.ActualHeight) / 2).toString();
            }
            
            elementNumber.AddEventListener("MouseLeftButtonDown", this._onNumberClick)
	    },
	    
	    _getPuzzleNumber : function(nRow, nCol)
	    {
	        return this.positions[nRow][nCol];
	    },
	    
	    _setPuzzleNumber : function(nRow, nCol, number)
	    {
	        this.positions[nRow][nCol]=number;
	    },
	    
	    _getCellPosition : function(number)
	    {
	        var cellPosition = new Object();
	        
            for (var nRow=0;nRow<4;nRow++)
            {
                for (var nCol=0;nCol<4;nCol++)
                {
	                if (this.positions[nRow][nCol]==number)
	                {
	                    cellPosition.nRow = nRow;
	                    cellPosition.nCol = nCol;
	                    break;
	                }
	            }
	        }
	        
	        return cellPosition;
	    },
	    
	    _getNumberFromElement : function(elementNumber)
	    {
	        var values = elementNumber.Name.split('_');
	        return parseInt(values[values.length-1]);
	    },
	    
	    _getElementFromNumber : function(number)
	    {
	        return this._rootElement.findName(String.format("{0}_Cell_{1}", this.get_id(), number));
	    },
	    
	    _onShuffleClick : function(sender, mouseEventArgs)
	    {
	        var values = sender.Name.split('_');
	        var control = $find(values[0]);
	        
	        for (var t=0;t<300;t++)
	        {
	            control._nextStepShuffle();
	        }
	        
	        control._refreshNumbers();
	    },
	    
	    _refreshNumbers : function()
	    {
            for (var nRow=0;nRow<4;nRow++)
            {
                for (var nCol=0;nCol<4;nCol++)
                {
                    var number = this.positions[nRow][nCol];
                    
                    if (number<16)
                    {
                        var elementNumber = this._getElementFromNumber(number);
                        this._setPuzzlePosition(number, elementNumber, nRow, nCol);
                    }
	            }
	        }
	    },
	    
	    _nextStepShuffle : function()
	    {
            var end = false;
            
            while (!end)
            {
                var randomNumber=(Math.floor(Math.random()*15)+1);
                
                var cellPosition = this._getCellPosition(randomNumber);
                
                end = this._tryToMove(false, cellPosition.nRow, cellPosition.nCol);
            }
	    },
	    
	    _onNumberClick : function(sender, mouseEventArgs)
	    {
	        var values = sender.Name.split('_');
	        var control = $find(values[0]);
	        
	        var number = control._getNumberFromElement(sender);
	        var cellPosition = control._getCellPosition(number);
	        
	        control._tryToMove(true, cellPosition.nRow, cellPosition.nCol);
	    },
	    
	    _tryToMove : function(makeMove, nRow, nCol)
	    {
	        var number = this._getPuzzleNumber(nRow, nCol)
            var numberElement = this._getElementFromNumber(number);
            
	        var nRowMove=-1;
	        var nColMove=-1;
	        
	        if (nRow==3)
	        {
	            var aboveNumber = this._getPuzzleNumber(nRow-1, nCol);
	            if (aboveNumber==16)
	            {
	                nRowMove=nRow-1;
	                nColMove=nCol;
	            }
	        }
	        else if (nRow==0)
	        {
	            var belowNumber = this._getPuzzleNumber(nRow+1, nCol);
	            if (belowNumber==16)
	            {
	                nRowMove=nRow+1;
	                nColMove=nCol;
	            }
	        }
	        else
	        {
	            var aboveNumber = this._getPuzzleNumber(nRow-1, nCol);
	            var belowNumber = this._getPuzzleNumber(nRow+1, nCol);

	            if (aboveNumber==16)
	            {
	                nRowMove=nRow-1;
	                nColMove=nCol;
	            }
	            
	            if (belowNumber==16)
	            {
	                nRowMove=nRow+1;
	                nColMove=nCol;
	            }
	        }
	        
	        if (nCol==3)
	        {
	            var leftNumber = this._getPuzzleNumber(nRow, nCol-1);
	            if (leftNumber==16)
	            {
	                nRowMove=nRow;
	                nColMove=nCol-1;
	            }
	        }
	        else if (nCol==0)
	        {
	            var rightNumber = this._getPuzzleNumber(nRow, nCol+1);
	            if (rightNumber==16)
	            {
	                nRowMove=nRow;
	                nColMove=nCol+1;
	            }
	        }
	        else
	        {
	            var leftNumber = this._getPuzzleNumber(nRow, nCol-1);
	            var rightNumber = this._getPuzzleNumber(nRow, nCol+1);

	            if (leftNumber==16)
	            {
	                nRowMove=nRow;
	                nColMove=nCol-1;
	            }

	            if (rightNumber==16)
	            {
	                nRowMove=nRow;
	                nColMove=nCol+1;
	            }
	        }
	        
	        if (nRowMove!=-1 && nColMove!=-1)
	        {
                this._movePuzzleTo(makeMove, numberElement, nRowMove, nColMove);
	                
	            return true;
	        }
	        else
	        {
	            return false;
	        }
	    },
	    
	    _setPuzzlePosition : function(number, elementNumber, toNRow, toNCol)
	    {
            if (this.get_puzzleRenderMode()==Controls.PuzzleRenderMode.Number)
            {
                elementNumber["Canvas.Left"] = this._getXPosition(toNCol);
                elementNumber["Canvas.Top"] = this._getYPosition(toNRow);
            }
            else
            {
                var nCol = (number-1)%4;
                var nRow = (number-1-nCol)/4;
                
                var transformElement = this._rootElement.findName(String.format("{0}_Cell_{1}_Transform", this.get_id(), number));
                transformElement["X"] = ((toNCol-nCol)*(this.PuzzleSize+1));
                transformElement["Y"] = ((toNRow-nRow)*(this.PuzzleSize+1));
            }
	    },
	    
	    _movePuzzleTo : function(makeMove, elementNumber, toNRow, toNCol)
	    {
            var number = this._getNumberFromElement(elementNumber);
	        var cellPosition = this._getCellPosition(number);
	        
	        if (makeMove)
	            this._setPuzzlePosition(number, elementNumber, toNRow, toNCol);
	        
            this._setPuzzleNumber(toNRow, toNCol, number);
            this._setPuzzleNumber(cellPosition.nRow, cellPosition.nCol, 16);
            
            if (makeMove)
                this._checkGameCompleted();
	    },
	    
	    _checkGameCompleted : function()
	    {
	        var n = 1;

            for (var nRow=0;nRow<4;nRow++)
            {
                for (var nCol=0;nCol<4;nCol++)
                {
	                if (this.positions[nRow][nCol]!=n)
	                {
	                    return;
	                }
	                
	                n++;
	            }
	        }
	        
            alert("Game completed!");
	    },
	    
	    _renderNumbers : function()
	    {
	        for (var nRow=0;nRow<4;nRow++)
	        {
	            for (var nCol=0;nCol<4;nCol++)
	            {
	                if (((nRow*4)+nCol+1)<=15)
	                {
                        this._drawNumber(nRow, nCol);
                    }
                }
	        }
	    },
	    
        _renderControl : function()
        {
            this.get_element().innerHTML = String.format("<div id='{0}_Content' style='width:{1};height:{2}'></div>", this.get_id(), this.get_width(), this.get_height());
            
            var hostId = String.format("{0}_Host", this.get_id());
            var bounds = Sys.UI.DomElement.getBounds(this._getContentElement());
            
            Silverlight.createObject(this.get_xamlUrl(), this._getContentElement(), hostId, 
            { width:bounds.width.toString(), height:bounds.height.toString(), version:'1.0' },
            { onError:null, onLoad:Function.createDelegate(this, this._onXamlLoaded) }, 
            null);
        }
    };
    
    Controls.FifteenPuzzle.registerClass("Controls.FifteenPuzzle", Sys.UI.Control);
    
    Controls.PuzzleRenderMode = function(){};
    Controls.PuzzleRenderMode.prototype = 
    {
        Number : 0,
        Image : 1
    }
    
    Controls.PuzzleRenderMode.registerEnum("Controls.PuzzleRenderMode");    
    
    if (typeof (Sys) != "undefined")
    {    
        Sys.Application.notifyScriptLoaded();    
    }

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) sparesFinder
Italy Italy
I'm an Italian Software Developer from about 15 years.
I worked a long time in south Italy (where I was born) and after 2 years in Milan and an year in UK, I'm working remotely from Italy as Senior ASP.NET C# Developer using ASP.NET Ajax technology for a UK company.

Check out my personal blog:
http://techcookies.net/

and my first Android game (Fifteen Puzzle X):
https://play.google.com/store/apps/details?id=it.megasoft78.fifteenpuzzlex

Comments and Discussions