some image

Codes and Tags

Tic-Tac-Toe usando AngularJS

Etiquetas: , Blog, Web No comments

Estoy seguro que todos alguna vez en la vida llegamos a jugar este famoso Tic-Tac-Toe o Triqui, sobre un pedazo de papel mientras estábamos en el colegio o aburridos. Bien, aprovechando mi self-study que estoy haciendo con Angular decidí aprender jugando 😛 , así que acá traigo el juego de Tic-Tac-Toe usando AngularJS.

1. Introducción

Según la definición de Wikipedia este juego se define como :

Es unjuego de lápiz y papel entre dos jugadores: O y X, que marcan los espacios de un tablero de 3×3 alternadamente. Un jugador gana si consigue tener una línea de tres de sus símbolos: la línea puede ser horizontal, vertical o diagonal.

2. Estructura de archivos

La estructura de archivos de elaboró de la siguiente manera :

Estructura de archivos

Estructura de archivos

 

  • index.html => Archivo principal
  • css => Estilos y Bootstrap
  • js => Lógica del juego en JavaScript y angular, librerias de angularJS, jQuery y bootstrap.
  • fonts => Fuentes para manejar estilos más interesantes.
  • img => Para almacenar imagenes en caso de que se quiera tener una interfaz más agradable.

 

3. Creando el tablero

Para crear el tablero, decidí utilizar la directiva de angularJS ng-repeat la cuál nos permite iterar los elementos de una lista o arreglo de datos. Adicionalmente sobre los botones, es necesario utilizar la directiva ng-click y ng-disabled, para generar el evento cuando se pulsa click y bloquear el botón cuando ya ha hecho un movimiento.

 

4. Creando el Objeto de juego

Para manejar la lógica en el juego, decidí utilizar un objeto en JavaScript con expresiones anonimas (Funciones) que me permitieran conocer estados y validaciones del objeto en cuestión. El objeto TicTacToe, es la representación de una clase en JavaScript con sus atributos y métodos. 😀

 

var TicTacToe = function(){
        this.title = "Tic Tac Toe";
        this.activePlayer = null;
        this.winner = null;
        this.draw = true;
        this.movements = null;
        this.players=[
            {name: "Player 1", symbol:"X", movements : []},
            {name: "Player 2", symbol:"O", movements : []}
        ];
        this.solutions = [
            [1,2,3],   [4,5,6],   [7,8,9], // Horizontals
            [1,4,7],   [2,5,8],   [3,6,9], // Verticals
            [1,5,9],   [7,5,3]    // Diagonals
        ];
        this.board ={
            rows:[
                [
                    {id: 1, value: "", isChecked:false},
                    {id: 2, value: "", isChecked:false},
                    {id: 3, value: "", isChecked:false}
                ],
                [
                    {id: 4, value: "", isChecked:false},
                    {id: 5, value: "", isChecked:false},
                    {id: 6, value: "", isChecked:false}
                ],
                [
                    {id: 7, value: "", isChecked:false },
                    {id: 8, value: "", isChecked:false},
                    {id: 9, value: "", isChecked:false}
                ]
            ]
        };
        this.fillBox = function(id){
            for(var i = 0; i < this.board.rows.length; i++){
                for(var k = 0; k < this.board.rows[i].length; k++){
                    if(this.board.rows[i][k].id == id){
                        if(this.activePlayer == null){
                            this.activePlayer = this.players[0];
                        }else{
                            if(this.activePlayer.name == this.players[0].name){
                                this.players[0].movements.push(id);
                                this.verifyGame(this.players[0]);
                                this.activePlayer = this.players[1];
                            }else{
                                this.players[1].movements.push(id);
                                this.verifyGame(this.players[1]);
                                this.activePlayer = this.players[0];
                            }
                        }
                        this.board.rows[i][k].value = this.activePlayer.symbol;
                        this.board.rows[i][k].isChecked = true;
                    }
                }
            }
        };
        this.verifyGame =function(player){
            var totalMovements = (this.players[0].movements.length + this.players[1].movements.length);
            if(totalMovements == this.board.rows.length * this.board.rows[0].length){
                this.draw = false;
            }else{
                for(var i = 0; i < this.solutions.length; i++){
                    var isSolution = true;
                    for(var k = 0; k < this.solutions[i].length; k++){
                        isSolution &= (player.movements.indexOf(this.solutions[i][k]) != -1);
                    }
                    if(isSolution){
                        this.winner = player.name;
                        this.movements = player.movements.length;
                        this.highLightSolution(this.solutions[i]);
                    }
                }
            }
        };
        this.highLightSolution = function(solution){
            for(var i = 0; i < solution.length; i++){
                var button = $("button")[solution[i] - 1];
                $(button).addClass("solution-check");
            }
        }
    };

 

De esta manera, cada vez que se necesario iniciar un nuevo juego o crear una instancia desde nuestro código en angularJS, simplemente nos limitamos a escribir algo como esto.

 

var app = angular.module('ticTacToe', []);
    app.controller('GameController', function(){
        this.game = new TicTacToe();
        this.game.activePlayer = this.game.players[0];
        this.newGame = function(){
            this.game = new TicTacToe();
            this.game.activePlayer = this.game.players[0];
        }
    });

5. Verificando cuando un jugador gana o empata el juego

Para determinar cuando un jugador gana o empata el juego, se hace a partir de la cantidad de movimientos jugados y las posibles soluciones para el juego. Es por eso que he creado un arreglo de soluciones y he contado la cantidad de movimientos para verificar dichas situaciones.

this.solutions = [
            [1,2,3],   [4,5,6],   [7,8,9], // Horizontals
            [1,4,7],   [2,5,8],   [3,6,9], // Verticals
            [1,5,9],   [7,5,3]    // Diagonals
        ];

this.verifyGame =function(player){
            var totalMovements = (this.players[0].movements.length + this.players[1].movements.length);
            if(totalMovements == this.board.rows.length * this.board.rows[0].length){
                this.draw = false;
            }else{
                for(var i = 0; i < this.solutions.length; i++){
                    var isSolution = true;
                    for(var k = 0; k < this.solutions[i].length; k++){
                        isSolution &= (player.movements.indexOf(this.solutions[i][k]) != -1);
                    }
                    if(isSolution){
                        this.winner = player.name;
                        this.movements = player.movements.length;
                        this.highLightSolution(this.solutions[i]);
                    }
                }
            }
        };

 

6. Resaltando la solución

Para resaltar la solución, simplemente utilicé una clase en css y una busqueda de los botones con jQuery, identificando que posiciones pertenecian a la posición correspondiente del tablero inicial.

.solution-check{
    background-color: #c1e2b3;
}

 

this.highLightSolution = function(solution){
            for(var i = 0; i < solution.length; i++){
                var button = $("button")[solution[i] - 1];
                $(button).addClass("solution-check");
            }
        }

7. Resultado

Acá se muestran algunas  imágenes del resultado final 😀 .

Winner Tic Tac Toe Game

Winner Tic Tac Toe Game

Draw Tic Tac Toe Game

Draw Tic Tac Toe Game

Tic Tac Toe Game

Tic Tac Toe Game

 

Jugar Tic Tac Toe (Demo)

8. Código fuente

Git Logo

Git Logo

About Edwin Torres

Related Posts

  • AngularJS Logo
  • JavaScript Logo
  • JavaScript 5
  • JavaScript 5

Add your comment