miércoles, 16 de diciembre de 2015

Juego de Ajedrez (II). Creando la estructura del proyecto

Artículos anteriores:
Juego de Ajedrez (I). Introducción a la Programación Orientada a Objetos

El código completo tanto en C# como en Visual Basic .NET está disponible en:

Códigos de muestra - Ejemplos MSDN. Juego de Ajedrez

Tras hacer un resumen de lo que iremos viendo a lo largo de los diferentes artículos, vamos a meternos en harina creando el proyecto y la estructura básica de clases que encapsularán la funcionalidad de nuestro juego de ajedrez.
En primer lugar vamos a crear un nuevo proyecto Windows Forms llamado ChessGame:

Nuevo proyecto Windows Forms

En este primer artículo vamos a crear la estructura de clases que implementarán la funcionalidad de los diferentes elementos del juego, así que por ahora nos limitaremos a renombrar el formulario por defecto Form1 que crea Visual Studio por ChessGameForm.

Para definir las diferentes clases crearé una nueva carpeta Model en el proyecto y, dentro de ésta, tres archivos de código: Chess.cs/Chess.vb (que contendrá la funcionalidad de la partida), Chessboard.cs/Chessboard.vb (que contendrá la funcionalidad del tablero) y Pieces.cs/Pieces.vb (que contendrá las clases que encapsulan la funcionalidad de las diferentes piezas).

Crear archivo de código

En primer lugar crearé dos enumeraciones en el archivo Chess.cs/Chess.vb: la enumeración PlayerColor define los diferentes colores de los jugadores (blanco o negro) y la enumeración GameState define los diferentes estados en que puede encontrarse la aplicación.

    enum PlayerColor
    {
        White, Black
    }

    enum GameState
    {
        PendingForWhiteMove,
        PendingForBlackMove,
        WhitePlayerMoving,
        BlackPlayerMoving,
        WhitePlayerWin,
        BlackPlayerWin
    }
Enum PlayerColor
    White
    Black
End Enum

Enum GameState
    PendingForWhiteMove
    PendingForBlackMove
    WhitePlayerMoving
    BlackPlayerMoving
    WhitePlayerWin
    BlackPlayerWin
End Enum


En el archivo Pieces.cs/Pieces.vb crearé una clase abstracta ChessPiece que servirá como clase base para las diferentes piezas del juego.

Una clase abstracta es una clase a partir de la cual no pueden crearse instancias. Su propósito es crear una definición común que puedan compartir las clases derivadas.

En este caso definiremos en la clase ChessPiece la funcionalidad que deben compartir todas las piezas del juego de ajedrez, de forma que este comportamiento común esté definido en un único lugar. Para definir el comportamiento particular de una pieza crearemos una clase derivada de ChessPiece que heredará todo el comportamiento común y en el que definiremos ese comportamiento personalizado.

En esta clase base voy a definir dos propiedades:

  • Color: de tipo PlayerColor y que definirá el color de la pieza
  • BoardSquare: de tipo Square (que crearemos a continuación) y que devolverá la celda en la que se encuentra posicionada la pieza
Un método:
  • GetDestinationSquares: que devolverá una enumeración de las celdas a las que se puede mover la pieza. Como estas celdas dependen del tipo de pieza de que se trata no implementaré ninguna funcionalidad en la clase Piece si no que la funcionalidad del método deberá definirse en cada una de las clases derivadas. Es lo que se denomina un método abstracto y debe marcarse con la palabra reservada abstract (en C#) o MustOverride (en VB)
Y un constructor que recibirá como argumento el color de la pieza.


    abstract class ChessPiece
    {

        public ChessPiece(PlayerColor color)
        {
            Color = color;
        }

        public PlayerColor Color { get; set; }

        public Square BoardSquare { get; internal set; }

        public abstract IEnumerable<Square> GetDestinationSquares();

    }
MustInherit Class ChessPiece

    Public Sub New(pieceColor As PlayerColor)
        Color = pieceColor
    End Sub

    Property Color As PlayerColor

    Property BoardSquare As Square

    Public MustOverride Function GetDestinationSquares() As IEnumerable(Of Square)

End Class




En el archivo Chessboard.cs/Chessboard.vb definiré las clases Square, que definirá una celda del tablero, y Chessboard, que definirá el tablero.

En la clase Square definiré cuatro propiedades:

  • Board: que mantendrá una referencia al tablero al que pertenece la celda
  • Row y Col: que devolverán la fila y columna a las que corresponde la celda
  • Piece: que contendrá una referencia a la pieza que se encuentra en la celda
Y un constructor que recibirá el tablero al que pertenece la celda y su número de fila y columna.



    class Square
    {

        public Square(Chessboard board, int row, int column)
        {
            Board = board;
            Row = row;
            Column = column;
        }

        public Chessboard Board { get; set; }

        public int Row { get; set; }

        public int Column { get; set; }

        public ChessPiece Piece { get; set; }

    }
Class Square

    Public Sub New(squareBoard As Chessboard, squareRow As Integer, squareColumn As Integer)
        Board = squareBoard
        Row = squareRow
        Column = squareColumn
    End Sub

    Property Board As Chessboard

    Property Row As Integer

    Property Column As Integer

    Property Piece As ChessPiece

End Class

La clase Chessboard que define el tablero será básicamente una colección de celdas por lo que heredará del objeto List<Square>.
Además definirá una propiedad:

  • PlayerOnTop: que especificará el color del jugador cuyas piezas se colocarán en la parte superior del tablero
Un método:
  • GetSquare: que devolverá la celda correspondiente a la fila y columna pasadas como argumentos
Y un constructor en el que inicializaré el tablero creando las 64 celdas y estableciendo por defecto al jugador blanco como jugador para la parte superior del tablero.

    class Chessboard : List<Square>
    {

        public Chessboard()
        {
            for (int row = 0; row < 8; row++)
            {
                for (int column = 0; column < 8; column++)
                    Add(new Square(this, row, column));
            }
            PlayerOnTop = PlayerColor.White;
        }

        public PlayerColor PlayerOnTop { get; set; }

        public Square GetSquare(int row, int column)
        {
            return this.FirstOrDefault(s => s.Row == row && s.Column == column);
        }

    }
Class Chessboard
    Inherits List(Of Square)

    Public Sub New()
        For row = 0 To 7
            For column = 0 To 7
                Add(New Square(Me, row, column))
            Next
        Next
        PlayerOnTop = PlayerColor.White
    End Sub

    Property PlayerOnTop As PlayerColor

    Public Function GetSquare(row As Integer, column As Integer) As Square
        Return Me.FirstOrDefault(Function(s) s.Row = row AndAlso s.Column = column)
    End Function

End Class

Por último, en el archivo Chess.cs/Chess.vb crearé la clase Game que mantendrá el estado de la partida. Por ahora únicamente voy a crear dos propiedades:

  • Board: que permitirá acceder al tablero de la partida
  • State: que contendrá el estado actual de la partida
Y un constructor que creará el tablero de juego.

    class Game
    {

        public Game()
        {
            Board = new Chessboard();
        }

        public Chessboard Board { get; private set; }

        public GameState State { get; set; }

    }
Class Game

    Public Sub New()
        _board = New Chessboard()
    End Sub

    Private _board As Chessboard
    Public Property Board() As Chessboard
        Get
            Return _board
        End Get
        Private Set(ByVal value As Chessboard)
            _board = value
        End Set
    End Property

    Private _state As GameState
    Public Property State() As GameState
        Get
            Return _state
        End Get
        Private Set(ByVal value As GameState)
            _state = value
        End Set
    End Property

End Class

Una vez definida la estructura básica, en las próximas entradas continuaré ampliando la funcionalidad de cada una de ellas.


Artículo siguiente:
Juego de Ajedrez (III). Definiendo las piezas

2 comentarios:

  1. Hola, Asier, disculpa que te moleste, antes que nada, Feliz Navidad.......Quiero consultarte, si sabes y es posible sobre lo siguiente:

    Cuando selecciono una fila de GridView, los datos de esas filas pasan a otro webForm, a unos textBox.....Todos se llenan, y hay 4 de Ellos Enabled=true..........Lo que sucede es que uno de ellos no se llena, y me da un Error, porque luego de operar los que si se pueden se guardan en Base de Datos.

    Que sucede que no se llena ese TextBox?.......

    Si sabes algo, podrias ayudarme??

    Abrazo nos vemos...

    ResponderEliminar
    Respuestas
    1. Hola Guillermo,
      es difícil saber lo que sucede sin ver el código.

      Para estos casos lo mejor es que plantees el problema en los foros de msdn:
      Msdn foros

      De esta forma tanto yo como los compañeros que colaboran habitualmente en los foros podremos ayudarte mejor.

      Un saludo y feliz año.

      Eliminar