Пишем игру для Android используя Canvas

    Привет Хабр!
    Сегодня я хочу рассказать о том, как написать простую логическую игру для Android OS с использованием Canvas. С этой игрой я познакомился около 5 лет назад на своем телефоне. Название забылось, а поиски на нескольких тематических форумах ни к чему не привели и я решил написать свою реализации этой игры. Разработка для меня скорее хобби, хотя иногда берусь за небольшие проекты. После некоторых раздумий я решил не использовать движок, а писать самостоятельно. Причины такого решения: желание получить опыт работы с Canvas'ом.

    Суть такова...



    Имеется игровое поле подобное шахматной доске, однако без деления клеток на черные и белые. Размер поля может быть произвольным, однако играть на поле меньше, чем 2х3 не имеет особого смысла. Мне нравится играть на поле 10х10.

    Количество игроков может произвольным, однако на мой взгляд интереснее играть вдвоем или вчетвером. Если играть втроем на прямоугольном поле, то возникает дисбаланс, поскольку один из игроков будет отдален от «пустого» угла. Если играть компанией больше, чем 4 человека, то сложно воплощать свою стратегию.

    Каждый игрок по очереди должен положить один объект (назовем его атомом) в свободную ячейку или в ячейку, где уже есть его атомы. Если в ячейке накапливается «критическая масса», равная числу соседних ячеек, то атомы из данной ячейки перемещаются в соседние ячейки, при этом находящиеся в соседних ячейках атомы «захватываются», т.е. теперь они принадлежат игроку, чьи атомы разлетелись.

    Пара картинок для пояснения сути.



    Пустое поле 4х4 с указанием критической массы для каждой ячейки.


    Игровая ситуация после третьего хода.


    Игровая ситуация после четвертого хода (первыми ходят синие). Видно, что в верхнем левом углу скопилось критическое количество атомов.


    Бах! Они разлетелись, захватив 2 синих атома в ячейке [0][1]. И в этой ячейке [0][1] теперь тоже критическое количество. Цепная реакция!


    Ситуация после разлета. Конец четвертого хода. Синие сейчас совершат пятый ход.


    Реализация. Графическая часть.



    Приступим к реализации. Создадим производный от View класс.
    public class GameView extends View {
    
        private Bitmap mBitmap;
        private Canvas mCanvas;
        private Paint paint, mBitmapPaint;
        private float canvasSize;
        private final int horizontalCountOfCells, verticalCountOfCells;
    
        public GameView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //размер игрового поля
            horizontalCountOfCells =10;
            verticalCountOfCells =10;
            //в xml разметке позднее пропишем размер вьюхи равный 300dp
            canvasSize=(int)convertDpToPixel(300, context);
    
            mBitmap = Bitmap.createBitmap((int) canvasSize, (int) canvasSize, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    
            //определяем параметры кисти, которой будем рисовать сетку и атомы
            paint =new Paint();
            paint.setAntiAlias(true);
            paint.setDither(true);
            paint.setColor(0xffff0505);
            paint.setStrokeWidth(5f);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeCap(Paint.Cap.ROUND);
    
            //рисуем сетку
            for(int x=0;x< horizontalCountOfCells +1;x++)
                mCanvas.drawLine((float)x* canvasSize / horizontalCountOfCells, 0, (float)x* canvasSize / horizontalCountOfCells, canvasSize, paint);
            for(int y=0;y< verticalCountOfCells +1;y++)
                mCanvas.drawLine(0, (float)y* canvasSize / verticalCountOfCells, canvasSize, (float)y* canvasSize / verticalCountOfCells, paint);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        }
    
        //переводим dp в пиксели
        public float convertDpToPixel(float dp,Context context){
            Resources resources = context.getResources();
            DisplayMetrics metrics = resources.getDisplayMetrics();
            return dp * (metrics.densityDpi/160f);
        }
    }
    


    Здесь я допустил немного говнокода кода плохого качества, а именно захардкордил в коде цвет линий, разделяющих ячейки игрового поля и размер вьюхи считается равным 300 dp. Этот размер можно получить из объекта attrs класса AttributeSet, однако не будем загромождать код.

    Также сразу набросаем Activity, дабы убедиться, что все рисуется красиво.

    public class GameActivity extends Activity {
     
        Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        }
    }
    


    И разметка main.xml

    <LinearLayout xmlns:android=«schemas.android.com/apk/res/android»
            android:orientation=«vertical»
            android:layout_width=«fill_parent»
            android:layout_height=«fill_parent»
            android:background="#aaa"
            android:gravity=«center_horizontal»>
    <com.devindi.chain.GameView
            android:layout_width=«300dp»
            android:layout_height=«300dp»
            android:id="@+id/game_view"
            android:layout_gravity=«center»
            android:background="#000"/>
    </LinearLayout>
    


    Код после этого этапа.

    Теперь добавим возможность изменять масштаб игрового поля, поскольку возможны промахи мимо нужной ячейки по причине их малого размера. Для этого переопределяем нужные нам методы реализации ScaleGestureDetector.SimpleOnScaleGestureListener интерфейса OnScaleGestureListener в нашем классе GameView.

        private final ScaleGestureDetector scaleGestureDetector;
        private final int viewSize;
        private float mScaleFactor;
     
        public GameView(Context context, AttributeSet attrs) {
           //в xml разметке позднее пропишем размер вьюхи равный 300dp
            viewSize=(int)convertDpToPixel(300, context);
            mScaleFactor=1f;//значение зума по умолчанию
            canvasSize=(int)(viewSize*mScaleFactor);//определяем размер канваса        
            …
            scaleGestureDetector=new ScaleGestureDetector(context, new MyScaleGestureListener());
    }
     
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.save();
            canvas.scale(mScaleFactor, mScaleFactor);//зумируем канвас
            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
            canvas.restore();
        }
    
        //в случае касания пальем передаем управление MyScaleGestureListener
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            scaleGestureDetector.onTouchEvent(event);
            return true;
        }
    
        //унаследовались от ScaleGestureDetector.SimpleOnScaleGestureListener, чтобы не писать пустую реализацию ненужных
        //методов интерфейса OnScaleGestureListener
        private class MyScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
            //обрабатываем "щипок" пальцами
            @Override
            public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
                float scaleFactor=scaleGestureDetector.getScaleFactor();//получаем значение зума относительно предыдущего состояния
                //получаем координаты фокальной точки - точки между пальцами
                float focusX=scaleGestureDetector.getFocusX();
                float focusY=scaleGestureDetector.getFocusY();
                //следим чтобы канвас не уменьшили меньше исходного размера и не допускаем увеличения больше чем в 2 раза
                if(mScaleFactor*scaleFactor>1 && mScaleFactor*scaleFactor<2){
                    mScaleFactor *= scaleGestureDetector.getScaleFactor();
                    canvasSize =viewSize*mScaleFactor;//изменяем хранимое в памяти значение размера канваса
                    //используется при расчетах
                    //по умолчанию после зума канвас отскролит в левый верхний угол.
                    //Скролим канвас так, чтобы на экране оставалась
                    //область канваса, над которой был жест зума
                    //Для получения данной формулы достаточно школьных знаний математики (декартовы координаты).
                    int scrollX=(int)((getScrollX()+focusX)*scaleFactor-focusX);
                    scrollX=Math.min( Math.max(scrollX, 0), (int) canvasSize -viewSize);
                    int scrollY=(int)((getScrollY()+focusY)*scaleFactor-focusY);
                    scrollY=Math.min( Math.max(scrollY, 0), (int) canvasSize -viewSize);
                    scrollTo(scrollX, scrollY);
                }
                //вызываем перерисовку принудительно
                invalidate();
                return true;
            }
        }
    


    Получившийся код

    Обратите внимание, что установлены границы значения увеличинения (увеличение будет на промежутке от 1 до 2), а также производится скролл игрового поля к точке зумирования (точка посередине между пальцами) с проверкой на показ области вне игрового поля. Скролл к точке зуммирования (фокальной точке) производится следующим образом — расчитывается координаты фокальной точки относительно начала канваса(верхний левый угол), умножаются на коэффициент зуммирования и вычитаются координаты точки относительно вьюхи. После этого берем ближайшее значение из промежутка [0, canvasSize -viewSize] для предотвращения скролла за пределы игрового поля.

    Теперь напишем обработку скролла, одиночного тапа и двойного тапа (двойной тап будет возвращать к исходному масштабу игрового поля).

        private final GestureDetector detector;
        public GameView(Context context, AttributeSet attrs) {
        ...
        detector=new GestureDetector(context, new MyGestureListener());
        }
    
        //в случае касания пальем передаем обработку Motion Event'а MyGestureListener'у и MyScaleGestureListener'у
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            detector.onTouchEvent(event);
            scaleGestureDetector.onTouchEvent(event);
            return true;
        }
    
    
        //унаследовались от GestureDetector.SimpleOnGestureListener, чтобы не писать пустую
        //реализацию ненужных методов интерфейса OnGestureListener
        private class MyGestureListener extends GestureDetector.SimpleOnGestureListener
        {
            //обрабатываем скролл (перемещение пальца по экрану)
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
            {
                //не даем канвасу показать края по горизонтали
                if(getScrollX()+distanceX< canvasSize -viewSize && getScrollX()+distanceX>0){
                    scrollBy((int)distanceX, 0);
                }
                //не даем канвасу показать края по вертикали
                if(getScrollY()+distanceY< canvasSize -viewSize && getScrollY()+distanceY>0){
                    scrollBy(0, (int)distanceY);
                }
                return true;
            }
    
            //обрабатываем одиночный тап
            @Override
            public boolean onSingleTapConfirmed(MotionEvent event){
                //получаем координаты ячейки, по которой тапнули
                int cellX=(int)((event.getX()+getScrollX())/mScaleFactor);
                int cellY=(int)((event.getY()+getScrollY())/mScaleFactor);
                return true;
            }
    
            //обрабатываем двойной тап
            @Override
            public boolean onDoubleTapEvent(MotionEvent event){
                //зумируем канвас к первоначальному виду
                mScaleFactor=1f;
                canvasSize =viewSize;
                scrollTo(0, 0);//скролим, чтобы не было видно краев канваса.
                invalidate();//перерисовываем канвас
                return true;
            }
        }    
    


    Получившийся код
    При одиночном тапе мы рассчитываем координаты ячейки, по которой тапнули, например верхняя левая ячейка будет иметь координаты 0,0.

    Напишем метод рисования атомов drawAtoms. параметры метода — координаты ячейки, в которой рисуем атомы, цвет и количество атомов.

            void drawAtoms(int cellX, int cellY, int color, int count){
            //считаем координаты центра ячейки
            float x0=((1f/(2* horizontalCountOfCells))*viewSize+(1f/ horizontalCountOfCells)*cellX*viewSize);
            float y0=((1f/(2* verticalCountOfCells))*viewSize+(1f/ verticalCountOfCells)*cellY*viewSize);
            paint.setColor(color);
            switch (count){
                //todo non-absolute values
                case 1:
                    drawAtoms(cellX, cellY, color, 0);//стираем существующие атомы
                    mCanvas.drawCircle(x0, y0, 3, paint);//рисуем один атом в центре ячейки
                    break;
                case 2:
                    drawAtoms(cellX, cellY, color, 0);
                    //рисуем пару атомов на удалении от центра ячейки
                    mCanvas.drawCircle(x0-7, y0, 3, paint);
                    mCanvas.drawCircle(x0+7, y0, 3, paint);
                    break;
                case 3:
                    drawAtoms(cellX, cellY, color, 0);
                    //рисуем три атома в вершинах правильного треугольника с центром в центре ячейки
                    mCanvas.drawCircle(x0 - 7, y0 + 4, 3, paint);
                    mCanvas.drawCircle(x0 + 7, y0 + 4, 3, paint);
                    mCanvas.drawCircle(x0, y0-8, 3, paint);
                    break;
                case 4:
                    drawAtoms(cellX, cellY, color, 0);
                    //рисуем 4 атом в вершинах квадрата с центром в центре ячейки
                    mCanvas.drawCircle(x0-7, y0-7, 3, paint);
                    mCanvas.drawCircle(x0-7, y0+7, 3, paint);
                    mCanvas.drawCircle(x0+7, y0+7, 3, paint);
                    mCanvas.drawCircle(x0+7, y0-7, 3, paint);
                    break;
                case 0:
                    //устанавливаем кисти режим стирания
                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                    //заполнение обойденного участка
                    paint.setStyle(Paint.Style.FILL);
                    //рисуем большой круг, на месте которого ничего не останется
                    mCanvas.drawCircle(x0, y0, 17, paint);
                    //возвращаем исходные параметры
                    paint.setStyle(Paint.Style.STROKE);
                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
                    break;
            }
            invalidate();//перерисовываем канвас
        }
    


    На данный момент метод имеет недоработку в виде абсолютных значений размеров атомов и расстояний между ними. К чему это может привести? При размере поля меньше, чем 10х10 атомы будут смотреться мелкими, а при большем размере поля могут не влезть в ячейку.

    Осталось добавить скроллбары. Этот процесс хорошо описан здесь habrahabr.ru/post/120931.

    Прежде чем приступить к описанию игровой логики добавим глобальную переменную типа GameLogic (наш класс, описывающий логику) с именем logic и добавим в метод обработки одиночного тапа onSingleTapConfirmed
    вызов будущего метода логической обработки добавления нового атома.
    logic.addAtom(cellX, cellY);
    Также необходим сеттер для этой переменной.

    Код.

    Реализация. Игровая логика.



    Создадим класс GameLogic, описывающий логику игры. Также нам понадобится внутренний класс Cell, хранящий параметры ячейки игрового поля.

        public class GameLogic {
        private class Cell{
             int player=0, countOfAtoms=0;//хозяин ячейки, количество атомов в ячейке
             final int maxCountOfAtoms;//емкость ячейки
         
             Cell(int maxCountOfAtoms){
                 this.maxCountOfAtoms=maxCountOfAtoms;
             }
         
             public int getCountOfAtoms() {
                 return countOfAtoms;
             }
         
             public int getPlayer() {
                 return player;
             }
         
             public void setPlayer(int player) {
                 this.player = player;
             }
         
             public void resetCount() {
                 this.countOfAtoms = 0;
             }
         
             public void addAtom(){
                 this.countOfAtoms++;
             }
         
             boolean isFilled(){
                 return this.countOfAtoms == this.maxCountOfAtoms;
             }
         }
        }
    


    Сам класс GameLogic

        private final GameView view;
        private final GameActivity activity;
        private int moveNumber=0, currentPlayer=0;
        private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
        private final Cell[][] cells;
    
        private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
        private final Handler mHandler;
    
        public GameLogic(GameView view, GameActivity activity) {
            this.view = view;
            this.activity=activity;
            mHandler=new Handler();
            //инициализируем игровые параметры (количество игроков, размер доски)
            this.COUNT_OF_PLAYERS=2;
            this.BOARD_HEIGHT=10;
            this.BOARD_WIDTH=10;
            cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
            for(int x=0; x<BOARD_WIDTH; x++){
                for(int y=0; y<BOARD_HEIGHT; y++){
                    if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
                        cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
                    }else
                    if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
                        cells[x][y]=new Cell(3);//краевые, но не угловые - 3
                    }else{
                        cells[x][y]=new Cell(4);//остальные - 4
                    }
                }
            }
        }
    
    
        //вызывается из вьюхи по одиночному тапу
        public void addAtom(final int cellX, final int cellY) {
            //получаем ячейку, в которую добавляем атом, если ее нет в массиве - выходим из функции.
            final Cell currentCell;
            try{
                currentCell=cells[cellX][cellY];
            }catch (IndexOutOfBoundsException ex){
                return;
            }
            //если в ячейке уже есть атомы этого игрока
            if(currentCell.getPlayer()==currentPlayer){
                currentCell.addAtom();
                view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
                //если ячейка заполнена
                if(currentCell.isFilled()){
                    final List<Cell> nearby=new ArrayList<Cell>(4);//лист соседних ячеек
                    selfAddCell(cellX, cellY-1, nearby);
                    selfAddCell(cellX, cellY+1, nearby);
                    selfAddCell(cellX-1, cellY, nearby);
                    selfAddCell(cellX+1, cellY, nearby);
                    for(Cell nearbyCell:nearby){
                        nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
                    }
                    delayedAddAtom(cellX, cellY-1);
                    delayedAddAtom(cellX, cellY+1);
                    delayedAddAtom(cellX-1, cellY);
                    delayedAddAtom(cellX+1, cellY);
                    //через секунду произойдет вызов метода run()
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            //текущая ячейка становится нейтральной (ничейной)
                            currentCell.setPlayer(-1);
                            //и пустой
                            currentCell.resetCount();
                            view.drawAtoms(cellX, cellY, 0x000000, 0);
                        }
                    }, 1000);
                    return;
                }
            }else if(currentCell.getPlayer()==-1){
                currentCell.addAtom();
                view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
                currentCell.setPlayer(currentPlayer);
            }else{
                return;
            }
        }
    
        //через секунду соседние ячйки получат по атому
        private void delayedAddAtom(final int cellX, final int cellY){
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    addAtom(cellX, cellY);
                }
            }, 1000);
        }
    
    
        //добавляем в лист target существующие ячейки
        private void selfAddCell(int cellX, int cellY, List<Cell> target){
            try{
                target.add(cells[cellX][cellY]);
            }catch (IndexOutOfBoundsException ignore){}
        }    
    


    Код.

    Здесь мы видим конструктор, который создает двумерный массив объектов Cell и метод addAtom, вызываемый из вьюхи по одиночному тапу и из себя при условии что ячейка наполнена атомами под завязку.
    Теперь можно добавлять атомы в ячейки, а при накоплении в ячейке критического количества атомов они разлетятся в стороны через секунду. Однако сейчас во время этой секунды можно добавлять атомы. Избавимся от этого, добавив переменную-флаг isLock и методы isLock(), lock() и unlock() в класс GameView.

    Также необходимо добавить смену игрока после хода, подсчет очков и обработку конца игры (когда все атомы принадлежат одному игроку и каждый игрок совершил как минимум 1 ход).
    Добавим в конец метода addAtom() следующий код

            int[] score=scoring();
            if(moveNumber==0){
                endTurn(score);
            }else {
                //проверка на конец игры. Нельзя делать в теле метода endTurn() потому что
                //не определим конец игры при бесконечной реакции
                int losersCount=0;
                for(int i=0; i<COUNT_OF_PLAYERS; i++){
                    if(score[i]==0)
                        losersCount++;
                }
                if(losersCount+1==COUNT_OF_PLAYERS){
                    isEndGame=true;
                }
                if(!mHandler.hasMessages(0)){
                    view.unlock();
                    endTurn(score);
                }
            }
        }
    
        //обработка конца хода
        private void endTurn(int[] score){
            if(!isEndGame){
                if(currentPlayer == COUNT_OF_PLAYERS-1){
                    moveNumber++;
                    currentPlayer=0;
                }else {
                    currentPlayer++;
                }
            }else{
                activity.endGame(currentPlayer, score[currentPlayer]);
            }
            //извещаем активити, о том, что поменялся счет, текущий игрок и номер хода
            activity.setMoveNumber(moveNumber);
            activity.setPlayerName(currentPlayer);
            activity.setScore(score);
    
        }
    
        //подсчет очков
        int[] scoring(){
            int[] score=new int[COUNT_OF_PLAYERS];
            for(int x=0; x<BOARD_WIDTH; x++){
                for(int y=0; y<BOARD_HEIGHT; y++){
                    if(cells[x][y].getPlayer()!=-1){
                        score[cells[x][y].getPlayer()]+=cells[x][y].getCountOfAtoms();
                    }
                }
            }
            return score;
        }
    


    Весь код
    Осталось написать реализацию методов
         void setPlayerName(int playerID){}
    
        void setScore(int[] score){}
    
        void setMoveNumber(int moveNumber){}
    
        void endGame(int winnerID, int score){} 
    


    Это будет домашним заданием. Тут все тривиально.

    После сборки обработать напильником



    Далее требуется небольшое допиливание получившегося приложения в виде создания Activity для настройки игры (размер игрового поля, количество игроков, цвет атомов и имена игроков, однако это не тема данной статьи. Итоговый код можно посмотреть на гитхабе, получившуюся игру попробовать на Google Play

    Надеюсь, кому-нибудь статья поможет.
    Прошу большими камнями не кидаться. Осознаю низкое качество кода и обещаю стремиться избегать говнокода. Спасибо за внимание.

    P.S. Это моя первая статья на хабре.
    • +26
    • 51k
    • 7
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 7

      0
      >> Прошу большими камнями не кидаться. Осознаю низкое качество кода и обещаю стремиться избегать говнокода. Спасибо за внимание.
      >> P.S. Это моя первая статья на хабре.

      Все когда-то с этого начинали. Ну, за исключением Ализароподобных, у которых, с рождения новости в крови… А так, you're welcome… :)
        0
        Для игры лучше использовать SurfaceView, тогда весь вывод на экран можно вынести в отдельный поток.
          0
          А зачем? Есть же вполне устоявшийся вариант game loop'a со смещением, который зачастую (если умеем грамотно воспользоваться этим смещением) будет работать лучше.
          Я про последнюю реализацию туточки.
          0
          идея игры очень напоминает одну из моих любимых игр — гексагон
          помню, еще на вин98 через дос играл в нее :)
          недавно, вот попалась флеш-реализация — vk.com/app1922887
            0
            >> Название забылось, а поиски на нескольких тематических форумах ни к чему не привели
            Она? play.google.com/store/apps/details?id=uk.co.stevebosman.criticalmass.android
              0
              Суть та же. Видел еще один аналог для андроида, но с дополнениями. Сам играл на платформе J2ME леть пять назад.
              0
              Заголовок

              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){
              nearbyCell.setPlayer(currentPlayer);//соседним ячейкам устанавливаем нового владельца
              }
              delayedAddAtom(cellX, cellY-1);
              delayedAddAtom(cellX, cellY+1);
              delayedAddAtom(cellX-1, cellY);
              delayedAddAtom(cellX+1, cellY);
              //через секунду произойдет вызов метода run()
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              //текущая ячейка становится нейтральной (ничейной)
              currentCell.setPlayer(-1);
              //и пустой
              currentCell.resetCount();
              view.drawAtoms(cellX, cellY, 0x000000, 0);
              }
              }, 1000);
              return;
              }
              }else if(currentCell.getPlayer()==-1){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              currentCell.setPlayer(currentPlayer);
              }else{
              return;
              }
              }

              //через секунду соседние ячйки получат по атому
              private void delayedAddAtom(final int cellX, final int cellY){
              mHandler.postDelayed(new Runnable() {
              Override
              public void run() {
              addAtom(cellX, cellY);
              }
              }, 1000);
              }

              //добавляем в лист target существующие ячейки
              private void selfAddCell(int cellX, int cellY, List target){
              try{
              target.add(cells[cellX][cellY]);
              }catch (IndexOutOfBoundsException ignore){}
              }
              private final GameView view;
              private final GameActivity activity;
              private int moveNumber=0, currentPlayer=0;
              private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT;
              private final Cell[][] cells;

              private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};//цвета атомов
              private final Handler mHandler;

              public GameLogic(GameView view, GameActivity activity) {
              this.view = view;
              this.activity=activity;
              mHandler=new Handler();
              //инициализируем игровые параметры (количество игроков, размер доски)
              this.COUNT_OF_PLAYERS=2;
              this.BOARD_HEIGHT=10;
              this.BOARD_WIDTH=10;
              cells=new Cell[BOARD_WIDTH][BOARD_HEIGHT];
              for(int x=0; x<BOARD_WIDTH; x++){
              for(int y=0; y<BOARD_HEIGHT; y++){
              if((x==0 || x==BOARD_WIDTH-1) && (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(2);//угловые ячейки имеют емкость 2
              }else
              if((x==0 || x==BOARD_WIDTH-1) || (y==0 || y==BOARD_HEIGHT-1)){
              cells[x][y]=new Cell(3);//краевые, но не угловые — 3
              }else{
              cells[x][y]=new Cell(4);//остальные — 4
              }
              }
              }
              }

              //вызывается из вьюхи по одиночному тапу
              public void addAtom(final int cellX, final int cellY) {
              //получаем ячейку, в которую добавляем атом, если ее нет в массиве — выходим из функции.
              final Cell currentCell;
              try{
              currentCell=cells[cellX][cellY];
              }catch (IndexOutOfBoundsException ex){
              return;
              }
              //если в ячейке уже есть атомы этого игрока
              if(currentCell.getPlayer()==currentPlayer){
              currentCell.addAtom();
              view.drawAtoms(cellX, cellY, colors[currentPlayer], currentCell.getCountOfAtoms());
              //если ячейка заполнена
              if(currentCell.isFilled()){
              final List nearby=new ArrayList(4);//лист соседних ячеек
              selfAddCell(cellX, cellY-1, nearby);
              selfAddCell(cellX, cellY+1, nearby);
              selfAddCell(cellX-1, cellY, nearby);
              selfAddCell(cellX+1, cellY, nearby);
              for(Cell nearbyCell:nearby){

              Only users with full accounts can post comments. Log in, please.