dockapps/wmtictactoe/wmtictactoe/wmtictactoe.c
2017-08-27 21:56:47 +02:00

1117 lines
31 KiB
C

/*
wmtictactoe - the ultimate tictactoe for WindowMaker
=-=-=-=-=-= ======================================
Copyright (C) 1999 André R. Camargo
Este programa é um software de livre distribuição, que pode ser copiado e
distribuído sob os termos da Licença Pública Geral GNU, conforme publicada
pela Free Software Foundation, versão 2 da licença ou (a critério do autor)
qualquer versão posterior.
Este programa é distribuído na expectativa de ser útil aos seus usuários,
porém NÃO TEM NENHUMA GARANTIA, EXPLÍCITAS OU IMPLÍCITAS, COMERCIAIS OU DE
ATENDIMENTO A UMA DETERMINADA FINALIDADE. Consulte a Licença Pública Geral
GNU para maiores detalhes.
Deve haver uma cópia da Licença Pública Geral GNU junto com este software
em inglês ou português. Caso não haja escreva para
Free Software Foundation, Inc.
675 Mass Ave,
Cambridge, MA 02139, USA.
acamargo@conesul.com.br
André Ribeiro Camargo
Rua Silveira Martins, 592/102
Centro
Canguçu-RS-Brasil
CEP 96.600-000
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <libdockapp/wmgeneral.h>
#include "wmtictactoe-master.xpm"
// ---------------------------------------------------------------
// definicoes :)
#define WMTICTACTOE_VERSION "1.1"
#define TRUE 1
#define FALSE 0
#define USLEEP 20000
#define BLINK 200000
#define LEGENDA_VAZIO 0
#define LEGENDA_USUARIO 1
#define LEGENDA_X 2
#define JOGO_OFENSIVO 0
#define JOGO_DEFENSIVO 1
// ---------------------------------------------------------------
// Variáveis Globais
char *ProgName;
typedef struct {
int left;
int top;
int right;
int bottom;
} regioes;
regioes quadrantes[MAX_MOUSE_REGION] =
{
{5, 8, 20, 18},
{24, 8, 40, 18},
{43, 8, 57, 18},
{5, 20, 20, 30},
{24, 20, 40, 30},
{43, 20, 57, 30},
{5, 33, 20, 44},
{24, 33, 40, 44},
{43, 33, 57, 44}};
int tabuleiro[9] =
{LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO,
LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO,
LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO};
int sequencias[8][3] =
{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
{0, 3, 6},
{1, 4, 7},
{2, 5, 8},
{0, 4, 8},
{2, 4, 6}};
int livre[9] =
{0, 1, 2, 3, 4, 5, 6, 7, 8};
int livre_max;
int game_mode;
int mute_mode;
int score_user_offensive = 0;
int score_X_offensive = 0;
int score_deuce_offensive = 0;
int score_user_defensive = 0;
int score_X_defensive = 0;
int score_deuce_defensive = 0;
int score_opponent = 0;
// modo padrao eh jogar contra o micro
// por isso deadmatch leva um FALSE
int isDeadmatch = FALSE;
int adversario = TRUE;
// mascara
char wmtictactoe_mask_bits[64 * 64];
int wmtictactoe_mask_width = 64;
int wmtictactoe_mask_height = 64;
// ----------------------------------------------------------
// declaracao das funcoes do sistema
void main (int argc, char *argv[]);
void usage (void);
void printversion (void);
void readfile (void);
void writefile (void);
void desenhaJogador (int);
void desenhaX (int);
void desenhaAdversario (int);
void desenhaLimpa (int);
void desenhaAvisoJoga (void);
void desenhaAvisoLimpa (void);
void desenhaAvisoVoceVenceu (void);
void desenhaAvisoEuVenci (void);
void desenhaAvisoEmpate (void);
int mostra_score (void);
void escreve_placar (void);
void reseta_score (void);
void piscaVencedor (void);
void troca_game_mode (void);
void reseta_tabuleiro (void);
void livre_desempilha (int);
void principal (int, char **);
int escolheJogador (void);
void joga (int);
void jogaHumano (int);
void jogaX (void);
int tapa_buraco (void);
int analisa_jogo (void);
int chuta_jogada (void);
int validaJogada (int);
void game_over (void);
// -------------------------------------------------------------------------------------------
// funcao: main()
// descricao: funcao principal da linguagem
// in: argc - numero de argumentos passados por linha d comando
// argv - vetor com os argumentos
// out: nada
void main (int argc, char *argv[])
{
int i;
ProgName = argv[0];
if (strlen (ProgName) >= 11)
ProgName += (strlen (ProgName) - 11);
game_mode = JOGO_DEFENSIVO;
mute_mode = FALSE;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (*arg == '-') {
switch (arg[1]) {
case 'o':
game_mode = JOGO_OFENSIVO;
break;
case 'd':
printf("%s", arg+1);
if (strcmp (arg + 1, "deadmatch") == 0) {
isDeadmatch = TRUE;
break;
}
if (strcmp (arg + 1, "display") == 0)
break;
usage ();
exit (1);
case 'v':
printversion ();
exit (0);
case 'q':
mute_mode = TRUE;
break;
default:
usage ();
exit (0);
}
}
}
if (mute_mode) {
fprintf (stderr, "\nwmTicTacToe %s - Copyright © 1999 André Ribeiro Camargo\n\n", WMTICTACTOE_VERSION);
fprintf (stderr, "Este software NÃO POSSUI NENHUMA GARANTIA; Este é um ");
fprintf (stderr, "software de livre \ndistribuição e você está autorizado a distribui-lo dentro de certas\n");
fprintf (stderr, "condições. Verifique a documentação do sistema para maiores detalhes.\n");
fprintf (stderr, "\n\n\"Thank you for shopping at Pop Mart\"-U2\n");
fprintf (stderr, "\nPlaying on %s mode... %s", isDeadmatch ? "deadmatch" : (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", isDeadmatch ? ":) <-> (:" : (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
}
principal (argc, argv);
}
// -------------------------------------------------------------------------------------------
// funcao: desenhaAdversario(int quadrante)
// descricao: desenha a jogada feita pelo adversario no tabuleiro
// in: quadrante - quadrante do tabuleiro
// out: nada
void
desenhaAdversario (int quadrante)
{
tabuleiro[quadrante] = LEGENDA_X;
copyXPMArea(97, 74, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
}
// -------------------------------------------------------------------------------------------
// funcao: desenhaJogador(int quadrante)
// descricao: desenha o jogador no tabuleiro
// in: quadrante - quadrante do tabuleiro
// out: nada
void
desenhaJogador (int quadrante)
{
tabuleiro[quadrante] = LEGENDA_USUARIO;
copyXPMArea (68, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
}
// --------------------------------------------------------------------------------------------
// funcao: desenhaX(int quadrante)
// descricao: desenha o X no tabuleiro
// in: quadrante - quadrante do tabuleiro
// out: nada
void
desenhaX (int quadrante)
{
if (isDeadmatch)
desenhaAdversario(quadrante);
else
if (game_mode == JOGO_DEFENSIVO)
copyXPMArea (96, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
else
copyXPMArea (110, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
}
// --------------------------------------------------------------------------------------------
// funcao: desenhaLimpa(int quadrante)
// descricao: apaga o jogador que estiver no quadrante especificando
// in: quadrante - quadrante do tabuleiro
// out: nada
void
desenhaLimpa (int quadrante)
{
copyXPMArea (82, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
}
// ---------------------------------------------------------------------------------------------
// funcao: desenhaAvisoJoga
// descricao: desenha "play" na tela
// in: nada
// out: nada
void
desenhaAvisoJoga (void)
{
if (isDeadmatch && adversario) {
copyXPMArea(68, 103, 60, 9, 4, 47);
copyXPMArea(71, 93, 16, 8, 5, 47);
return;
}
if (isDeadmatch && !adversario) {
copyXPMArea(68, 103, 60, 9, 4, 47);
return;
}
copyXPMArea (68, 13, 60, 9, 4, 47);
}
// ----------------------------------------------------------------------------------------------
// funcao: desenhaAvisoVoceVenceu
// descricao: desenha "you win" na tela
// in: nada
// out: nada
void
desenhaAvisoVoceVenceu (void)
{
if (isDeadmatch)
copyXPMArea (68, 83, 60, 9, 4, 47);
else
copyXPMArea (68, 23, 60, 9, 4, 47);
}
// -----------------------------------------------------------------------------------------------
// funcao: desenhaAvisoEuVenci
// descricao: desenha "I win" na tela
// in: nada
// out: nada
void
desenhaAvisoEuVenci (void)
{
if (isDeadmatch)
copyXPMArea (68, 93, 60, 9, 4, 47);
else
copyXPMArea (68, 33, 60, 9, 4, 47);
}
// -----------------------------------------------------------------------------------------------
// funcao: desenhaAvisoEmpate
// descricao: desenha "deuce" na tela
// in: nada
// out: nada
void
desenhaAvisoEmpate (void)
{
copyXPMArea (68, 43, 60, 9, 4, 47);
}
// -----------------------------------------------------------------------------------------------
// funcao: desenhaAvisoLimpa
// descricao: "apaga" os displays da tela
// in: nada
// out: nada
void
desenhaAvisoLimpa (void)
{
copyXPMArea (68, 53, 60, 9, 4, 47);
}
// ------------------------------------------------------------------------------------------------
// funcao: validaJogada
// descricao: Verifica se o quadrante jah nao estah ocupado
// in: quadrante
// out: 0 - quadrante ocupado
// 1 - quadrante disponivel, jogada valida!
int
validaJogada (int quadrante)
{
return ((quadrante > -1) ? tabuleiro[quadrante] == 0 : 0);
}
// ------------------------------------------------------------------------------------------------
// funcao: reseta_tabuleiro
// descricao: reseta o jogo
// in: nada
// out: nada
void
reseta_tabuleiro (void)
{
int i;
for (i = 0; i < 9; i++) {
tabuleiro[i] = LEGENDA_VAZIO;
desenhaLimpa (i);
livre[i] = i;
}
livre_max = i;
desenhaAvisoJoga ();
}
// ------------------------------------------------------------------------------------------------
// funcao: escolheJogador
// descricao: escolhe qual dos jogadores iniciarah a partida
// in: nada
// out: 0 - comeca pelo X
// 1 - comeca pelo Usuario
int
escolheJogador (void)
{
srand ((int) time (NULL));
adversario = ((int) ((float) random () / (float) RAND_MAX * 2));
return adversario;
}
// ------------------------------------------------------------------------------------------------
// funcao: verificaSequencia
// descricao: verifica se foi fechada alguma sequencia
// in: nada
// out: -2 - todos os quadrantes preenchido e nenhuma sequencia fechada, ou seja, empate!
// -1 - nao foi encontrado sequencia fechada
// > -1 - numero da sequencia fechada
int
verificaSequencia ()
{
/*
matriz d jogadas contem o numero da posicao
0 | 1 | 2
---+---+---
3 | 4 | 5
---+---+---
6 | 7 | 8
*/
int sucesso = 0;
int padrao;
int i;
for (i = 0; i < 8; i++) {
padrao = tabuleiro[sequencias[i][0]];
if (padrao == LEGENDA_VAZIO)
continue;
sucesso = ((tabuleiro[sequencias[i][1]] == padrao) &&
(tabuleiro[sequencias[i][2]] == padrao));
if (sucesso)
break;
}
// verifica se ha algum quadrante para se jogar
if (!sucesso && !livre_max)
return (-2);
return ((sucesso) ? i : -1);
}
// ------------------------------------------------------------------------------------
// funcao: game_over
// descricao: caso o jogo tenha acabado, pisca vencedor
// in: nada
// out: nada
void
game_over ()
{
if (verificaSequencia () != -1)
piscaVencedor ();
}
// -------------------------------------------------------------------------------------
// funcao: piscaVencedor
// descricao: pisca as jogadas da sequencia especifica vencedora
// in: nada
// out: nada
void
piscaVencedor ()
{
int mostra = 0;
int i;
int seq = verificaSequencia ();
int jogador = tabuleiro[sequencias[seq][0]];
XEvent Event;
// incrementa o score do vencedor
if (seq == -2) {
if (game_mode == JOGO_OFENSIVO)
(score_deuce_offensive > 98) ? score_deuce_offensive = 1 : score_deuce_offensive++;
else
(score_deuce_defensive > 98) ? score_deuce_defensive = 1 : score_deuce_defensive++;
} else
if (jogador == LEGENDA_X) {
if (game_mode == JOGO_OFENSIVO)
(score_X_offensive > 98) ? score_X_offensive = 1 : score_X_offensive++;
else
(score_X_defensive > 98) ? score_X_defensive = 1 : score_X_defensive++;
} else {
if (game_mode == JOGO_OFENSIVO)
(score_user_offensive > 98) ? score_user_offensive = 1 : score_user_offensive++;
else
(score_user_defensive > 98) ? score_user_defensive = 1 : score_user_defensive++;
}
if (!isDeadmatch)
writefile ();
while (1) {
RedrawWindow ();
usleep (BLINK);
while (XPending (display)) {
XNextEvent (display, &Event);
switch (Event.type) {
case Expose:
RedrawWindow ();
break;
case DestroyNotify:
XCloseDisplay (display);
exit (0);
break;
case ButtonRelease:
switch (Event.xbutton.button) {
case 3:
if (mostra_score ())
return;
break;
default:
reseta_tabuleiro ();
return;
}
}
}
if (mostra) {
if (seq == -2)
desenhaAvisoEmpate ();
else {
if (jogador == LEGENDA_USUARIO)
desenhaAvisoVoceVenceu ();
else
desenhaAvisoEuVenci ();
for (i = 0; i < 3; i++)
if (jogador == LEGENDA_USUARIO)
desenhaJogador (sequencias[seq][i]);
else
desenhaX (sequencias[seq][i]);
}
} else {
desenhaAvisoLimpa ();
if (seq != -2)
for (i = 0; i < 3; i++)
desenhaLimpa (sequencias[seq][i]);
}
mostra = !mostra;
}
}
// -------------------------------------------------------------------------------------
// funcao: escreve_placar
// descricao: escreve o placar do jogo na tela de score
// in: nada
// out: nada
void
escreve_placar ()
{
int i;
int coluna_xpm = 65;
int coluna_score[6] =
{8, 15, 26, 33, 43, 50 };
char placar[7];
if (isDeadmatch){
copyXPMArea(97, 74, 13, 9, 43, 88);
if (!mute_mode)
sprintf(placar,
"%.2d%.2d%.2d",
game_mode == JOGO_OFENSIVO ? score_user_offensive : score_user_defensive,
game_mode == JOGO_OFENSIVO ? score_deuce_offensive : score_deuce_defensive,
game_mode == JOGO_OFENSIVO ? score_X_offensive : score_X_defensive);
}
else
// desenha o glyph do X modo ofensivo no placar
if (game_mode == JOGO_OFENSIVO) {
copyXPMArea (110, 4, 13, 8, 43, 88);
if (!mute_mode)
sprintf(placar, "%.2d%.2d%.2d", score_user_offensive, score_deuce_offensive, score_X_offensive);
} else {
copyXPMArea (96, 4, 13, 8, 43, 88);
if (!mute_mode)
sprintf(placar, "%.2d%.2d%.2d", score_user_defensive, score_deuce_defensive, score_X_defensive);
}
for (i = 0; i < 6; i++)
copyXPMArea (coluna_xpm+((placar[i]-48)*6), 65, 6, 9, coluna_score[i], 100);
}
// -------------------------------------------------------------------------------------
// funcao: reseta_score
// descricao: zera o placar do jogo
// in: nada
// out: nada
void
reseta_score ()
{
score_X_offensive = 0;
score_user_offensive = 0;
score_deuce_offensive = 0;
score_X_defensive = 0;
score_user_defensive = 0;
score_deuce_defensive = 0;
score_opponent = 0;
writefile ();
escreve_placar ();
}
// -------------------------------------------------------------------------------------
// funcao: mostra_score
// descricao: mostra o placar e aguarda o usuario pressionar qq botao
// para voltar ao jogo
// in: nada
// out: 0: se o modo d jogo continua o mesmo
// 1: se o modo d jogo foi alterado
int
mostra_score ()
{
XEvent Event;
int game_mode_changed = 0;
escreve_placar ();
while (1) {
RedrawWindowXY (0, 60);
while (XPending (display)) {
XNextEvent (display, &Event);
switch (Event.type) {
case Expose:
RedrawWindow ();
break;
case DestroyNotify:
XCloseDisplay (display);
exit (0);
break;
case ButtonRelease:
if (Event.xbutton.button == 1 &&
!isDeadmatch) {
troca_game_mode ();
game_mode_changed = 1;
escreve_placar ();
} else
if (Event.xbutton.button == 2)
reseta_score ();
else
return (game_mode_changed);
}
}
usleep (USLEEP);
}
}
// ----------------------------------------------------------------------------------
// funcao: principal
// descricao: funcao principal do jogo
// in: argc - numero de argumentos passados por main()
// argv - matriz de strings com os argumentos passador por main()
// out: nada
void
principal (int argc, char **argv)
{
int i;
XEvent Event;
createXBMfromXPM (wmtictactoe_mask_bits, wmtictactoe_master_xpm, wmtictactoe_mask_width, wmtictactoe_mask_height);
openXwindow (argc, argv, wmtictactoe_master_xpm, wmtictactoe_mask_bits, wmtictactoe_mask_width, wmtictactoe_mask_height);
for (i = 0; i < MAX_MOUSE_REGION; i++)
AddMouseRegion (i, quadrantes[i].left, quadrantes[i].top, quadrantes[i].right, quadrantes[i].bottom);
reseta_tabuleiro ();
if (!isDeadmatch)
readfile ();
mostra_score ();
if (!isDeadmatch && escolheJogador ())
jogaX ();
desenhaAvisoJoga ();
while (1) {
RedrawWindow ();
while (XPending (display)) {
XNextEvent (display, &Event);
switch (Event.type) {
case Expose:
RedrawWindow ();
break;
case DestroyNotify:
XCloseDisplay (display);
exit (0);
break;
case ButtonRelease:
i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
switch (Event.xbutton.button) {
case 1:
if (validaJogada (i)) {
jogaHumano (i);
if (isDeadmatch)
desenhaAvisoJoga ();
else
jogaX ();
}
break;
case 2:
reseta_tabuleiro ();
break;
case 3:
mostra_score ();
}
}
}
usleep (USLEEP);
}
}
// ------------------------------------------------------------------------------
// funcao: livre_desempilha
// descricao: esta rotina retira o quadrante "quad" da matriz de posicoes vazias
// in: quadrante
// out: nada
void
livre_desempilha (int quad)
{
int i = 0;
// localiza quadrante no vetor de quadrantes livres
while (livre[i] < quad)
i++;
// desempilha
while (i < livre_max) {
livre[i] = livre[i + 1];
i++;
}
// seta o ultimo elemento como -1
// *assim fica + facil debugar :) *
livre[--livre_max] = -1;
}
// ------------------------------------------------------------------------------
// funcao: tapa_buraco
// descricao: verifica se o usuario nao estah por fechar alguma sequencia,
// retornando o quadrante onde o X deverah jogar para anular a jogada
// in: nada
// out: -1 - nao ha buraco
// > -1 - quadrante que tapa
int
tapa_buraco (void)
{
int sucesso = 0;
int desocupado, seta;
int i, i2;
for (i = 0; i < 8; i++) {
sucesso = 0;
desocupado = 0;
seta = 0;
for (i2 = 0; i2 < 3; i2++) {
if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
sucesso++;
if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO) {
desocupado = sequencias[i][i2];
seta = 1;
}
}
if ((sucesso == 2) && seta)
return (desocupado);
}
return (-1);
}
// ------------------------------------------------------------------------------
// funcao: tenta_fechar
// descricao: verifica se nao existe alguma sequencia do jogador X por fechar
// in: nada
// out: -1 - nao ha sequencia
// > -1 - quadrante que fecha
int
tenta_fechar (void)
{
int sucesso;
int desocupado, seta;
int i, i2;
for (i = 0; i < 8; i++) {
sucesso = 0;
desocupado = 0;
seta = 0;
for (i2 = 0; i2 < 3; i2++) {
if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
sucesso++;
if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO) {
desocupado = sequencias[i][i2];
seta = 1;
}
}
if ((sucesso == 2) && seta)
return (desocupado);
}
return (-1);
}
// ------------------------------------------------------------------------------
// funcao: chuta_jogada
// descricao: como ultima opcao de jogada para X, chuta um quadrante qualquer
// in: nada
// out: quadrante livre
int
chuta_jogada (void)
{
srand ((int) time (NULL));
return (livre[(int) ((float) random () / (float) RAND_MAX * livre_max)]);
}
// ------------------------------------------------------------------------------
// funcao: analisa_jogo
// descricao: analisa a melhor jogada, verificando as chances de cada jogador
// in: nada
// out: -1 - nao ha sequencia
// > -1 - quadrante para tentar criar sequencia
int
analisa_jogo (void)
{
int jogadas_usuario;
int jogadas_X;
int i, i2, maior_chance_X, maior_chance_usuario;
int status_jogo[8][2]; // numero de jogadas em cada sequencia
int chance[9][2];
int possibilidades_de_jogadas[9];
int limite_possibilidades;
// contabiliza o numero de jogadas do usuario e do X
for (i = 0; i < 8; i++) {
jogadas_usuario = 0;
jogadas_X = 0;
for (i2 = 0; i2 < 3; i2++) {
if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
jogadas_usuario++;
if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
jogadas_X++;
}
status_jogo[i][0] = jogadas_X;
status_jogo[i][1] = jogadas_usuario;
}
// zera a matriz... *preguiça*
for (i = 0; i < 9; i++) {
chance[i][0] = 0;
chance[i][1] = 0;
}
// estima a chance de jogo em cada _quadrante_ para cada jogador
for (i = 0; i < 8; i++)
for (i2 = 0; i2 < 3; i2++) {
if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO && status_jogo[i][0] > 0 && status_jogo[i][1] == 0)
chance[sequencias[i][i2]][0]++;
if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO && status_jogo[i][1] > 0 && status_jogo[i][0] == 0)
chance[sequencias[i][i2]][1]++;
}
// rotina p'ra verificar se existe alguma chance
// se nao houver, cai fora...
for (i = 0; i < 8 && (((chance[i][0] == chance[i][1]) == chance[i][0]) == 0); i++);
if (i == 8)
return(-1);
// seleciona _quadrante_ com maior probabilidade d jogo
// aqui a porca torce o rabo... :DDDD
limite_possibilidades = 0;
maior_chance_X = -1;
maior_chance_usuario = -1;
for (i = 0; i < 9; i++) {
if ( game_mode == JOGO_DEFENSIVO ? chance[i][1] > maior_chance_usuario : chance[i][0] > maior_chance_X) {
limite_possibilidades = 0;
possibilidades_de_jogadas[limite_possibilidades] = i;
maior_chance_X = chance[i][0];
maior_chance_usuario = chance[i][1];
} else {
if ( game_mode == JOGO_DEFENSIVO ? chance[i][1] == maior_chance_usuario : chance[i][0] == maior_chance_X) {
if ( game_mode == JOGO_DEFENSIVO ? chance[i][0] > maior_chance_X : chance[i][1] > maior_chance_usuario) {
limite_possibilidades = 0;
possibilidades_de_jogadas[limite_possibilidades] = i;
if (game_mode == JOGO_DEFENSIVO)
maior_chance_X = chance[i][0];
else
maior_chance_usuario = chance[i][1];
} else if ( game_mode == JOGO_DEFENSIVO ? chance[i][0] == maior_chance_X : chance[i][1] == maior_chance_usuario) {
limite_possibilidades++;
possibilidades_de_jogadas[limite_possibilidades] = i;
}
}
}
}
// seleciona a jogadas que estao em "limite_possibilidades"
i = (float) random () / (float) RAND_MAX * (limite_possibilidades+1);
return(possibilidades_de_jogadas[i]);
}
// ------------------------------------------------------------------------------
// funcao: tenta_matar_jogada
// descricao: procura matar uma sequencia que o usuario planeja fazer
// in: nada
// out: -1 - nao ha sequencia
// > -1 - quadrante para tentar criar sequen`cia
int
tenta_matar_jogada (void)
{
int sucesso;
int jogadasX;
int i, i2, maior_chance, opcao_escolhida, nr_opcoes;
int p = -1;
int provavel_jogada[8][2];
int chance[9] =
{0, 0, 0, 0, 0, 0, 0, 0, 0};
// procura por jogadas em aberto,
// contabilizando o numero de quadrantes jah ocupados das sequencias
for (i = 0; i < 8; i++) {
sucesso = 0;
jogadasX = 0;
for (i2 = 0; i2 < 3; i2++) {
if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
sucesso++;
if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
jogadasX++;
}
if (jogadasX == 0) {
p++;
provavel_jogada[p][0] = i;
provavel_jogada[p][1] = sucesso;
}
}
// procura jogar nas sequencias q jah tem casa preenchida
if (p >= 0) {
for (i = 0; i <= p; i++)
if (provavel_jogada[i][1] >= 0)
for (i2 = 0; i2 < 3; i2++)
if (tabuleiro[sequencias[provavel_jogada[i][0]][i2]] == LEGENDA_VAZIO)
chance[sequencias[provavel_jogada[i][0]][i2]]++;
maior_chance = chance[0];
nr_opcoes = 1;
for (i = 1; i <= 8; i++) {
if (maior_chance < chance[i]) {
nr_opcoes = 1;
maior_chance = chance[i];
} else {
if (maior_chance == chance[i]) {
nr_opcoes++;
}
}
}
opcao_escolhida = (float) random () / (float) RAND_MAX *(nr_opcoes);
i2 = 0;
for (i = 0; i <= 8; i++) {
if ((maior_chance == chance[i]) && (maior_chance >= 1)) {
if (i2 == opcao_escolhida)
return (i);
i2++;
}
}
}
// se nao tiver jeito, passa adiante... :)
return (-1);
}
// ------------------------------------------------------------------------------
// funcao: jogaX
// descricao: cerebro do jogador X, nesta rotina que ele escolhe onde jogara
// in: nada
// out: nada
void
jogaX (void)
{
int q;
q = tenta_fechar ();
if (q == -1)
q = tapa_buraco ();
if (q == -1)
q = analisa_jogo ();
if (q == -1)
q = chuta_jogada();
livre_desempilha (q);
tabuleiro[q] = LEGENDA_X;
desenhaX (q);
game_over ();
}
// ------------------------------------------------------------------------------
// funcao: jogaHumano
// descricao: rotina de verificacao da jogada do usuario
// in: quadrante clicado pelo usuario
// out: game over?
void
jogaHumano (int quadrante)
{
if (adversario && isDeadmatch)
desenhaAdversario (quadrante);
else
desenhaJogador (quadrante);
adversario = !adversario;
livre_desempilha (quadrante);
game_over ();
}
// ------------------------------------------------------------------------------
// funcao: usage
// descricao: help da aplicacao
// in: nada
// out: nada
void
usage (void)
{
fprintf (stderr, "\nwmTicTacToe %s - The Ultimate TicTacToe for WindowMaker... :) \n", WMTICTACTOE_VERSION);
fprintf (stderr, "Copyright © 1999 André Ribeiro Camargo\n\n");
fprintf (stderr, "usage:\n");
fprintf (stderr, "\t-display <display name>\n");
fprintf (stderr, "\t-deadmatch\n");
fprintf (stderr, "\t-h\tthis screen\n");
fprintf (stderr, "\t-v\tprint the version number\n");
fprintf (stderr, "\t-o\tofensive mode\n");
fprintf (stderr, "\t-q\tquiet mode(for Debian's user)\n");
fprintf (stderr, "\t\tdefault: defensive mode\n");
fprintf (stderr, "\n");
}
// ------------------------------------------------------------------------------
// funcao: printversion
// descricao: imprime a versao da aplicacao
// in: nada
// out: nada
void
printversion (void)
{
if (!strcmp (ProgName, "wmtictactoe"))
fprintf (stderr, "%s\n", WMTICTACTOE_VERSION);
}
// ------------------------------------------------------------------------------
// funcao: readfile
// descricao: lê o arquivo de configuracao da aplicação
// in: nada
// out: nada
void
readfile (void)
{
FILE *rcfile;
char rcfilen[256];
char buf[256];
int done;
sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
if ((rcfile=fopen(rcfilen, "r")) != NULL){
do {
fgets(buf, 250, rcfile);
if((done = feof(rcfile)) == 0){
buf[strlen(buf)-1]=0;
if(strncmp(buf, "score_user_offensive ", strlen("score_user "))==0)
sscanf(buf, "score_user_offensive %i", &score_user_offensive);
if(strncmp(buf, "score_X_offensive ", strlen("score_X "))==0)
sscanf(buf, "score_X_offensive %i", &score_X_offensive);
if(strncmp(buf, "score_deuce_offensive ", strlen("score_deuce "))==0)
sscanf(buf, "score_deuce_offensive %i", &score_deuce_offensive);
if(strncmp(buf, "score_user_defensive ", strlen("score_user "))==0)
sscanf(buf, "score_user_defensive %i", &score_user_defensive);
if(strncmp(buf, "score_X_defensive ", strlen("score_X "))==0)
sscanf(buf, "score_X_defensive %i", &score_X_defensive);
if(strncmp(buf, "score_deuce_defensive ", strlen("score_deuce "))==0)
sscanf(buf, "score_deuce_defensive %i", &score_deuce_defensive);
}
} while(done == 0);
fclose(rcfile);
}
}
// ------------------------------------------------------------------------------
// funcao: writefile
// descricao: grava o arquivo de configuracao da aplicação
// in: nada
// out: nada
void
writefile (void)
{
FILE *rcfile;
char rcfilen[256];
sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
if ((rcfile=fopen(rcfilen, "w")) != NULL){
fprintf(rcfile, "score_user_offensive %d\nscore_deuce_offensive %d\nscore_X_offensive %d\n", score_user_offensive, score_deuce_offensive, score_X_offensive);
fprintf(rcfile, "score_user_defensive %d\nscore_deuce_defensive %d\nscore_X_defensive %d\n", score_user_defensive, score_deuce_defensive, score_X_defensive);
fclose(rcfile);
}
}
// ------------------------------------------------------------------------------
// funcao: troca_game_mode
// descricao: troca o modo de jogo
// in: nada
// out: nada
void
troca_game_mode (void)
{
game_mode = !game_mode;
if (!mute_mode)
fprintf (stderr, "\nPlaying on %s mode... %s", (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
reseta_tabuleiro ();
}