Grille Code

by greentec
using 6X6 Grille, you can make code message and decode it.

1. select a message in upper list.
2. push encode button, and check your code message. 
- if original message is shorter than 36, random alphabet fill the rest of code message.
3. push decode button, see decoding animation.

Reference - http://en.wikipedia.org/wiki/Grille_(cryptography)

* I used List component in minimalcomps first, but it is not working.. I don't know why. so I changed List to ComboBox...
♥0 | Line 335 | Modified 2014-10-12 02:30:14 | MIT License
play

ActionScript3 source code

/**
 * Copyright greentec ( http://wonderfl.net/user/greentec )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/x6Rb
 */

package {
    import com.bit101.components.InputText;
    import com.bit101.components.Label;
    import com.bit101.components.ComboBox;
    import com.bit101.components.PushButton;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.utils.ByteArray;
    
    public class FlashTest extends Sprite {
        
        public var _backBD:BitmapData;
        public var _back:Bitmap;
        
        public var _width:int = 465;
        public var _height:int = 465;
        
        public var grilleWidth:int = 6;
        public var grilleCellWidth:int = 30;
        public var grilleShape:Shape = new Shape();
        public var grilleArray:Array = [];
        public var grilleCopyArray:Array;
        public var codeArray:Array = [];
        
        public var plainTextArray:Array = ["SHEWALKSINBEAUTYLIKETHENIGHT",
                                           "OFCLOUDLESSCLIMESANDSTARRYSKIES",
                                           "ANDALLTHATSBESTOFDARKANDBRIGHT",
                                           "MEETINHERASPECTANDHEREYES",
                                           "THUSMELLOWEDTOTHATTENDERLIGHT",
                                           "WHICHHEAVENTOGAUDYDAYDENIES"]; //Lord Byron, <She Walks in Beauty>
        //public var plainTextArray:Array = ["%"];
        public var alphabet:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        public var pickIndex:int;
        public var codeText:String;
        public var decodeText:String;
        public var labelArray:Array = [];
        
        public var encodeButton:PushButton;
        public var decodeButton:PushButton;
        public var showGrilleButton:PushButton;
        public var rotateGrilleButton:PushButton;
        public var codeTextLabel:InputText;
        public var decodeTextLabel:InputText;
        public var plainTextList:ComboBox;
        
        public var rotateDuration:int = 15;
        public var rotateNowFrame:int = 0;
        public var rotateTarget:int;
        public var rotateOriginal:int;
        
        public var decodeIndex:int;
        public var decodeAnimationTime:int;
        public var decodeAnimationTimeMax:int = 36 + 16 * 4;
        
        public function FlashTest() {
            // write as3 code here..
            _backBD = new BitmapData(_width, _height, false, 0x292929);
            _back = new Bitmap(_backBD);
            addChild(_back);
            
            var label:Label = new Label(this, 10, 10, "Plain Text - ( Lord Byron, <She Walks in Beauty> )");
            plainTextList = new ComboBox(this, 10, 30, "", plainTextArray);
            plainTextList.width = 465 - 20;
            //plainTextList.height = 40;
            
            encodeButton = new PushButton(this, 10, _height / 2 - (grilleCellWidth * (grilleWidth + 2) / 2), "ENCODE", onEncode);
            encodeButton.width = 90;
            encodeButton.height = 110;
            
            decodeButton = new PushButton(this, 10, encodeButton.y + encodeButton.height + 10, "DECODE", onDecode);
            decodeButton.width = 90;
            decodeButton.height = 110;
            
            showGrilleButton = new PushButton(this, _width - 100, encodeButton.y, "SHOW Grille", onShowGrille);
            showGrilleButton.toggle = true;
            showGrilleButton.width = 90;
            showGrilleButton.height = 110;
            
            rotateGrilleButton = new PushButton(this, showGrilleButton.x, showGrilleButton.y + showGrilleButton.height + 10, "ROTATE Grille", onRotateGrille);
            rotateGrilleButton.toggle = true;
            rotateGrilleButton.width = 90;
            rotateGrilleButton.height = 110;
            
            
            label = new Label(this, 10, _height / 2 + (grilleCellWidth * (grilleWidth + 2) / 2) + 10, "Code Text");
            codeTextLabel = new InputText(this, 10, label.y + label.height + 5, "");
            codeTextLabel.width = _width / 2;
            
            label = new Label(this, 10, codeTextLabel.y + codeTextLabel.height + 10, "Decode Text");
            decodeTextLabel = new InputText(this, 10, label.y + label.height + 5, "");
            decodeTextLabel.width = _width / 2;
            
            initGrille();
            
            //redColT = new ColorTransform();
            //redColT.color = 0xff0000;
            
            grilleShape.x = _width / 2;
            grilleShape.y = _height / 2;
            addChild(grilleShape);
            
            pickIndex = Math.random() * plainTextArray.length;
            plainTextList.selectedIndex = pickIndex;
            makeCodeText();
            
            //addEventListener(Event.ENTER_FRAME, onLoop);
        }
        
        private function onRotateGrille(e:Event = null):void
        {
            rotateGrilleButton.enabled = false;
            //grilleShape.rotation += 90;
            
            rotateNowFrame = 0;
            rotateTarget = 75;
            rotateOriginal = grilleShape.rotation;
            addEventListener(Event.ENTER_FRAME, onRotateEaseOutSine);
            
        }
        
        private function onRotateEaseOutSine(e:Event):void
        {
            
            if (rotateNowFrame >= rotateDuration)
            {
                //grilleShape.rotation = rotateTarget;
                removeEventListener(Event.ENTER_FRAME, onRotateEaseOutSine);
                rotateGrilleButton.enabled = true;
            }
            else
            {
                rotateNowFrame += 1;
                //grilleShape.rotation = rotateTarget * Math.sin(rotateNowFrame / rotateDuration * (Math.PI / 2)) + rotateNowFrame;
                grilleShape.rotation = rotateOriginal + rotateTarget * Math.sin(rotateNowFrame / rotateDuration * (Math.PI / 2)) + rotateNowFrame;
                //trace(grilleShape.rotation);
                
            }
            
            
        }
        
        private function onShowGrille(e:Event):void
        {
            grilleShape.alpha = 1 - grilleShape.alpha;
        }
        
        private function onDecode(e:Event):void
        {
            decodeButton.enabled = false;
            rotateGrilleButton.enabled = false;
            
            var i:int, j:int, r:int;
            var index:int;
            index = 0;
            
            //decodeTextLabel.text = "";
            decodeText = "";
            
            for (r = 0; r < 4; r += 1)
            {
                for (i = 0; i < grilleWidth; i += 1)
                {
                    for (j = 0; j < grilleWidth; j += 1)
                    {
                        if (grilleArray[i][j] == 0)
                        {
                            decodeText += labelArray[i][j].text;
                            index += 1;
                            //if (r == 0) // for debug..
                            //{
                                //labelArray[i][j].transform.colorTransform = redColT;
                            //}
                        }
                    }
                }
                
                //if (r != 3)
                {
                    //copy and rotate
                    grilleCopyArray = clone(grilleArray);
                    
                    for (i = 0; i < grilleWidth; i += 1)
                    {
                        for (j = 0; j < grilleWidth; j += 1)
                        {
                            grilleArray[i][j] = grilleCopyArray[grilleWidth - j - 1][i];
                            //trace(i, j, "<-", grilleWidth - j - 1, i);
                        }
                    }
                    
                }
                
                
                
                
            }
            
            decodeIndex = 0;
            decodeTextLabel.text = "";
            decodeAnimationTime = 0;
            grilleShape.rotation = 0;
            addEventListener(Event.ENTER_FRAME, onDecodeAnimation);
        }
        
        private function onDecodeAnimation(e:Event):void
        {
            if (decodeAnimationTime < decodeAnimationTimeMax)
            {
                if (decodeAnimationTime % 25 < 9) //25 = 9 + 16. 9 = cellNum in one Grille. 16 = rotate Anim. duration + 1
                {
                    decodeTextLabel.text += decodeText.substr(decodeIndex, 1);
                    decodeIndex += 1;
                }
                else if(decodeAnimationTime % 25 == 9) //anim. first frame
                {
                    rotateNowFrame = 0;
                    rotateTarget = 75;
                    rotateOriginal = grilleShape.rotation;
                }
                else //on Animation.
                {
                    rotateNowFrame += 1;
                    grilleShape.rotation = rotateOriginal + rotateTarget * Math.sin(rotateNowFrame / rotateDuration * (Math.PI / 2)) + rotateNowFrame;
                    
                }
                
                decodeAnimationTime += 1;
                
            }
            else
            {
                removeEventListener(Event.ENTER_FRAME, onDecodeAnimation);
                decodeButton.enabled = true;
                rotateGrilleButton.enabled = true;
            }
            
            
        }
        
        private function onEncode(e:Event):void
        {
            resetGrille();
            
            pickIndex = plainTextList.selectedIndex;
            makeCodeText();
        }
        
        private function resetGrille():void
        {
            var i:int, j:int;
            
            for (i = 0; i < grilleWidth; i += 1)
            {
                for (j = 0; j < grilleWidth; j += 1)
                {
                    grilleArray[i][j] = 1;
                }
            }
            
            makeGrille();
            
        }
        
        private function makeCodeText():void
        {
            //pickIndex = Math.random() * plainTextArray.length;
            //plainTextList.selectedIndex = pickIndex;
            
            var i:int, j:int, r:int;
            var index:int = 0;
            var len:int = plainTextArray[pickIndex].length;
            
            for (r = 0; r < 4; r += 1)
            {
                for (i = 0; i < grilleWidth; i += 1)
                {
                    for (j = 0; j < grilleWidth; j += 1)
                    {
                        if (grilleArray[i][j] == 0)
                        {
                            if (index < len)
                            {
                                codeArray[i][j] = plainTextArray[pickIndex].substr(index, 1);
                                labelArray[i][j].text = codeArray[i][j];
                            }
                            else
                            {
                                codeArray[i][j] = alphabet.substr(int(Math.random() * alphabet.length), 1);
                                labelArray[i][j].text = codeArray[i][j];
                            }
                            index += 1;
                            //if (r == 0) // for debug..
                            //{
                                //labelArray[i][j].transform.colorTransform = redColT;
                            //}
                        }
                    }
                }
                
                //if (r != 3)
                {
                    //copy and rotate
                    grilleCopyArray = clone(grilleArray);
                    
                    for (i = 0; i < grilleWidth; i += 1)
                    {
                        for (j = 0; j < grilleWidth; j += 1)
                        {
                            grilleArray[i][j] = grilleCopyArray[grilleWidth - j - 1][i];
                            //trace(i, j, "<-", grilleWidth - j - 1, i);
                        }
                    }
                    
                }
                
                
                
                //for (i = 0; i < grilleWidth; i += 1)
                //{
                    //trace(grilleArray[i]);
                //}
            }
            
            codeText = "";
            for (i = 0; i < grilleWidth; i += 1)
            {
                for (j = 0; j < grilleWidth; j += 1)
                {
                    codeText += codeArray[i][j];
                }
            }
            
            codeTextLabel.text = codeText;
            
            //trace(index);
            //trace(plainTextArray[pickIndex]);
            //trace(codeText);
            
            
            
        }
        
        //private function onLoop(e:Event):void
        //{
            //grilleShape.rotation += 1;
        //}
        
        private function initGrille():void
        {
            //init grille data
            var i:int, j:int;
            var label:Label;
            
            for (i = 0; i < grilleWidth; i += 1)
            {
                grilleArray[i] = [];
                codeArray[i] = [];
                labelArray[i] = [];
                
                for (j = 0; j < grilleWidth; j += 1)
                {
                    grilleArray[i].push(1);
                    codeArray[i].push(" ");
                    label = new Label(this, 
                                      (j - (grilleWidth / 2)) * grilleCellWidth + _width / 2, 
                                      (i - (grilleWidth / 2)) * grilleCellWidth + _height / 2, 
                                      "");
                    label.scaleX = label.scaleY = 1.5;
                    labelArray[i].push(label);
                }
            }
            
            makeGrille();
            
        }
        
        private function makeGrille():void
        {
            var i:int, j:int;
            //var arr:Array = printRandomNumber(grilleWidth * grilleWidth, int(grilleWidth * grilleWidth / 4));
            var arr:Array = printRandomNumber(int(grilleWidth * grilleWidth / 4), int(grilleWidth * grilleWidth / 4)); //consider position
            var dx:int;
            var dy:int;
            var r:int;
            var k:int;
            var temp:int;
            
            for (i = 0; i < arr.length; i += 1)
            {
                dx = arr[i] % (grilleWidth / 2);
                dy = int(arr[i] / (grilleWidth / 2));
                
                r = Math.random() * 4;
                if (r > 0)
                {
                    for (k = 1; k < r; k += 1) //90 degree rotate - for k times
                    {
                        temp = dx;
                        dx = dy 
                        dy = grilleWidth - temp - 1;
                    }
                }
                
                grilleArray[dy][dx] = 0;
                //trace(dy, dx);
            }
            //trace(grilleArray);
            
            //draw grille
            grilleShape.graphics.clear();
            grilleShape.graphics.beginFill(0x00cc00);
            
            grilleShape.graphics.drawRect(grilleCellWidth * -(grilleWidth + 2) / 2, grilleCellWidth * -(grilleWidth + 2) / 2, grilleCellWidth * (grilleWidth + 2), grilleCellWidth * (grilleWidth + 2));
            grilleShape.graphics.drawRect(grilleCellWidth * (-(grilleWidth + 2) / 2 + 1), grilleCellWidth * (-(grilleWidth + 2) / 2 + 1), grilleCellWidth * grilleWidth, grilleCellWidth * grilleWidth);
            
            grilleShape.graphics.beginFill(0x006600);
            
            for (i = 0; i < grilleWidth; i += 1)
            {
                for (j = 0; j < grilleWidth; j += 1)
                {
                    if (grilleArray[i][j] == 1)
                    {
                        grilleShape.graphics.drawRect((j-(grilleWidth/2)) * grilleCellWidth, (i-(grilleWidth/2)) * grilleCellWidth, grilleCellWidth, grilleCellWidth);
                    }
                }
            }
            
            grilleShape.graphics.endFill();
        }
        
        private function printRandomNumber(n:int, k:int) : Array
        {
            var original:Array=[];
            var result:Array=[];
            var i:int;
            var randInt:int;
            var temp:Object;
            
            for(i=0;i<n;i+=1)
            {
                original.push(i);
            }
            
            for(i=0;i<k;i+=1)
            {
                randInt = Math.random()*(n-i) + i;
                temp = original[i];
                original[i] = original[randInt];
                original[randInt] = temp;
                result.push(original[i]);
            }
            
            return result;
        }
        
        public function clone(source:Object):*
        {
            var myBA:ByteArray = new ByteArray();
            myBA.writeObject(source);
            myBA.position = 0;
            return(myBA.readObject()); 
        }
    }
}