forked from: Game Life Gex
forked from Game Life Gex (diff: 186)
Продолжим, как оказалось - в gex поле - фигуры более симметричны, и у них меньше "Степеней" свободы, чем в оригинале. Как это можно развить? 1. Сделать поле больше, а клетки меньше - наглядность 2. Касательно свободы - думаю, можно попробовать добавить "старение" сейчас клетка либо 1(жива) либо 0(мертва) - 2(жива) 1(старая) 0(мертва) в таком варианте клетки будут жить на один шаг дольше, что возможно даст чуть больше свободы и упростит создание интересных форм - глайдеры, долгожители
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);
}
}
}