forked from: Game Life Gex

by Cheshir forked from Game Life Gex (diff: 186)
Продолжим, как оказалось - в gex поле - фигуры более симметричны, и у них меньше
"Степеней" свободы, чем в оригинале. 
Как это можно развить? 
1. Сделать поле больше, а клетки меньше - наглядность
2. Касательно свободы - думаю, можно попробовать добавить "старение"
сейчас клетка либо 1(жива) либо 0(мертва) - 2(жива) 1(старая) 0(мертва)
в таком варианте клетки будут жить на один шаг дольше, что возможно даст чуть больше свободы
и упростит создание интересных форм - глайдеры, долгожители
♥0 | Line 232 | Modified 2016-12-10 03:39:50 | MIT License
play

ActionScript3 source code

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

// forked from Cheshir's Game Life Gex
// Продолжим, как оказалось - в gex поле - фигуры более симметричны, и у них меньше
// "Степеней" свободы, чем в оригинале. 
// Как это можно развить? 
// 1. Сделать поле больше, а клетки меньше - наглядность
// 2. Касательно свободы - думаю, можно попробовать добавить "старение"
// сейчас клетка либо 1(жива) либо 0(мертва) - 2(жива) 1(старая) 0(мертва)
// в таком варианте клетки будут жить на один шаг дольше, что возможно даст чуть больше свободы
// и упростит создание интересных форм - глайдеры, долгожители

package {
    import flash.events.Event;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextField;
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        public var front:Sprite;
        public var logit:TextField;
        public var play:Sprite;
        
        public var field:Array=[];
        public var fieldCheck:Array=[];
        
        public var widthF:int = 28; // Централизуем размеры
        public var heightF:int = 24;
        
        public function FlashTest() {
            // write as3 code here..
            front = new Sprite();
            play = new Sprite();
            logit = new TextField();
            logit.autoSize = TextFieldAutoSize.LEFT;
            initField();
            
            drawField();
            addChild(front);
            addChild(logit);
            addChild(play);
            play.x = 160; play.y = 10;
            drawPlayButton();
            stage.addEventListener(MouseEvent.MOUSE_MOVE, cellMove);
            stage.addEventListener(MouseEvent.CLICK, cellSet);
            play.addEventListener(MouseEvent.CLICK, playHolder);
            
            stage.addEventListener(Event.ENTER_FRAME, loopGame);
            stage.frameRate = 16;
            /* Что дальше? 
            Очевидно, что гексагональные сетки отличаются правилами
            и я не вижу ничего интересного пока. Ничего похожего на глайдеры
            Однако есть таки некоторые статьи на эту тему, где предлагаются следующие правила:
            1) Клетка при сумме состояний ее 6-ти соседей <(a) и >(b) умирает. =0;
            2) При сумме равной (a) или (b) рождается. =1;
            3) В остальных случаях не меняет состояние
            предлагают попробовать варианты
            [2,2] [2,3] [3,3] [3,4] [3,5] [3,6]
            Но эти варианты как я понимаю не подразумевают разных состояний клеток.
            
            С разными состояниями похоже тоже есть интересные варианты.
            Однако из за технической сложности статьи не догоняю в чем они состоят
            Вводятся термины "ингибитор" "активатор" "основание"
            "основание" - очевидно пустая клетка
            "ингибитор" - это замедлитель реакции (что имеется в виду в статье?)
            "активатор" - это ускоритель реакции (и как это понимать в КА?)
            */
        }
        // Цикл игры
        private var checkFrame:Boolean = true;
        private var inGame:Boolean = false;
        public function loopGame(e:Event):void{
            if(!inGame){ return; } // Вообще пауза, забей на все
            
            var tx:int = 0;
            var ty:int = 0;
            
            // А что если каждый шаг будет разный, тогда вообще хрен угадаешь)))
            // но случайности не стабилизируются...
            var automat:Function = automats[2];//automats[Math.floor(Math.random()*2)];
            if(checkFrame){ // Проверочный этап
                // необходимо пройти по массиву игры field и записать 
                // в массив fieldCheck - как должно быть на следующей итерации
                for(tx=0; tx<widthF; tx++){
                    for(ty=0; ty<heightF; ty++){
                        fieldCheck[tx][ty] = automat(tx,ty);
                        //fieldCheck[tx][ty] = cell_automat_older34(tx,ty);
                    }
                }
            } else { // Этап обновления
                // Здесь необходимо переписать все из массива fieldCheck в field 
                for(tx=0; tx<widthF; tx++){
                    for(ty=0; ty<heightF; ty++){
                        field[tx][ty] = fieldCheck[tx][ty];
                    }

                }
                drawField();    // Чуть не забыл ;)
            }
            checkFrame = !checkFrame;
        }
        
        public var automats:Object = {0:cell_automat_older, 1:cell_automat, 2:cell_automat_older34};
        
        // "Стареющий" клеточный автомат - 3 состояния клеток [0,1,2]
        // Теперь клетки будут стареть, всесто смерти, от клетки отнимается 1
        public function cell_automat_older(tx:int, ty:int):int{
            var cl:int = getCell(tx,ty);
            var ar:int = aroundCount(tx,ty); 
            if(cl == 0){ // Мертвая клетка 
                if(ar==3){ // Вокруг 3
                    return 2; // Новая клетка
                }
            } else { // Живая клетка - 1 или 2
                if(ar >= 2 && ar <= 3){ // Соседи в норме
                    return cl; // Остается жить в том же состоянии
                }
            }
            if(cl-1<0){
                return 0; // Мертвые клетки остаются мертвыми
            }
            return cl-1; // Живая клетка у которой соседи - неадекваты - умирает
        }
        
        // Эта функция для 0,1 состояний с разными параметрами
        private var auto_a:int = 3;
        private var auto_b:int = 4;
        public function cell_automat(tx:int, ty:int):int{
            var cl:int = getCell(tx,ty);
            var ar:int = aroundCount(tx,ty);/*
            1) Клетка при сумме состояний ее 6-ти соседей <(a) и >(b) умирает. =0;
            2) При сумме равной (a) или (b) рождается. =1;
            3) В остальных случаях не меняет состояние */
            if(ar < auto_a || ar > auto_b){
                return 0;
            }
            if(ar == auto_a || ar == auto_b){
                return 1;
            }
            return cl;
        }
        
        // Здесь я попробую содинить страение с правилом 3 и 4 rule34?
        public function cell_automat_older34(tx:int, ty:int):int{
            var cl:int = getCell(tx,ty);
            var ar:int = aroundCount(tx,ty); 
            
            if(cl == 0){ // Мертвая клетка 
                if(ar==3){ // Вокруг 3
                    return 2; // Новая клетка
                }
                if(ar==4){ // Слабая клетка
                    return 1;
                }
            } else { // Живая клетка - 1 или 2
                if(ar >= 3 && ar <= 4){ // Соседи от 3 до 4
                    return cl; // Остается жить в том же состоянии
                }
            }

            if(cl-1<0){
                return 0; // Мертвые клетки остаются мертвыми
            }
            return cl-1; // Живая клетка у которой соседи - неадекваты - умирает
        }


        
        // Запуск и остановка игры.
        public function playHolder(e:MouseEvent):void{
            inGame = !inGame;
            if(inGame){
                drawPauseButton();
            } else {
                // Когда игра ставится на паузу недостаточно просто остановить отрисовку
                drawPlayButton(); // Необходимо вернуть игру в состояние проверочного этапа
                checkFrame = true;
            }
        }
        // Игра на паузе рисуем стрелку
        public function drawPlayButton():void{
            play.graphics.clear();
            play.graphics.beginFill(0xffffff);
            play.graphics.drawRect(0,0,30,30);
            play.graphics.beginFill(0x00cc00);
            play.graphics.lineTo(30,15);
            play.graphics.lineTo(0,30);
            play.graphics.endFill();
        }
        public function drawPauseButton():void{
            play.graphics.clear();
            play.graphics.beginFill(0xffffff);
            play.graphics.drawRect(0,0,30,30);
            play.graphics.beginFill(0xcc0000);
            play.graphics.drawRect(0,0,10,30);
            play.graphics.drawRect(20,0,10,30);
            play.graphics.endFill();
        }
        
        // Создание пуcтого поля
        public function initField():void{
            // Как хранить данные о гексагональных клетках? 
            // Так же как и обычные, просто каждая четная колонка смещена.
            for(var tx:int=0; tx<widthF; tx++){
                field[tx] = [];
                fieldCheck[tx] = [];
                for(var ty:int=0; ty<heightF; ty++){
                    field[tx][ty] = 0;//Math.round(Math.random()); // Все клетки 2|1|0
                    fieldCheck[tx][ty] = 0;
                }
            }/*
            for(var i:int=0; i<rand_life; i++){
                field[Math.round(widthF*Math.random())][Math.round(heightF*Math.random())] = 1;
            }*/
        }
        
        // Рассчет соседей в gex-окресностях
        public function aroundCount(x:uint, y:uint):int{
            // Игра "Жизнь" использует окресность Мура, но у меня только 6 клеток
            var ar:int = 0;
            if(x%2==0){ // Четные
                ar += cellLife(x, y-1);
                ar += cellLife(x+1, y-1);
                ar += cellLife(x+1, y);
                ar += cellLife(x, y+1);
                ar += cellLife(x-1, y);
                ar += cellLife(x-1, y-1);
            } else { // Нечетные
                ar += cellLife(x, y-1);
                ar += cellLife(x+1, y);
                ar += cellLife(x+1, y+1);
                ar += cellLife(x, y+1);
                ar += cellLife(x-1, y+1);
                ar += cellLife(x-1, y);
            }
        //    log("and ar?"+ar);
            return ar;
        //    log(x+" "+y+" around "+ar);
        }
        
        // Чтобы не ломалось out of range и "закольцевать" массив
        // Получить, жива ли клетка 1 или 0
        public function cellLife(tx:int, ty:int):int{
            if(tx>widthF-1) { tx-=widthF; } else if (tx<0){ tx+=widthF; }
            if(ty>heightF-1){  ty-=heightF; } else if (ty<0){ ty+=heightF; }
            if(field[tx][ty] > 0){
                return 1;
            }
            return 0;
        }
        // Получить точное значение клетки
        public function getCell(tx:int, ty:int):int{
            if(tx>widthF-1) { tx-=widthF; } else if (tx<0){ tx+=widthF; }
            if(ty>heightF-1){  ty-=heightF; } else if (ty<0){ ty+=heightF; }
            return field[tx][ty];
        }


        // Корректирование игрового поля кликом 
        public function cellSet(e:MouseEvent):void{
            var xj:int = Math.floor((e.localX+7) / 14)-1;
            var yj:int = Math.floor((e.localY) / 14)-5;
            if(xj%2==0){
              yj+=1;  
            }
            if(xj>widthF-1 || yj>heightF-1 || xj<0 || yj<0){
                log("за пределами");
                return;
            }
            
            var cell:int = getCell(xj,yj);
            if(cell==2){ field[xj][yj] = 0;
            } else if(cell==0){ field[xj][yj] = 2; }
            drawField();
        }
        
        // Перемещение указателя мышки
        public function cellMove(e:MouseEvent):void {
            var xj:int = Math.floor((e.localX+7) / 14)*14;
            var yj:int = Math.floor((e.localY) / 14)*14;
            if(xj/14%2==1){ // Все еще проблема с позиционированием позиции мышки
                yj+=7; // Но по крайней мере почти.
            }
            front.graphics.clear();
            front.graphics.beginFill(0xff0000, 0.6);
            front.graphics.drawCircle(xj,yj, 6);
        //    log(xj+" "+yj);
        }

        // Дебаг, потому как trace нету
        public function log(s:*):void{
            logit.appendText("\n"+s.toString());
            if(logit.text.length>50){
                logit.text = s.toString();
            }
        }
        
        // Отрисовка Поля клеток
        public function drawField():void{
            this.graphics.clear();
            for(var i:int=0; i<widthF; i++){
                drawLine(i);
            }
        }
        
        // Отрисовка Столбца клеток
        public function drawLine(x:int):void{
            var yJoo:int = 14;
            if(x%2==0){
                yJoo = 7;
            }
            for(var y:int=0; y<heightF; y++){
                this.graphics.beginFill(0xcccccc);
                this.graphics.drawCircle(14 + x*14, 56 + yJoo + y*14, 6);
                if(field[x][y]==1){
                    this.graphics.beginFill(0x77aa77);
                    this.graphics.drawCircle(14+x*14, 56+yJoo+y*14, 6);
                    this.graphics.drawCircle(14+x*14, 56+yJoo+y*14, 3);
                } else if(field[x][y]==2){
                    this.graphics.beginFill(0x77aa77);
                    this.graphics.drawCircle(14+x*14, 56+yJoo+y*14, 6);
                }
            }
            //log("draw "+x);
        }
        

    }
}