batalla.c
, cuya adecuada compilación producirá
el ejecutable batalla
. En esencia, la acción
del programa se desarrolla sobre un tablero parecido al
del ajedrez, pero de 16x8 escaques. Sobre este tablero
evolucionan dos equipos de fichas, las blancas y las negras.
Cada equipo está formado por un rey inmortal y un número
variable de torres. Estas figuras se mueven siguiendo las
mismas reglas que sus homónimas del ajedrez: el rey a
cualquiera de las ocho casillas más próximas y las torres,
cualquier número de casillas horizontal o verticalmente
siempre que no se salte sobre otra ficha intermedia.
La imagen que se verá en la simulación será parecida a
la siguiente:
Batalla
acepta un máximo de dos argumentos por
la línea de órdenes. Si no se introducen argumentos, se imprimirá
un mensaje con la forma de uso del programa por el canal de
error estándar. En el caso de teclear un argumento, dicho argumento
será un número entero mayor o igual que cero
relacionado con la rapidez con que se producen los acontecimientos
en el programa. Cero indica la máxima rapidez y números
mayores suponen una rapidez progresivamente menor. Finalmente,
si son dos los parámetros introducidos, el primero es idéntico
al caso anterior y el segundo será una "D", indicando que se
desea que el programa produzca información de depuración por
el canal de errores estándar.
batalla.dll
y un fichero de cabeceras,
batalla.h
.
Gracias a la biblioteca, muchas de las funciones no las tendréis
que programar sino que invocarlas a la DLL, tal como se
explica en la sesión decimoquinta.
La biblioteca creará un hilo adicional a los vuestros para
su funcionamiento interno. Una descripción
detallada de las funciones de la biblioteca aparece más abajo
en esta misma página.
batalla.dll
batalla.dll
y el fichero de cabeceras batalla.h
.
batalla.dll
:
Descárgalo de aquí.
batalla.h
:
Descárgalo de aquí.
DWORD inicio(LONG intervalo, BOOL d)
intervalo
: valor de retardo que
se obtuvo de la línea de órdenes.
d
: flag que indica si se desea
que la biblioteca produzca información de
depuración por el canal de errores estándar.
inicio
devuelve el identificador de dicho hilo para que
podamos enviarle mensajes. En el caso de que la
función falle, inicio
devuelve 0.
inicio
. Las características del mensaje
enviado deben ser:
WM_USER
.
wParam
: un entero cuyo valor expresa
los escaques origen y destino de la ficha movida.
Observando la figura de esta página, se ve que
cada cuadro viene identificado unívocamente por
un par de dígitos hexadecimales, el primero para
la fila (0-7) y el segundo para la columna (0-F).
El rey blanco se encuentra en la posición 0x4B.
Si se deseara mover en diagonal hacia abajo,
posición 0x5C, wParam
debe valer
0x4B5C.
lParam
: identificador del hilo que
envía el mensaje.
WM_USER+1
con los mismos
parámetros que los enviados si es que se produjo un error.
Si se produce un error, la biblioteca dejará de atender mensajes
para mejor poder depurar la situación.
WM_USER+1
y wParam
igual a 0x1234
a la biblioteca para indicar que debe concluir el hilo gestor
de mensajes. La biblioteca imprimirá el número de movimientos
que ha atendido hasta ese momento.
EVENTOS Y VALOR INICIAL: EC* (automático), EV (automático). SEUDOCÓDIGO: C V === === Por_siempre_jamás Por _siempre_jamás { { W(EC) W(EV) escribir_consonante escribir_vocal Set(EV) Set(EC) } }Debéis indicar, asimismo, en el caso de que las hayáis realizado, las optimizaciones de código realizadas para producir más movimientos en 30s.
TerminateThread
para acabar con
los hilos. El problema de esta función es que
está diseñada para ser usada sólo en condiciones
excepcionales y el hilo muere abruptamente.
Puede dejar estructuras colgando e ir llenando
la memoria virtual del proceso con basura.
La casilla origen no contiene una ficha
válida
. Cuando examino la casilla, compruebo
que todo es correcto. ¿A qué puede ser debido?2>salida
. De este modo, toda la información
aparecerá en el fichero salida
.
inicio
de la biblioteca. No consigo de
ningún modo acceder a ella.inicio
por lo que veremos más
abajo. Para definir el tipo de esta variable
correctamente, debéis conocer cómo son los
punteros a función. En la
sesión quinta,
se describe una función, atexit
.
Dicha función en sí no es importante para lo
que nos traemos entre manos, pero sí el argumento
que tiene. Ese argumento es un puntero a función.
Fijándoos en ese argumento, no os resultará
difícil generalizarlo para poner un puntero
a funciones que admiten un (LONG,BOOL) y devuelven
un DWORD. Notad, además, que, al contrario que
ocurre con las variables "normales", la definición
de una variable puntero a función es especial
por cuanto su definición no va sólo antes del
nombre de la variable, sino que lo rodea.
Tenéis que poner algo similar a:
#$%&%$ inicio $%&$·@;
, es decir,
algo por delante y algo por detrás.
GetProcAddress
.
Pero, ¡cuidado!, GetProcAddress
devuelve un FARPROC
, que sólo
funciona con punteros a funciones que devuelven
int
y no se les pasa nada
(void)
. Debéis hacer el
correspondiente casting. Para ello,
de la definición de vuestro puntero, quitáis
el nombre, lo ponéis todo entre paréntesis
y lo añadís delante de
GetProcAddress
, como siempre.
inicio
como nombre al puntero,
ahora no se diferenciarán en nada vuestras
llamadas a la función respecto a si dicha
función no perteneciera a una DLL y la
hubierais programado vosotros.
while
. La condición de permanencia
vendrá en función de dos variables, una es común
para todos los hilos y marca si los 30s han pasado
y la otra indicará si la ficha ha sido comida y
será diferente para cada torre, evidentemente.
Para que la ficha que come a la torre pueda cambiar
el valor de esa variable, podéis almacenar un
puntero a la variable en el cuadro donde se
encuentre la ficha. Al comer, mediante ese puntero,
podemos cambiar la variable del hilo asociado.
HANDLE
s de todos los hilos de
las torres vivas en ese momento. Quizá una
solución sea almacenar en las casillas del
tablero el HANDLE
del hilo que
la está moviendo, pero puede ser complicado.
En cualquier caso, se puede dar una solución
ad hoc, no es tan importante para la
práctica como otros asuntos. Tanto estas ideas
como las anteriores son sólo eso, ideas para
aquellos que no logréis evolucionar. No quiere
decir que forzosamente debáis usarlas en lugar
de otras posibilidades.