ALGORITMOS

DEFINICIÓN

Consiste en aplicar adecuadamente una serie de pasos detallados que aseguran una solución correcta. Por lo general, cada algoritmo es específico de un dominio del conocimiento.

Mientras mas detalles podamos ver, nuestro programa sera mas preciso, te muestro dos ejemplos prácticos, situaciones comunes que hemos hecho probablemente todos.

EJEMPLO 1 


Un procedimiento que realizamos varias veces al día consiste en lavarnos los dientes. Veamos la forma de expresar este procedimiento como un Algoritmo:  

1. Tomar la crema dental  
2. Destapar la crema dental 
3. Tomar el cepillo de dientes 
4. Aplicar crema dental al cepillo 
5. Tapar la crema dental 
6. Abrir la llave del lavamanos 
7. Remojar el cepillo con la crema dental 
8. Cerrar la llave del lavamanos 
9. Frotar los dientes con el cepillo 
10. Abrir la llave del lavamanos 
11. Enjuagarse la boca 
12. Enjuagar el cepillo 
13. Cerrar la llave del lavamanos 
14.  Secarse la cara y las manos con una toalla


EJEMPLO 2

El ejemplo de cambiar una bombilla (foco) fundida es uno de los más utilizados por su sencillez para mostrar los pasos de un Algoritmo: 

1. Ubicar una escalera debajo de la bombilla fundida 
2. Tomar una bombilla nueva 
3. Subir por la escalera 
4. Girar la bombilla fundida hacia la izquierda hasta soltarla 
5. Enroscar la bombilla nueva en el plafón hasta apretarla 
6. Bajar de la escalera 
7. Fin 

Estos 2 ejercicios pueden ser aun mas precisos, has la prueba desde tu punto de vista y mejoralo.

Caracteristicas

un Algoritmo debe ser:  

•  Realizable: El proceso algorítmico debe terminar después de una cantidad finita de pasos. Se dice que un algoritmo es inaplicable cuando se ejecuta  con un conjunto de datos iniciales y el proceso resulta infinito o durante la ejecución se encuentra con un obstáculo insuperable sin arrojar un resultado. 

•  Comprensible: Debe ser claro lo que hace, de forma que quien ejecute los pasos (ser humano o máquina) sepa qué, cómo y cuándo hacerlo. Debe existir un procedimiento que determine el proceso de ejecución.  

•  Preciso: El orden de ejecución de las instrucciones debe estar perfectamente indicado. Cuando se ejecuta varias veces, con los mismos datos iniciales, el resultado debe ser el mismo siempre. La precisión implica determinismo.

Pasos para realizar un algoritmo


1. COMPRENDER EL PROBLEMA.

•  Leer el problema varias veces
•  Establecer los datos del problema
•  Aclarar lo que se va a resolver (¿Cuál es la pregunta?)
•  Precisar el resultado que se desea lograr
•  Determinar la incógnita del problema
•  Organizar la información
•  Agrupar los datos en categorías
•  Trazar una figura o diagrama. 

2. HACER EL PLAN.

•  Escoger y decidir las operaciones a efectuar. 
•  Eliminar los datos inútiles. 
•  Descomponer el problema en otros más pequeños. 

3. EJECUTAR EL PLAN (Resolver).

•  Ejecutar en detalle cada operación. 
•  Simplificar antes de calcular. 
•  Realizar un dibujo o diagrama 

4. ANALIZAR LA SOLUCIÓN (Revisar).

•  Dar una respuesta completa 
•  Hallar el mismo resultado de otra manera. 
•  Verificar por apreciación que la respuesta es adecuada.





Sentencias

Una sentencia es cada uno de los pasos que componen un algoritmo. Hay que distinguir entre:
  1. sentencias simples: son una única instrucción;
  2. sentencias de control: están conformadas por varias otras sentencias, que a su vez pueden ser simples o compuestas.
Las sentencias simples son realizadas secuencialmente, una después de la otra. Más abajo veremos los dos tipos de sentencias de control: los condicionales y los ciclos.

Expresiones y variables

Una expresión es una combinación de valores y operaciones que son evaluados durante la ejecución del algoritmo para obtener un resultado.
Por ejemplo, 2 + 3 es una expresión aritmética que, al ser evaluada, siempre entrega el valor 5 como resultado. En esta expresión, 2 y 3 son valores literales y + es el operador de adición.
En el algoritmo para resolver la ecuación cuadrática aparece la expresión   4ac, cuyo resultado depende de cuáles son los valores de ab y c al momento de la evaluación. A diferencia de los valores literales, ab y c son variables. Una variable es un nombre que es asociado a un valor, para poder usarlo de manera independiente al valor específico que representa.
Las diferentes partes de una expresión también son expresiones por sí solas. En el ejemplo, b4ac y 4 son expresiones.

Asignaciones

Cuando una expresión es evaluada, generalmente es necesario asociar el resultado a una variable para poder referirse a él en sentencias posteriores. 
La acción de guardar un valor y ponerle un nombre se representa como una sentencia simple llamada asignación,
Una asignación se representa así:
variable = expresión
La asignación debe interpretarse así:
  1. primero la expresión a la derecha del signo = es evaluada, utilizando los valores que tienen las variables ab y c en ese momento;
  2. una vez obtenido el resultado, el valor de la variable a la izquierda del signo = es reemplazado por ese resultado.
Bajo esta interpretación, es perfectamente posible una asignación como ésta:
i = i + 1
Primero la expresión i + 1 es evaluada, entregando como resultado el sucesor del valor actual de i. A continuación, la variable i toma el nuevo valor. Por ejemplo, si itiene el valor 15, después de la asignación tendrá el valor 16.
Esto no significa que 15 = 16. Una asignación no es una igualdad matemática o una ecuación.

Condicionales

A veces un algoritmo debe ejecutar sentencias diferentes dependiendo de si una condición se cumple o no. Es lo que hacemos en el paso 3 del ejemplo: decidimos que la ecuación no tiene soluciones solamente cuando se cumple que Δ < 0. Esto se llama un condicional.
Un condicional es una sentencia compuesta.
La condición que determina qué ejecutar es una expresión, cuyo valor debe ser verdadero o falso.

Ciclos

Un ciclo ocurre cuando un algoritmo ejecuta una serie de instrucciones varias veces.
Como un algoritmo no puede quedarse pegado, un ciclo debe tener además una condición de término.
Cada ejecución de un ciclo se llama iteración.
El ejemplo de la ecuación cuadrática no tiene ciclos.

Entrada

Cuando un algoritmo necesita recibir un dato, lo hace mediante una sentencia de entrada, que se encarga de poner el valor en la variable correspondiente.
Por ahora, para referirnos a la sentencia de entrada lo haremos simplemente como:
Leer variable
Durante la ejecución, esto significa que el dato es entregado por alguien y queda guardado en la variable.
En el ejemplo, la entrada ocurre en el paso 1, y puede ser representada así:
Leer a
Leer b
Leer c

Salida

Una vez que el algoritmo ha resuelto el problema para el que fue diseñado, debe entregar sus resultados como un mensaje. Por ahora, lo representaremos así:
Escribir mensaje
Si el mensaje es un texto literal, va entre comillas. Si es una variable, va sólo el nombre de la variable.
En el ejemplo, cuando no existen soluciones, la salida puede ser representada así:
Escribir 'No hay soluciones'
Cuando existe una única solución, se puede incluirla en el mensaje:
Escribir 'La solución única es ', x
Las notaciones que hemos introducido son útiles para describir un algoritmo de manera estructurada.
Cuando usamos esta notación de manera informal, se denomina pseudocódigo. En este caso, es posible tomarse ciertas libertades que hacen que el algoritmo más fácil de entender.

EJERCICIOS

1. A un trabajador le pagan segun sus horas y una tarifa de pago por
horas. si la cantidad de horas trabajadas es mayor a 40 horas. la
   tarifa se incrementa en un 50% para las horas extras. calcular el
   salario del trabajador dadas las horas trabajadas y la tarifa.

   variables: horas_trabajadas,tarifa,horas_extras,salario,tarifa_e
      inicio
        leer: horas_trabajadas,tarifa
              si: horas_trabajadas <= 40 entonces
                  salario <-- horas_trabajadas * tarifa
              si_no
                  tarifa_extra <-- tarifa + 0.50 * tarifa
                  horas_extras <-- horas_trabajadas - 40
                  salario <-- horas_extras * tarifa_extra + 40 *
                  tarifa
              fin_si
              imprimir: salario.
       fin

2. A un  trabajador le descuentan de su sueldo el 10% si su sueldo es
   menor o igual a 1000. por encima de 1000 y hasta 2000 el 5% del
   adicional, y por encima de 2000 el 3% del adicional. calcular el 
   descuento y sueldo neto que recibe el trabajador dado su sueldo.

   variables: sueldo,sueldo_neto,descuento
      inicio
        leer: sueldo
              si: sueldo <= 1000 entonces
                  descuento <-- sueldo * 0.1
              si_no
                 si: sueldo <= 2000 entonces
                     descuento <-- (sueldo - 1000) * 0.05 + 1000 * 0.1
                 si_no
                     descuento <-- (sueldo - 2000) * 0.03 + 1000 * 0.1
                 fin_si
                 imprimir: descuento.
       fin

3. Dado un monto calcular el descuento considerando que por encima de
   100 el descuento es el 10% y por debajo de 100 el descuento es el
   2%.

   variables: monto,descuento
      inicio
        leer: monto
              si: monto > 100 entonces
                  descuento <-- monto * 10 / 100
              si_no
                  descuento <-- monto * 2 / 100
              fin_si
              imprimir: monto, descuento
       fin

4. Dado un tiempo en segundos, calcular los segundos restantes que le
   correspondan para convertirse exactamente en minutos.

   variables: tiempo_seg,minutos,segundos
      inicio
        leer: tiempo_seg
              si minutos  <-- tiempo_seg div 60 entonces
                  segundos <-- tiempo_seg mod 60
       fin_si
              imprimir: minutos,segundos.
       fin 

5. Dado un tiempo en minutos, calcular los dias, horas y minutos que
   le corresponden.

   variables: tiempo,dias,horas,minutos
      inicio
        leer: tiempo
              si: dias <-- tiempo div 1440
                   x <-- tiempo mod 1440
                  horas <-- x div 60
                  minutos <-- x mod 60
                  imprimir: dias,minutos,horas
       fin_si
       fin     



6. Calcular mediante un algoritmo repetitivo la suma de los  N primeros números naturales.

     Inicio 
        Leer : N
              X<--1
              S<--0
              Mientras x<=N hacer
                   S<--s+1
                   X<--x+1
              Fin _ mientras
              Imprimir: s
     Fin


7. Modificar el ejercicio 1 para obtener la suma de los salarios de todos los trabajadores.

     Inicio
        Leer: N
             X<--1
             S<--0
             Mientras x<=N hacer
         Leer:h, t
         S<--h*t
              Imprimir s
              S<--s+s
              X<--x+1
             Fin _ mientras
             Imprimir: s
     Fin

8. Dada las horas trabajadas de una persona la tarifa de pago. 
   Calcular su salario e imprimirla.

     Inicio
       leer: h, t
            S<--h * t
            Imprimir: s
     fin

    (Para dos personas)

    inicio
      leer: h, t
           S<--h * t
           Imprimir s
      Leer: h, t
           S<--h * t
           Imprimir: s
    Fin

9. Dado N notas de un estudiante calcular:

   a) Cuantas notas tiene desaprobados.
   b) Cuantos aprobados.
   c) El promedio de notas.
   d) El promedio de notas aprobadas y desaprobadas.

   Inicio
   Leer: N
        X<--1
        Cd<--0
 NA <-0
 acum_desap <-0
 acum_ap  <- 0
 acum <- 0
        Mientras x<=N hacer
          Leer: not
            Si: not < 10.5 entonces
               CD<--cd+1
               acum_desap <- acum_desap + not
            Sino
  NA <- NA + 1
                acum_ap <- acum_ap + not
            fin _ si
     acum <- acum + not
            x<--x+1
        Fin _ mientras
 prom_ap <- acum_ap /NA
  prom_desap <- acum_desap/CD
 prom <- acum / N
        Imprimir: prom, prom_ap, prom_desap, NA, CD
    Fin


10. Dado un numero determinar la suma de sus dígitos.

    Inicio
      Leer: n
            S<--0
            Mientras n<>0 hacer
               R<--n mod 10
               S<--s + r
               N<--n div 10
            Fin _ mientras
            Imprimir: s
    Fin

11.Se trata de escribir el algoritmo que permita emitir la factura 
   correspondiente a una compra de un articulo determinado, del que 
   se adquieren una o varias unidades. El IVA es del 15% y si el precio    
   bruto ( precio venta mas IVA) es mayor de 50.00 pesetas se debe 
   realizar un descuento del 5%.

    Variables: precio, numeros de articulos(Nart), precio venta(Pv), descuento(d)
 Inicio 
  Leer precio, Nart
  Pv= Precio * Nart
  IVA= Pv * 0.15
  Pb= Pv + IVA
  Si Pb >= 50 entonces
   d= (Pb * 5)/100
  Sino
   d= 0
  Finsi
  Pl= Pb - d
  Escribir Pv, IVA, Pb,d, Pl
 Fin

12. Realizar un algoritmo que permita pedir 
    50 números naturales y determine e imprima cuantos son 
    pares, impares, positivos y negativos.

 variables:par(p), impares(im), positivos(pos), negativos(n) 
    Inicio
     p= 2
    in= 0
  pos.= 0
     n= 0
      Para  x= 1 hasta 50
           Leer n
  Si n mod 2= 0 entonces
                p= p + 1
  Sino
        in= in + 1
  Finsi
  Si n > 0 entonces
     Pos= pos + 1
  Sino
      n=  n + 1
  Finsi
      Fin_para
 Escribir p, in, pos, n
    Fin

13. Desarrollar un algoritmo para calcular e 
    imprimir el factorial de un número.

 variables: factorial(f). numero(n)
      Inicio
         f= 1
         Para x= 1 hasta n
    f = f * x
         Fin_para
         Escribir f
      Fin

14. Calcular la media de 100 números e imprimir su resultado.

 variables: suma(s), media
    Inicio
  s= 0
  x= 1
      Mientras x<= 100 hacer
 Leer n
  s = s + n
  x = x + 1
      Finmientras
  media = s /100
         Escribir media
    Fin
 
15. Calcular y visualizar la suma y el producto de los 
    números pares comprendidos entre 20 y 400 ambos  inclusive.

 variables: suma(s), producto(p)
       Inicio
                s = 0
                p = 1
                x = 20
          Mientras x<= 400 hacer
          s = s +1
         p = p *x
         x = x +1
          Finmientras
         Escribir s, p
       Fin
16.-Hacer un programa que al ingresar un número 
    de Amstrong nos escriba si es o no es un número de     
    amstrong, y si no es que indique que vuelva a intentar. 

 Variables número, número original, digito 

 INICIO
      LEER NÚMERO
          Numeró original
          Suma   0
          Mientras  NUMERO < > 0 hacer
              dijito <- digito  mod 10
              Suma <-  suma + dijito ^ 3
              Numero  <-  numero mod 10
            Si suma = Número _ original Entonces
               Escribir "es un numero de amstrong"
            Sino
               Escribir "no es un numero de amstrong, intente otra vez"
            Finsi
         Fin

17.-Hacer un programa que registre el nº de créditos de un alumno.
    *El número máximo de crédito es 25
    *Imprimir número de crédito y total de crédito.

    Variables crédito, numero_de_crédito
 Inicio
     total_de_crédito <- 0
        Leer crédito
          Si total_de_crédito + crédito  < = 25 entonces
              Total_de_crédito  <-   total_de_crédito + crédito
              Numero_de_crédito  <-  número_de_cedito + 1
          Fin si
          Imprimir Numero_de_crédito, crédito
         Fin
     
18.-Hacer un programa para escribir la primera vocal leída del teclado.
    *Se supone que se leen, uno a uno, carácter desde el teclado

 Variables vocal
        Carácter  J
        Inicio
         sw = 1
         Mientras sw = 1 hacer
           Leer J
           si (J= "a") o (J = "e")  o (J = "i") o (J = "o") o (J ="u")
               Escribir "LA PRIMERA VOCAL INGRESADA FUE",J
   sw <- 0 
    fin_si
          Fin_mientras       
        Fin
19.-Hacer un programa que no determine un numero 
    tiene o no parte fraccionaria.

 Variables  parte_fracciomaria
        Real   n
        Inicio
            Escribir "ingresa numero"
            Leer n
           Si n = trunc(n) entonces     // trunc es una funcion 
     // que elimina los decimales de un numero

               Escribir "numero no tiene parte fraccionaria"
             Sino
           Escribir" numero con parte fraccionaria"
           fin si
        Fin 
ENLACE DE INTERES
http://www.eduteka.org/pdfdir/AlgoritmosProgramacion.pdf
Archivo pdf con la informacion completa de esta entrada.

DIAGRAMAS DE FLUJO

Descargar aqui


Introducción.
Los diagramas de flujo son una manera de representar visualmente el flujo de datos a travéz de sistemas de tratamiento de información. Los diagramas de flujo describen que operaciónes y en que secuencia se requieren para solucionar un problema dado.
Un diagrama de flujo u organigrama es una representación diagramática que ilustra la secuencia de las operaciones que se realizarán para conseguir la solución de un problema. Los diagramas de flujo se dibujan generalmente antes de comenzar a programar el código frente a la computadora. Los diagramas de flujo facilitan la comunicación entre los programadores y la gente del negocio. Estos diagramas de flujo desempeñan un papel vital en la programación de un problema y facilitan la comprensión de problemas complicados y sobre todo muy largos. Una vez que se dibuja el diagrama de flujo, llega a ser fácil escribír el programa en cualquier idióma de alto nivel. Vemos a menudo cómo los diagramas de flujo nos dan ventaja al momento de explicar el programa a otros. Por lo tanto, está correcto decir que un diagrama de flujo es una necesidad para la documentación mejor de un programa complejo.
Reglas para dibujar un diagramas de flujo.
Los Diagramas de flujo se dibujan generalmente usando algunos símbolos estándares; sin embargo, algunos símbolos especiales pueden también ser desarrollados cuando séan requeridos. Algunos símbolos estándares, que se requieren con frecuencia para diagramar programas de computadora se muestran a continuación:
Inicio o fin del programa
Pasos, procesos o líneas de instruccion de programa de computo
Operaciones de entrada y salida
Toma de desiciónes y Ramificación
Conector para unir el flujo a otra parte del diagrama
Cinta magnética
Disco magnético
Conector de pagina
Líneas de flujo
Anotación
Display, para mostrar datos
Envía datos a la impresora
Observación: Para obtener la correcta elaboración de los símbolos, existen plantillas. Las puedes conseguir en Papelerías.
Simbolos gráficos
Dentro de los simbolos fundamentales para la creaación de diagramas de flujo, los símbolos gráficos son utilizádos especificamente para para operaciónes aritméticas y relaciónes condicionales. La siguiente es una lista de los símbolos más comunmente utilizados:
+Sumar
-Menos
*Multiplicación
/División
±Mas o menos
=Equivalente a
>Mayor que
<Menor que
³Mayor o igual que
£Menor o igual que
¹ o <>Diferente de
Si
No
True
False
Reglas para la creacion de Diagramas
  1. Los Diagramas de flujo deben escribirse de arriba hacia abajo, y/o de izquierda a derecha.
  2. Los símbolos se unen con líneas, las cuales tienen en la punta una flecha que indica la dirección que fluye la información procesos, se deben de utilizar solamente líneas de flujo horizontal o verticales (nunca diagonales).
  3. Se debe evitar el cruce de líneas, para lo cual se quisiera separar el flujo del diagrama a un sitio distinto, se pudiera realizar utilizando los conectores. Se debe tener en cuenta que solo se vana utilizar conectores cuando sea estrictamente necesario.
  4. No deben quedar líneas de flujo sin conectar
  5. Todo texto escrito dentro de un símbolo debe ser legible, preciso, evitando el uso de muchas palabras.
  6. Todos los símbolos pueden tener más de una línea de entrada, a excepción del símbolo final.
  7. Solo los símbolos de decisión pueden y deben tener mas de una línea de flujo de salida.
Ejemplos de diagramas de flujo
Diagrama de flujo que encuentra la suma de los primeros 50 numeros naturales

Bueno, y ahora la descripción del diagrama anterior

Suma, es la variable a la que se le va agregando la valor de cada número natural. N, es el contador. Éste recorrerá lo números hasta llegar al 50.
  • El primer bloque indica el inicio del Diagrama de flujo Inicio del Diagrama de flujo
  • El segundo bloque, es un Símbolo de procesos Bloque de proceso En este bloque se asume que las variables suma y N han sido declaradas previamente y las inicializa en 0 para comenzar a el conteo y la suma de valores (Para declararlas existe el bloque Tarjeta perforada).
  • El tercer bloque, es también un Símbolo de procesos Bloque de procesos En éste paso se incrementa en 1 la variable N (N = N + 1). Por lo que, en la primera pasada esta N valdrá 1, ya que estaba inicializada en 0.
  • El cuarto bloque es exactamente lo mismo que el anterior Bloque de procesos Pero en éste, ya se le agrega el valor de N a la variable que contendrá la suma (En el primer caso contendrá 1, ya que N = 1).
  • El quinto bloque es uno Símbolo de Toma de decisiones y Ramificación Lo que hay dentro del bloque es una pregunta que se le hace a los valores que actualmente influyen en el proceso (Por decir algo, no se como decirlo, soy muy sope :DSímbolo de toma de desiciónes y Ramificación ¿Es N=50?, Obviamente la respuesta es no, ya que N todavía es 1. por lo que el flujo de nuestro programa se dirigirá hacía la parte en donde se observa la palabra no: Tercer Bloque, éste le sumará 1 (N=N+1) y vuelve a llegar a éste bloque, donde preguntará ¿Es N=50?... ¡No!, todavía es 2. Ha pues, regresa al Tercer bloque y vuelve hacer lo mismo. Y así hasta llegar a 50, obteniendo así la suma de los primeros 50 primeros números naturales.
  • Por último indicamos que el resultado será mostrado en la impresora (Este lo puedes cambiarlo por el display para mostrar datos). Bloque de Display
  • Fin del programa (o diagrama) Fin del diagrama
FUENTE
http://mis-algoritmos.com/aprenda-a-crear-diagramas-de-flujo

AJEDREZ VISUAL C++

Como Implementar un Juego de Ajedrez en Visual C++
Enviado por Ivan Cachicatari

Introducción

A mi entender, la mejor forma de aprender y comprender algoritmos de programación es programando juegos. Los juegos suelen presentar situaciones que ayudan a despertar la creatividad y por la complejidad  incentivan el uso de algoritmos complejos casi como jugando.

Hace algunos años implementé un juego de ajedrez que publique sin documentación, miles de usuarios descargaron el código fuente del proyecto pero muchos me escribieron recordándome que no había documentación para entender el proyecto. Es por eso que decidí re-hacer el proyecto pero esta vez documentado y explicándolo paso a paso.

Este tutorial le ayudará a usted a implementar un juego de ajedrez, para ello he utilizado Microsoft Visual C++ 2005, sin embargo usted puede seguir los pasos con otras versiones de Visual C++ incluso otros entornos de programación.

Objetivo

El objetivo, obviamente, es implementar un juego de ajedrez escrito en Visual C++ con los siguientes requisitos:
  • Uso de la interfaz gráfica con manejo del Mouse.
  • Controlar validar movidas de los jugadores.
  • Permitir dos jugadores.
  • Detectar jaque, jaque mate, enroques, y otras movidas.
Así se verá el juego cuando se termine de codificar:
Juego de Ajedrez en Visual C++ Terminado
Imagen 1: Juego de Ajedrez en Visual C++ Terminado



Contenido del tutorial

  • Creación del proyecto
  • Dibujar el tablero
  • Dibujar las piezas de ajedrez
  • Mover las piezas de ajedrez
  • Funciones generales para mover las piezas de ajedrez
  • Movida de cada pieza de ajedrez

Juego de Ajedrez en Visual C++

Creación del proyecto

Para no alargar más este asunto, lo primero que tenemos que hacer es crear el proyecto, el tipo de aplicación que necesitamos es “Documento único” conocido también como SDI (Simple Document Interface), asegurarse de que el check de la opción “Usar bibliotecas unicode” este deshabilitado por que no siempre están disponibles dichas bibliotecas en tiempo de ejecución (Ver Imagen 2).
Elección del tipo de aplicación del proyecto.
Imagen 2: Elección del tipo de aplicación del proyecto.
En el siguiente paso del asistente podemos prescindir de algunas características que no utilizaremos en el proyecto, como: Controles ActiveX, Impresión y vista preliminar, Ayuda Contextual. Sólo consideraremos la opción “Manifiesto de controles comunes”, esta opción nos ayudará a sintonizar los controles comunes con el tema de windows actual, de tal forma que no se vean extraños.
Elección de las características avanzadas del proyecto.
Imagen 3: Elección de las características avanzadas del proyecto.
El resto de opciones no necesita mayor explicación, y al final encontrarán una ventana como de la imagen 4, en este punto deben asegurarse de tener a CView como clase base de la clase CAjedrezView; esto significa la clase donde dibujaremos y realizaremos todas las operaciones que tienen que ver con ajedrez estarán en la clase CAjedrezView.
Vista final del asistente de creación de proyectos del Visual C++
Imagen 4: Vista final del asistente de creación de proyectos del Visual C++
Luego de hacer clic en finalizar se habrá creado un proyecto con las 4 clases que se muestran  en la figura 4, podemos compilar y ejecutar el proyecto y obtendremos un programa como el que se muestra en la imagen 5.
Programa inicial ejecutándose
Programa inicial ejecutándose


Juego de Ajedrez en Visual C++


Dibujar el tablero


Para dibujar el tablero de ajedrez dentro de la vista creada tenemos que tener en cuenta los parámetros siguientes:
  1. Etiquetas de filas y columnas.
  2. Margen entre el borde de la ventana y la cuadrícula del tablero.
  3. Tamaño de la celda del tablero.
Parámetros para dibujar el tablero de ajedrez
Imagen 6: Parámetros para dibujar el tablero de ajedrez
Para dibujar el tablero necesitaremos definir 3 valores fijos que no cambiarán y nos servirán para dibujar el tablero cada vez que lo necesitemos.
#define MARGEN 30
#define TAMCELDA 60
#define CELDAS  8
El siguiente paso es crear la función que dibujará el tablero, para ello debemos abrir la vista de clases, hacer clic derecho sobre la clase y elegir “Agregar->Función” luego aparecerá un dialogo como el de la imagen 7. No se deben olvidar de agregar un parámetro del tipo CDC* para que podamos dibujar los elementos.
Agregar Función DibujarTablero
Imagen 7: Agregar Función DibujarTablero

  La función DibujarTablero

A continuación una descripción del algoritmo utilizado para dibujar el trablero de ajedréz.
  • Crea inicialmente los objetos necesarios para darle color al fondo y a las líneas del tablero de ajedrez (CPen, CBrush)
  • Luego dibuja celda por celda (for anidado de 8 iteraciones cada uno)
    • Al inicio de la iteración se calcula las dimensiones de la celda en base a los valores de i y j y los parámetros definidos inicialmente (margen y tamaño de celda) estos valores calculados son almacenados en la variable rcCelda de tipo RECT.
    • Para dibujar una celda oscura o blanca se verifica si es par o no, de esa forma se intercalan los colores, según estos valores se utiliza el Brush indicado junto a la función CDC::Rectangle.
    • Se aprovecha el valor de rcCelda para calcular la posición de las etiquetas que están contenidas en la variable m_vEtiquetas de tipo std::vector.
Segun el algoritmo anterior podemos escribir el siguiente código:
void CAjedrezView::DibujarTablero(CDC* pDC)
{
    //Definición de colores y fondos
    RECT rcCelda;
    CBrush brNegro,brSeleccion;
    brNegro.CreateSolidBrush(0xf36d4d);
    brSeleccion.CreateSolidBrush(RGB(255,240,108));

    CPen penAzulMarino,penAmarillo;
    penAzulMarino.CreatePen(PS_SOLID,3,0x00640000);
    penAmarillo.CreatePen(PS_SOLID,4,0x0000EEEE);

    CPen *penAnterior = pDC->SelectObject(&penAzulMarino);
    pDC->SetBkMode(TRANSPARENT);

    for(int i = 0 ; i < CELDAS ; i++)
    {
        for(int j = 0 ; j < CELDAS ; j++)
        {
            rcCelda.left  = j*TAMCELDA + MARGEN;
            rcCelda.top   = i*TAMCELDA + MARGEN;  
            rcCelda.right = rcCelda.left + TAMCELDA;
            rcCelda.bottom = rcCelda.top + TAMCELDA;

            if( i%2 == 0 )
            {
                if(j%2 != 0)
                {
                        CBrush *pFondoAnterior = pDC->SelectObject(&brNegro);
                        pDC->Rectangle(&rcCelda);
                        pDC->SelectObject(pFondoAnterior);
                }
                else
                {
                    pDC->Rectangle(&rcCelda);
                }
            }
            else
            {
                if(j%2 == 0)
                {
                        CBrush *pFondoAnterior = pDC->SelectObject(&brNegro);
                        pDC->Rectangle(&rcCelda);
                        pDC->SelectObject(pFondoAnterior);
                }
                else
                {
                    pDC->Rectangle(&rcCelda);
                }
            }
            
            //Dibujando las etiquetas
            if(j == 0 || j == 7)
            {
                rcCelda.left  = j==0?MARGEN-15:rcCelda.right;
                rcCelda.right = j==0?MARGEN:rcCelda.right + 15;
                pDC->DrawText(m_vEtiquetas[i],
                    &rcCelda,
                    DT_CENTER|DT_VCENTER|DT_SINGLELINE);
                
                //Restaurando valores para que no 
                //afecte el pintado de las etiquetas verticales
                rcCelda.left  = j*TAMCELDA + MARGEN;
                rcCelda.right = rcCelda.left + TAMCELDA;
            }
            if(i == 0 || i == 7)
            {
                rcCelda.top    = i==0?MARGEN-20:rcCelda.bottom;
                rcCelda.bottom = i==0?MARGEN:rcCelda.bottom + 20;
                pDC->DrawText(m_vEtiquetas[j+8],
                    &rcCelda,
                    DT_CENTER|DT_VCENTER|DT_SINGLELINE);
            }

        }
    }
    pDC->SelectObject(penAnterior);
}

Este código debe invocarse desde la función OnDraw, la función OnDraw ya esta establecida y recibe como parámetro también un objeto CDC, el mismo debe pasar como parámetro de la función DibujarTablero.
#include "memdc.h"

...

void CAjedrezView::OnDraw(CDC* pDC)
{
    CAjedrezDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    CMemDC memdc(pDC);
    DibujarTablero(&memdc);
}

La clase CMemDC es una herramienta para crear un mapa de bits en segundo plano para ir dibujando en él y al final pintar el mapa de bits sobre la ventana para así evitar el parpadeo que se produce al pintar objeto por objeto, esta técnica se le conoce como Double Buffering.
Pueden descargar el archivo memdc.h  de codeproject.com, esta clase fue escrita por Keith Rule (keithr@europa.com)
Agregar Función OnEraseBkgnd
Para que la técnica de double buffering quede completa debemos agregar la función asociada al evento WM_ERASEBKGND que decide si se va a eliminar el fondo antes de pintar nuevamente el tablero.

El código de la función generada se debe ver como sigue:

BOOL CAjedrezView::OnEraseBkgnd(CDC* pDC)
{
    return FALSE;
}




Luego de terminar de escribir la función pueden compilar y verán un resultado como el de la imagen 8.


Tablero Dibujado por la Funci
Imagen 8: Tablero Dibujado por la Función

Juego de Ajedrez en Visual C++

Dibujar las piezas

Buscando en la red pude encontrar una imagen con todas las piezas de ajedrez que vamos a necesitar. Si ustedes encuentran algún juego de imágenes mejorado pueden utilizarlo y seguir los mismos pasos.

Imagen con las piezas de ajedrez
Imagen 9: Imagen con las piezas de ajedrez
Les recomiendo que utilicen la opción Imagen -> Configuración de cuadrícula, para que pueda aparecer una cuadricula de 60x60 que va a facilitarles la ubicación de cada imagen. Las imágenes las guardaremos en los recursos con el id IDB_PIEZAS, deben modificar las propiedades de la imagen para que pueda ser guardada con “color verdadero”.
Si han podido notar, aun no creamos la matriz conde vamos a almacenar cada pieza de ajedrez, esta matriz no necesita ser muy compleja, solo necesitamos un arreglo de dos dimensiones de tipo entero.
int m_pCeldas[8][8];
CImageList m_imgPiezas;
Cada pieza de ajedrez será identificada según su posición en la imagen, por ejemplo las posiciones 0 ,1 y 2 corresponden a las piezas: reina negra, reina blanca, y rey negro respectivamente (Ver imagen 9), para facilitarnos las cosas definiremos los siguientes valores:
#define VACIO -1
#define PEONB 11
#define PEONN 10
#define ALFILB 7
#define ALFILN 6
#define CABALLOB 9
#define CABALLON 8
#define REYB 1
#define REYN 0
#define REINAB 3
#define REINAN 2
#define TORREB 5
#define TORREN 4
La terminación de cada definición anterior corresponde a la primera letra del color al que corresponde.
Para inicializar todos los valores en el arreglo m_pCeldas debemos crear una función que llamaremos InicializarTablero.
// Situa todas las piezas en su lugar
void CAjedrezView::InicializarTablero(void)
{
    //Inicializacion de celdas
    for(int i = 0 ; i < 8 ;i++)
        for(int j = 0 ; j < 8 ; j++)
            m_pCeldas[i][j] = VACIO;

    m_pCeldas[0][0] = TORREN;
    m_pCeldas[0][1] = CABALLON;
    m_pCeldas[0][2] = ALFILN;
    m_pCeldas[0][3] = REINAN;
    m_pCeldas[0][4] = REYN;
    m_pCeldas[0][5] = ALFILN;
    m_pCeldas[0][6] = CABALLON;
    m_pCeldas[0][7] = TORREN;

    m_pCeldas[7][0] = TORREB;
    m_pCeldas[7][1] = CABALLOB;
    m_pCeldas[7][2] = ALFILB;
    m_pCeldas[7][3] = REINAB;
    m_pCeldas[7][4] = REYB;
    m_pCeldas[7][5] = ALFILB;
    m_pCeldas[7][6] = CABALLOB;
    m_pCeldas[7][7] = TORREB;

    m_pCeldas[1][0] = PEONN;
    m_pCeldas[1][1] = PEONN;
    m_pCeldas[1][2] = PEONN;
    m_pCeldas[1][3] = PEONN;
    m_pCeldas[1][4] = PEONN;
    m_pCeldas[1][5] = PEONN;
    m_pCeldas[1][6] = PEONN;
    m_pCeldas[1][7] = PEONN;

    m_pCeldas[6][0] = PEONB;
    m_pCeldas[6][1] = PEONB;
    m_pCeldas[6][2] = PEONB;
    m_pCeldas[6][3] = PEONB;
    m_pCeldas[6][4] = PEONB;
    m_pCeldas[6][5] = PEONB;
    m_pCeldas[6][6] = PEONB;
    m_pCeldas[6][7] = PEONB;
}
La variable m_imgPiezas es donde cargaremos las imágenes, utilizaremos las funciones de la clase CImageList para extraer imágenes individuales al momento de pintar. En el constructor de la clase CAjedrezView debemos inicializar las imágenes para tenerlas disponibles en todo momento.
CAjedrezView::CAjedrezView()
{
    m_imgPiezas.Create(IDB_PIEZAS,TAMCELDA,0,RGB(255,0,255));

    InicializarTablero();
}
Finalmente para que podamos ver cada pieza en el tablero tenemos que agregar las siguientes líneas a la función DibujarTablero:
void CAjedrezView::DibujarTablero(CDC* pDC)
{
    ...

    for(int i = 0 ; i < CELDAS ; i++)
    {
        for(int j = 0 ; j < CELDAS ; j++)
        {
            ... 

            if(m_pCeldas[i][j] >= 0)
            {
                POINT p;
                p.x = rcCelda.left;
                p.y = rcCelda.top;
                SIZE s;
                s.cx = s.cy = 60;

                m_imgPiezas.DrawEx( pDC, m_pCeldas[i][j],
                    p,s,RGB(255,0,255),0,ILD_TRANSPARENT);
            }

            ...
        }
    }
    ...
}
Luego de seguir todos estos pasos, al compilar se podrá observar las piezas inicializadas en su lugar tal como se muestra en la imagen 10.
 Tablero de ajedrez con sus piezas
Imagen 10: Tablero de ajedrez con sus piezas
 Ahora solo falta modificar las propiedades de la ventana para que pueda tener un tamaño fijo también debemos modificar algunas propiedades más para evitar que al usuario pueda cambiar el tamaño de la ventana.

Para ello debemos ir a la clase CMainFrame a las funciones PreCreateWindow y OnCreate, y agregar las líneas siguientes:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    //Asignar las dimensiones
    MoveWindow(0,0,60*9,60*10,FALSE);
    CenterWindow();
    
    if (!m_wndStatusBar.Create(this) ||
        !m_wndStatusBar.SetIndicators(indicators,
          sizeof(indicators)/sizeof(UINT)))
    {
        TRACE0("No se pudo crear la barra de estado\n");
        return -1;
    }

    return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.style = WS_POPUPWINDOW|WS_CAPTION;

    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;

    return TRUE;
}
 Si no lo han notado aun, también he borrado las líneas que corresponden a la creación de la barra de herramientas que no vamos a necesitar en adelante.

Al compilar nuestro proyecto en este punto podremos el siguiente resultado:
 Tablero del juego de ajedréz
Imagen 11: Tablero del juego de ajedréz

Juego de Ajedrez en Visual C++

Utilizar el Mouse para mover las piezas

Antes de continuar debemos definir algunas variables que nos ayudarán a manipular los eventos, estas variables deben definirse dentro de la clase CAjedrezView para tenerlas disponibles en todo momento.
class CAjedrezView : public CView
{
    ...

    POINT m_celdaSel;
    POINT m_celdaCursor;
    bool m_bFichaSeleccionada;
    bool m_bTurnoBlancas;

    ...
}
Algunas aclaraciones sobre las variables:
  • La variable m_celdaSel es de tipo POINT y ahí guardaremos la celda seleccionada para ser movida en el siguiente clic.
  • En la variable m_celdaCursor guardaremos las coordenadas de la celda sobre la cual esta el cursor del Mouse, para dibujar un borde amarillo en pantalla.
  • La variable booleana m_FichaSeleccionada será un indicador que nos permitirá verificar si hay una ficha seleccionada para moverla, esto nos evitará varias líneas de código para verificar si ha habido una movida antes que la actual. Esta variable se inicializa en false por que al principio no hay fichas seleccionadas.
  • La variable m_bTurnoBlancas decidirá el turno actual, esta variable se inicializará en verdadero (true) por que las reglas del ajedrez indican que primero empiezan las blancas. Si esta variable es false entonces obviamente le toca a equipo negro.

OnMouseMove

Para activar el uso del Mouse solo tenemos que hacer clic en las propiedades de la clase CAjedrezView y buscar los eventos WM_MOUSEMOVE y WM_LMOUSEDOWN, opcionalmente también utilizaremos el evento WM_KEYDOWN para interceptar la tecla de escape.
Agregar Función OnEraseBkgnd
Agregar Función OnMouseMove
La función OnMouseMove, esta función nos ayudará a identificar la celda sobre la cual esta el puntero del Mouse. La secuencia del código fuentes es como sigue:
  • Inicialmente crearemos las variables de las coordenadas inicializadas en -1 al principio.
  • Luego transformaremos las coordenadas actuales de píxeles a posiciones de la matriz de piezas dividiendo las coordenadas entre 60.
  • Luego verificamos si las coordenadas transformadas están dentro del margen permitido.
    • Si están dentro del margen permitido y si han cambiado respecto a las coordenadas anteriores entonces cambiamos la celda de cursor a la posición actual.
    • Caso contrario modificamos la celda de cursor a -1,-1 para evitar que se vea en pantalla.
Sin tantas complicaciones podemos escribir este codigo para el algoritmo anterior:
void CAjedrezView::OnMouseMove(UINT nFlags, CPoint point)
{
    static int x = -1;
    static int y = -1;

    x = (point.x - MARGEN)/60; 
    y = (point.y - MARGEN)/60;

    if(x >= 0 && y >= 0 && x<8 && y<8)
    {
        if(x != m_celdaCursor.x || y != m_celdaCursor.y )
        {
            m_celdaCursor.x = x;
            m_celdaCursor.y = y;

            Invalidate();
        }
    }
    else
    {
        x=-1;
        y=-1;
        if(x != m_celdaCursor.x || y != m_celdaCursor.y )
        {
            m_celdaCursor.x = -1;
            m_celdaCursor.y = -1;

            Invalidate();
        }
    }

    CView::OnMouseMove(nFlags, point);
}

OnLButtonDown

La función OnLButtonDown (Al presional el boton izquierdo del mouse) , se hace la misma verificación de las coordenadas pero esta vez se invoca a la función MoverFicha,  La función MoverFicha la veremos mas adelante.
void CAjedrezView::OnLButtonDown(UINT nFlags, CPoint point)
{
    static int x = -1;
    static int y = -1;

    x = (point.x - MARGEN)/60; 
    y = (point.y - MARGEN)/60;

    if(x >= 0 && y >= 0 && x<8 && y<8)
    {
        MoverFicha(x,y);
    }
    CView::OnLButtonDown(nFlags, point);
}

Modificar la funcion DibujarTablero

Debemos agregar líneas de código a la función DibujarTablero para ver los efectos:
void CAjedrezView::DibujarTablero(CDC* pDC)
{
    ...
    for(int i = 0 ; i < CELDAS ; i++)
    {
        for(int j = 0 ; j < CELDAS ; j++)
        {

            ...

            if(m_celdaSel.x == j && m_celdaSel.y == i)
            {
                CBrush *pFondoAnterior = pDC->SelectObject(&brSeleccion);
                pDC->Rectangle(&rcCelda);
                pDC->SelectObject(pFondoAnterior);
            }

            ...

Juego de Ajedrez en Visual C++

Funciones generales para mover las piezas de ajedrez

Ahora veremos el código mas difícil de hacer, todo lo que hicimos hasta el momento ha estado relativamente fácil comparado con lo que vamos a ver. Pero creo que no va a ser tan dificil por que todo el codigo fuente esta explicado y será pan comido.
Antes de seguir debemos implementar algunas funciones que nos va a permitir controlar todas las movidas. Todo empieza desde la función OnLButtonDown que invoca a la función MoverFicha.

Función MoverFicha

  • Si hay una ficha seleccionada.
    • Si la celda es nula o es del otro equipo, entonces intentamos mover la pieza.
    • Sino, mostramos el mensaje “Movida no permitida” y volvemos a esperar la movida del usuario.
  • Sino
    • Si la celda esta vacía, no hacemos nada.
    • Si la pieza corresponde al turno es el correcto:
      • Cambiamos la variable m_celdaSel con la posición actual.
      • Levantamos el flag m_bFichaSeleccionada
      • Mostramos un mensaje para hacerle saber al usuario que debe realizar el siguiente paso.
      • Refrescar la pantalla.
Código fuente de la función MoverFicha
void CAjedrezView::MoverFicha(int x,int y)
{
    if(m_bFichaSeleccionada)
    {
        if(EsCeldaNula(x,y) 
            || (!EsPiezaBlanca(x,y) && m_bTurnoBlancas)
            || (EsPiezaBlanca(x,y) && !m_bTurnoBlancas))
        {
            IntentarMovidaHacia(x,y);
        }
        else
        {
            Mensaje("Movida no permitida");
            CancelarMovida();
        }
    }
    else
    {
        if(EsCeldaNula(x,y))
            return;
        if((EsPiezaBlanca(x,y) && m_bTurnoBlancas )
            || (!EsPiezaBlanca(x,y) && !m_bTurnoBlancas))
        {
            m_celdaSel.x = x;
            m_celdaSel.y = y;
            m_bFichaSeleccionada = true;
            
            Mensaje("Presione ESC para cancelar la selección");

            Invalidate();
        }
    }
}

La función IntentarMovidaHacia

  • Obtener el valor de la celda de la celda seleccionada.
  • Identificar el tipo de pieza y e invocar a la función que corresponde.
  • Si hay resultado exitoso al intentar mover la pieza
    • Mostrar mensaje
    • Realizar la movida.
  • Sino
    • Mostar mensaje de error
void CAjedrezView::IntentarMovidaHacia(int x, int y)
{
    int nPiezaActual = m_pCeldas[m_celdaSel.y][m_celdaSel.x];

    bool bSePuedeMover = false;

    switch(nPiezaActual)
    {
        case PEONB:
        case PEONN:
            bSePuedeMover = MoverPeonHacia(x,y);
            break;
        case ALFILB:
        case ALFILN:
            bSePuedeMover = MoverAlfilHacia(x,y);
            break;
        case CABALLOB:
        case CABALLON:
            bSePuedeMover = MoverCaballoHacia(x,y);
            break;
        case REYB:
        case REYN:
            bSePuedeMover = MoverReyHacia(x,y);
            break;
        case REINAB:
        case REINAN:
            bSePuedeMover = MoverReinaHacia(x,y);
            break;
        case TORREB:
        case TORREN:
            bSePuedeMover = MoverTorreHacia(x,y);
            break;
    }

    if(bSePuedeMover)
    {
        Mensaje("Movida correcta, siguiente jugador");
        RealizarMovida(x, y);
    }
    else
    {
        Mensaje("Movida incorrecta, intenta nuevamente");
        CancelarMovida();
    }
}

La función EsViaLibre

  • Inicialmente obtenemos la diferenca entre las coordenadas, esto nos ayudará a identificar que tipo de movida se ha realizado.
  • Si la diferencia de las coordenadas x es igual a cero entonces se ha realizado un movimiento vertical.
    • Recorremos todas las celdas que hay entre las dos coordenadas, si encontramos alguna celda con una pieza de ajedrez entonces retornamos false.
  • Si la diferencia de las coordenadas y es igual a cero entonces se ha realizado un movimiento horizontal.
    • Recorremos todas las celdas que hay entre las dos coordenadas, si encontramos alguna celda con una pieza de ajedrez entonces retornamos false.
  • Si la diferencia de las coordenas x e y son iguales entonces se ha realizado un movimiento diagonal
    • Recorremos todas las celdas que hay entre las dos coordenadas, si encontramos alguna celda con una pieza de ajedrez entonces retornamos false.
  • Si al final no se ha determinado que tipo de movimiento se ha realizado entonces se devuelve el valor de ok que en ese punto deberá ser false.
Codigo fuente de la función EsViaLibre
bool CAjedrezView::EsViaLibre(int x, int y)
{
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    bool ok = true;

    if(difx == 0) //Movimiento Vertical
    {        
        for(int i = 1 ; i < abs(dify) ; i++)
        {
            if(m_pCeldas[m_celdaSel.y + (dify<0?-i:i)][m_celdaSel.x] != VACIO)
            {
                ok = false;
            }
        }
    }
    else if(dify == 0) //Movimiento Horizontal
    {
        for(int i = 1 ; i < abs(difx) ; i++)
        {
            if(m_pCeldas[m_celdaSel.y][m_celdaSel.x + (difx<0?-i:i)] != VACIO )
            {
                ok = false;
            }
        }        
    }
    else if(abs(difx) == abs(dify)) //Movimiento diagonal
    {
        for(int i = 1 ; i < abs(dify) ; i++)
        {
            if(m_pCeldas[m_celdaSel.y + (dify<0?-i:i)][m_celdaSel.x + (difx<0?-i:i)] != VACIO)
            {
                ok = false;
            }
        }
    }
    return ok;
}
En adelante, para todos los casos se utilizará la diferencia de coordenadas, por que es una manera facil y rápida de identificar la dirección y tipo de movida.

La función RealizarMovida

  • Cambiar turno de jugador.
  • Ubicar la pieza de origen a la posición de destino.
  • Cambiar los valores que tienen que ver con la ficha seleccionada.
  • Repintar.
Codigo fuente de la función RalizarMovida.
void CAjedrezView::RealizarMovida(int x, int y)
{
    //Cambiar Turno
    m_bTurnoBlancas      = !m_bTurnoBlancas;

    //Asignar la pieza de origen al destino
    m_pCeldas[y][x] = m_pCeldas[m_celdaSel.y][m_celdaSel.x];

    //TODO: Agregar a la lista de eliminados
    m_pCeldas[m_celdaSel.y][m_celdaSel.x] = VACIO;

    //Soltar la ficha seleccionada
    m_bFichaSeleccionada = false;
    m_celdaSel.x = -1;
    m_celdaSel.y = -1;

    Invalidate();    
}

Juego de Ajedrez en Visual C++

Moviendo cada pieza de ajedrez

Ahora veremos en detalle como podemos controlar la movida de cada pieza de ajedréz.

Movida del peón

Es la movida que parece simple de implementar, pero presenta situaciones especiales.
  • Obtenemos la diferencia entre las coordenadas de origen y destino.
  • Si es una movida vertical
    • Si se ha movido un casillero
      • Si la dirección de la movida corresponde al turno, entonces es posible realizar la movida
    • Si se ha movido dos casilleros
      • Si la dirección de la movida corresponde al turno y la pieza del peon aun no se ha movido, entonces es posible realizar la movida
        • Si hay vía libre para realizar la movida, entonces es posible realizar la movida.
  • Si es un movimiento diagonal y si la orientación de la movida es correcta con el turno y si la celda de destino no esta vacía y si la celda de destino corresponde a una pieza del oponente.
    • Se puede realizar la movida.
Código fuente de la función   MoverPeonHacia
bool CAjedrezView::MoverPeonHacia(int x, int y)
{
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    bool bMovidaPosible = false;

    if(difx == 0) //Movida Vertical
    {        
        if(abs(dify) == 1)//Si mueve un casillero
        {
            if(dify == (EsPiezaBlanca(m_celdaSel.x ,m_celdaSel.y)?-1:1))
            {
                bMovidaPosible = true;
            }
        }
        else if(abs(dify) == 2) //Movida larga de peon
        {
            if(m_celdaSel.y == (EsPiezaBlanca(m_celdaSel.x ,m_celdaSel.y)?6:1))
            {
                if(EsViaLibre(x,y))
                    bMovidaPosible = true;
            }
        }
    }
    else if((abs(difx) == 1) // Si esta intentando comer
        && (dify == (EsPiezaBlanca(m_celdaSel.x ,m_celdaSel.y)?-1:1))
        && !EsCeldaNula(x,y) 
        && (m_pCeldas[m_celdaSel.y ][m_celdaSel.x] != m_pCeldas[y][x]))
    {
        bMovidaPosible = true;
    }

    return bMovidaPosible;
}

Movida del alfil

El alfil es una pieza que se mueve diagonalmente, entonces basta con verificar si hay vía libre entre las posiciones.
  • Obtenemos la diferencia entre las coordenadas de origen y destino.
  • Si la diferencia de ambas coordenadas son iguales entonces es un movimiento diagonal.
    • Si hay vía libre y la celda de destino esta vacía o corresponde al enemigo
      • Devolver true, indicando que se puede realizar la movida.
  • Sino, devolver falso.
Código fuente de la función
bool CAjedrezView::MoverAlfilHacia(int x, int y)
{
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    if(abs(difx) == abs(dify))
    {
        if(EsViaLibre(x,y) && m_pCeldas[m_celdaSel.y ][m_celdaSel.x] != m_pCeldas[y][x])
        {            
            return true;
        }
    }
    return false;
}

Movida de la torre

La movida de la torre es similar a la del alfil con la diferencia que una de las dos diferencias debe ser cero.
bool CAjedrezView::MoverTorreHacia(int x, int y)
{ 
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    if((difx == 0) || (dify == 0) )
    {
        if(EsViaLibre(x,y) && m_pCeldas[m_celdaSel.y ][m_celdaSel.x] != m_pCeldas[y][x])
        {            
            return true;
        }
    }
    return false;
}

Movida de la reina

Es mas fácil de lo que parece:
bool CAjedrezView::MoverReinaHacia(int x, int y)
{
    return MoverAlfilHacia(x,y) || MoverTorreHacia(x,y);
}

Movida del rey

En esta movida solo hay que verificar que se haya movido un casillero y que la celda de destino sea la del oponente.
bool CAjedrezView::MoverReyHacia(int x, int y)
{
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    if((abs(difx) == 1) && (abs(dify) == 1) )
    {        
        if(m_pCeldas[m_celdaSel.y ][m_celdaSel.x] != m_pCeldas[y][x])
        {
            return true;
        }
    }
    return false;
}

Movida del caballo

Esta movida no se parece a ninguna de las anteriores, es por eso que necesita explicación.
  • Obtenemos la diferencia entre las coordenadas de origen y destino.
  • Si la diferencia entre las coordenadas debe ser 2 y 1 para cada caso
    • Si la celda de destino es del oponente o esta en blanco
      • Devolver true indicando que se puede realizar la movida
  • Sino, retornar false.
bool CAjedrezView::MoverCaballoHacia(int x, int y)
{
    int dify = y - m_celdaSel.y;
    int difx = x - m_celdaSel.x;

    if(((abs(difx) == 2) && (abs(dify) == 1))||((abs(difx) == 1) && (abs(dify) == 2)))
    {
        if(m_pCeldas[m_celdaSel.y ][m_celdaSel.x] != m_pCeldas[y][x])
        {
            return true;
        }
    }
    return false;
}

Tareas por hacer

El proyecto no esta completo, por lo que dejo una lista de tareas por hacer para que algun aventurero se anime a completarlas. Si alguien ha completado alguna solo tiene que escribirme a mi correo e inmediatamente subiré su actualización.
  • Permitir enroque y peon al paso.
  • Detectar Jaque / Jaque Mate.
  • Visualizar las movidas realizadas segun la notación oficial.
  • Permitir guardar/recuperar una partida.

 
Design by Free Wordpress Themes | Bloggerized by Lasantha - Premium Blogger Templates