Remove trailing whitespace
[dockapps.git] / wmtictactoe / wmtictactoe / wmtictactoe.c
blobf1dbd1509624247e3647929f288c6b1559d03b93
1 /*
2 wmtictactoe - the ultimate tictactoe for WindowMaker
3 =-=-=-=-=-= ======================================
4 Copyright (C) 1999 André R. Camargo
6 Este programa é um software de livre distribuição, que pode ser copiado e
7 distribuído sob os termos da Licença Pública Geral GNU, conforme publicada
8 pela Free Software Foundation, versão 2 da licença ou (a critério do autor)
9 qualquer versão posterior.
11 Este programa é distribuído na expectativa de ser útil aos seus usuários,
12 porém NÃO TEM NENHUMA GARANTIA, EXPLÍCITAS OU IMPLÍCITAS, COMERCIAIS OU DE
13 ATENDIMENTO A UMA DETERMINADA FINALIDADE. Consulte a Licença Pública Geral
14 GNU para maiores detalhes.
16 Deve haver uma cópia da Licença Pública Geral GNU junto com este software
17 em inglês ou português. Caso não haja escreva para
18 Free Software Foundation, Inc.
19 675 Mass Ave,
20 Cambridge, MA 02139, USA.
22 acamargo@conesul.com.br
23 André Ribeiro Camargo
24 Rua Silveira Martins, 592/102
25 Centro
26 Canguçu-RS-Brasil
27 CEP 96.600-000
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <string.h>
36 #include <X11/Xlib.h>
37 #include <X11/xpm.h>
38 #include <X11/extensions/shape.h>
40 #include <libdockapp/wmgeneral.h>
41 #include "wmtictactoe-master.xpm"
43 // ---------------------------------------------------------------
44 // definicoes :)
46 #define WMTICTACTOE_VERSION "1.1"
48 #define TRUE 1
49 #define FALSE 0
51 #define USLEEP 20000
52 #define BLINK 200000
54 #define LEGENDA_VAZIO 0
55 #define LEGENDA_USUARIO 1
56 #define LEGENDA_X 2
58 #define JOGO_OFENSIVO 0
59 #define JOGO_DEFENSIVO 1
61 // ---------------------------------------------------------------
62 // Variáveis Globais
64 char *ProgName;
66 typedef struct {
67 int left;
68 int top;
69 int right;
70 int bottom;
71 } regioes;
73 regioes quadrantes[MAX_MOUSE_REGION] =
75 {5, 8, 20, 18},
76 {24, 8, 40, 18},
77 {43, 8, 57, 18},
78 {5, 20, 20, 30},
79 {24, 20, 40, 30},
80 {43, 20, 57, 30},
81 {5, 33, 20, 44},
82 {24, 33, 40, 44},
83 {43, 33, 57, 44}};
85 int tabuleiro[9] =
86 {LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO,
87 LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO,
88 LEGENDA_VAZIO, LEGENDA_VAZIO, LEGENDA_VAZIO};
90 int sequencias[8][3] =
92 {0, 1, 2},
93 {3, 4, 5},
94 {6, 7, 8},
95 {0, 3, 6},
96 {1, 4, 7},
97 {2, 5, 8},
98 {0, 4, 8},
99 {2, 4, 6}};
101 int livre[9] =
102 {0, 1, 2, 3, 4, 5, 6, 7, 8};
103 int livre_max;
104 int game_mode;
105 int mute_mode;
106 int score_user_offensive = 0;
107 int score_X_offensive = 0;
108 int score_deuce_offensive = 0;
109 int score_user_defensive = 0;
110 int score_X_defensive = 0;
111 int score_deuce_defensive = 0;
112 int score_opponent = 0;
113 // modo padrao eh jogar contra o micro
114 // por isso deadmatch leva um FALSE
115 int isDeadmatch = FALSE;
116 int adversario = TRUE;
118 // mascara
119 char wmtictactoe_mask_bits[64 * 64];
120 int wmtictactoe_mask_width = 64;
121 int wmtictactoe_mask_height = 64;
123 // ----------------------------------------------------------
124 // declaracao das funcoes do sistema
126 void main (int argc, char *argv[]);
127 void usage (void);
128 void printversion (void);
129 void readfile (void);
130 void writefile (void);
132 void desenhaJogador (int);
133 void desenhaX (int);
134 void desenhaAdversario (int);
135 void desenhaLimpa (int);
136 void desenhaAvisoJoga (void);
137 void desenhaAvisoLimpa (void);
138 void desenhaAvisoVoceVenceu (void);
139 void desenhaAvisoEuVenci (void);
140 void desenhaAvisoEmpate (void);
142 int mostra_score (void);
143 void escreve_placar (void);
144 void reseta_score (void);
145 void piscaVencedor (void);
146 void troca_game_mode (void);
148 void reseta_tabuleiro (void);
149 void livre_desempilha (int);
151 void principal (int, char **);
152 int escolheJogador (void);
154 void joga (int);
155 void jogaHumano (int);
157 void jogaX (void);
158 int tapa_buraco (void);
159 int analisa_jogo (void);
160 int chuta_jogada (void);
162 int validaJogada (int);
163 void game_over (void);
165 // -------------------------------------------------------------------------------------------
166 // funcao: main()
167 // descricao: funcao principal da linguagem
168 // in: argc - numero de argumentos passados por linha d comando
169 // argv - vetor com os argumentos
170 // out: nada
171 void main (int argc, char *argv[])
173 int i;
175 ProgName = argv[0];
176 if (strlen (ProgName) >= 11)
177 ProgName += (strlen (ProgName) - 11);
179 game_mode = JOGO_DEFENSIVO;
180 mute_mode = FALSE;
182 for (i = 1; i < argc; i++) {
183 char *arg = argv[i];
185 if (*arg == '-') {
186 switch (arg[1]) {
187 case 'o':
188 game_mode = JOGO_OFENSIVO;
189 break;
190 case 'd':
191 printf("%s", arg+1);
192 if (strcmp (arg + 1, "deadmatch") == 0) {
193 isDeadmatch = TRUE;
194 break;
196 if (strcmp (arg + 1, "display") == 0)
197 break;
198 usage ();
199 exit (1);
200 case 'v':
201 printversion ();
202 exit (0);
203 case 'q':
204 mute_mode = TRUE;
205 break;
206 default:
207 usage ();
208 exit (0);
213 if (mute_mode) {
214 fprintf (stderr, "\nwmTicTacToe %s - Copyright © 1999 André Ribeiro Camargo\n\n", WMTICTACTOE_VERSION);
215 fprintf (stderr, "Este software NÃO POSSUI NENHUMA GARANTIA; Este é um ");
216 fprintf (stderr, "software de livre \ndistribuição e você está autorizado a distribui-lo dentro de certas\n");
217 fprintf (stderr, "condições. Verifique a documentação do sistema para maiores detalhes.\n");
218 fprintf (stderr, "\n\n\"Thank you for shopping at Pop Mart\"-U2\n");
220 fprintf (stderr, "\nPlaying on %s mode... %s", isDeadmatch ? "deadmatch" : (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", isDeadmatch ? ":) <-> (:" : (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
223 principal (argc, argv);
226 // -------------------------------------------------------------------------------------------
227 // funcao: desenhaAdversario(int quadrante)
228 // descricao: desenha a jogada feita pelo adversario no tabuleiro
229 // in: quadrante - quadrante do tabuleiro
230 // out: nada
231 void
232 desenhaAdversario (int quadrante)
234 tabuleiro[quadrante] = LEGENDA_X;
235 copyXPMArea(97, 74, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
238 // -------------------------------------------------------------------------------------------
239 // funcao: desenhaJogador(int quadrante)
240 // descricao: desenha o jogador no tabuleiro
241 // in: quadrante - quadrante do tabuleiro
242 // out: nada
243 void
244 desenhaJogador (int quadrante)
246 tabuleiro[quadrante] = LEGENDA_USUARIO;
247 copyXPMArea (68, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
250 // --------------------------------------------------------------------------------------------
251 // funcao: desenhaX(int quadrante)
252 // descricao: desenha o X no tabuleiro
253 // in: quadrante - quadrante do tabuleiro
254 // out: nada
255 void
256 desenhaX (int quadrante)
258 if (isDeadmatch)
259 desenhaAdversario(quadrante);
260 else
261 if (game_mode == JOGO_DEFENSIVO)
262 copyXPMArea (96, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
263 else
264 copyXPMArea (110, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
267 // --------------------------------------------------------------------------------------------
268 // funcao: desenhaLimpa(int quadrante)
269 // descricao: apaga o jogador que estiver no quadrante especificando
270 // in: quadrante - quadrante do tabuleiro
271 // out: nada
272 void
273 desenhaLimpa (int quadrante)
275 copyXPMArea (82, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
278 // ---------------------------------------------------------------------------------------------
279 // funcao: desenhaAvisoJoga
280 // descricao: desenha "play" na tela
281 // in: nada
282 // out: nada
283 void
284 desenhaAvisoJoga (void)
286 if (isDeadmatch && adversario) {
287 copyXPMArea(68, 103, 60, 9, 4, 47);
288 copyXPMArea(71, 93, 16, 8, 5, 47);
289 return;
291 if (isDeadmatch && !adversario) {
292 copyXPMArea(68, 103, 60, 9, 4, 47);
293 return;
296 copyXPMArea (68, 13, 60, 9, 4, 47);
299 // ----------------------------------------------------------------------------------------------
300 // funcao: desenhaAvisoVoceVenceu
301 // descricao: desenha "you win" na tela
302 // in: nada
303 // out: nada
304 void
305 desenhaAvisoVoceVenceu (void)
307 if (isDeadmatch)
308 copyXPMArea (68, 83, 60, 9, 4, 47);
309 else
310 copyXPMArea (68, 23, 60, 9, 4, 47);
313 // -----------------------------------------------------------------------------------------------
314 // funcao: desenhaAvisoEuVenci
315 // descricao: desenha "I win" na tela
316 // in: nada
317 // out: nada
318 void
319 desenhaAvisoEuVenci (void)
321 if (isDeadmatch)
322 copyXPMArea (68, 93, 60, 9, 4, 47);
323 else
324 copyXPMArea (68, 33, 60, 9, 4, 47);
327 // -----------------------------------------------------------------------------------------------
328 // funcao: desenhaAvisoEmpate
329 // descricao: desenha "deuce" na tela
330 // in: nada
331 // out: nada
332 void
333 desenhaAvisoEmpate (void)
335 copyXPMArea (68, 43, 60, 9, 4, 47);
338 // -----------------------------------------------------------------------------------------------
339 // funcao: desenhaAvisoLimpa
340 // descricao: "apaga" os displays da tela
341 // in: nada
342 // out: nada
343 void
344 desenhaAvisoLimpa (void)
346 copyXPMArea (68, 53, 60, 9, 4, 47);
349 // ------------------------------------------------------------------------------------------------
350 // funcao: validaJogada
351 // descricao: Verifica se o quadrante jah nao estah ocupado
352 // in: quadrante
353 // out: 0 - quadrante ocupado
354 // 1 - quadrante disponivel, jogada valida!
356 validaJogada (int quadrante)
358 return ((quadrante > -1) ? tabuleiro[quadrante] == 0 : 0);
361 // ------------------------------------------------------------------------------------------------
362 // funcao: reseta_tabuleiro
363 // descricao: reseta o jogo
364 // in: nada
365 // out: nada
366 void
367 reseta_tabuleiro (void)
369 int i;
371 for (i = 0; i < 9; i++) {
372 tabuleiro[i] = LEGENDA_VAZIO;
373 desenhaLimpa (i);
374 livre[i] = i;
376 livre_max = i;
378 desenhaAvisoJoga ();
381 // ------------------------------------------------------------------------------------------------
382 // funcao: escolheJogador
383 // descricao: escolhe qual dos jogadores iniciarah a partida
384 // in: nada
385 // out: 0 - comeca pelo X
386 // 1 - comeca pelo Usuario
388 escolheJogador (void)
390 srand ((int) time (NULL));
391 adversario = ((int) ((float) random () / (float) RAND_MAX * 2));
392 return adversario;
395 // ------------------------------------------------------------------------------------------------
396 // funcao: verificaSequencia
397 // descricao: verifica se foi fechada alguma sequencia
398 // in: nada
399 // out: -2 - todos os quadrantes preenchido e nenhuma sequencia fechada, ou seja, empate!
400 // -1 - nao foi encontrado sequencia fechada
401 // > -1 - numero da sequencia fechada
403 verificaSequencia ()
406 matriz d jogadas contem o numero da posicao
408 0 | 1 | 2
409 ---+---+---
410 3 | 4 | 5
411 ---+---+---
412 6 | 7 | 8
415 int sucesso = 0;
416 int padrao;
417 int i;
419 for (i = 0; i < 8; i++) {
420 padrao = tabuleiro[sequencias[i][0]];
421 if (padrao == LEGENDA_VAZIO)
422 continue;
423 sucesso = ((tabuleiro[sequencias[i][1]] == padrao) &&
424 (tabuleiro[sequencias[i][2]] == padrao));
425 if (sucesso)
426 break;
429 // verifica se ha algum quadrante para se jogar
430 if (!sucesso && !livre_max)
431 return (-2);
433 return ((sucesso) ? i : -1);
436 // ------------------------------------------------------------------------------------
437 // funcao: game_over
438 // descricao: caso o jogo tenha acabado, pisca vencedor
439 // in: nada
440 // out: nada
441 void
442 game_over ()
444 if (verificaSequencia () != -1)
445 piscaVencedor ();
448 // -------------------------------------------------------------------------------------
449 // funcao: piscaVencedor
450 // descricao: pisca as jogadas da sequencia especifica vencedora
451 // in: nada
452 // out: nada
453 void
454 piscaVencedor ()
456 int mostra = 0;
457 int i;
458 int seq = verificaSequencia ();
459 int jogador = tabuleiro[sequencias[seq][0]];
460 XEvent Event;
462 // incrementa o score do vencedor
463 if (seq == -2) {
464 if (game_mode == JOGO_OFENSIVO)
465 (score_deuce_offensive > 98) ? score_deuce_offensive = 1 : score_deuce_offensive++;
466 else
467 (score_deuce_defensive > 98) ? score_deuce_defensive = 1 : score_deuce_defensive++;
468 } else
469 if (jogador == LEGENDA_X) {
470 if (game_mode == JOGO_OFENSIVO)
471 (score_X_offensive > 98) ? score_X_offensive = 1 : score_X_offensive++;
472 else
473 (score_X_defensive > 98) ? score_X_defensive = 1 : score_X_defensive++;
474 } else {
475 if (game_mode == JOGO_OFENSIVO)
476 (score_user_offensive > 98) ? score_user_offensive = 1 : score_user_offensive++;
477 else
478 (score_user_defensive > 98) ? score_user_defensive = 1 : score_user_defensive++;
481 if (!isDeadmatch)
482 writefile ();
484 while (1) {
485 RedrawWindow ();
487 usleep (BLINK);
488 while (XPending (display)) {
489 XNextEvent (display, &Event);
490 switch (Event.type) {
491 case Expose:
492 RedrawWindow ();
493 break;
494 case DestroyNotify:
495 XCloseDisplay (display);
496 exit (0);
497 break;
498 case ButtonRelease:
499 switch (Event.xbutton.button) {
500 case 3:
501 if (mostra_score ())
502 return;
503 break;
504 default:
505 reseta_tabuleiro ();
506 return;
511 if (mostra) {
512 if (seq == -2)
513 desenhaAvisoEmpate ();
514 else {
515 if (jogador == LEGENDA_USUARIO)
516 desenhaAvisoVoceVenceu ();
517 else
518 desenhaAvisoEuVenci ();
519 for (i = 0; i < 3; i++)
520 if (jogador == LEGENDA_USUARIO)
521 desenhaJogador (sequencias[seq][i]);
522 else
523 desenhaX (sequencias[seq][i]);
525 } else {
526 desenhaAvisoLimpa ();
527 if (seq != -2)
528 for (i = 0; i < 3; i++)
529 desenhaLimpa (sequencias[seq][i]);
531 mostra = !mostra;
535 // -------------------------------------------------------------------------------------
536 // funcao: escreve_placar
537 // descricao: escreve o placar do jogo na tela de score
538 // in: nada
539 // out: nada
540 void
541 escreve_placar ()
543 int i;
544 int coluna_xpm = 65;
545 int coluna_score[6] =
546 {8, 15, 26, 33, 43, 50 };
547 char placar[7];
549 if (isDeadmatch){
550 copyXPMArea(97, 74, 13, 9, 43, 88);
551 if (!mute_mode)
552 sprintf(placar,
553 "%.2d%.2d%.2d",
554 game_mode == JOGO_OFENSIVO ? score_user_offensive : score_user_defensive,
555 game_mode == JOGO_OFENSIVO ? score_deuce_offensive : score_deuce_defensive,
556 game_mode == JOGO_OFENSIVO ? score_X_offensive : score_X_defensive);
558 else
559 // desenha o glyph do X modo ofensivo no placar
560 if (game_mode == JOGO_OFENSIVO) {
561 copyXPMArea (110, 4, 13, 8, 43, 88);
562 if (!mute_mode)
563 sprintf(placar, "%.2d%.2d%.2d", score_user_offensive, score_deuce_offensive, score_X_offensive);
564 } else {
565 copyXPMArea (96, 4, 13, 8, 43, 88);
566 if (!mute_mode)
567 sprintf(placar, "%.2d%.2d%.2d", score_user_defensive, score_deuce_defensive, score_X_defensive);
570 for (i = 0; i < 6; i++)
571 copyXPMArea (coluna_xpm+((placar[i]-48)*6), 65, 6, 9, coluna_score[i], 100);
574 // -------------------------------------------------------------------------------------
575 // funcao: reseta_score
576 // descricao: zera o placar do jogo
577 // in: nada
578 // out: nada
579 void
580 reseta_score ()
582 score_X_offensive = 0;
583 score_user_offensive = 0;
584 score_deuce_offensive = 0;
585 score_X_defensive = 0;
586 score_user_defensive = 0;
587 score_deuce_defensive = 0;
588 score_opponent = 0;
590 writefile ();
592 escreve_placar ();
595 // -------------------------------------------------------------------------------------
596 // funcao: mostra_score
597 // descricao: mostra o placar e aguarda o usuario pressionar qq botao
598 // para voltar ao jogo
599 // in: nada
600 // out: 0: se o modo d jogo continua o mesmo
601 // 1: se o modo d jogo foi alterado
603 mostra_score ()
605 XEvent Event;
606 int game_mode_changed = 0;
608 escreve_placar ();
609 while (1) {
610 RedrawWindowXY (0, 60);
612 while (XPending (display)) {
613 XNextEvent (display, &Event);
614 switch (Event.type) {
615 case Expose:
616 RedrawWindow ();
617 break;
618 case DestroyNotify:
619 XCloseDisplay (display);
620 exit (0);
621 break;
622 case ButtonRelease:
623 if (Event.xbutton.button == 1 &&
624 !isDeadmatch) {
625 troca_game_mode ();
626 game_mode_changed = 1;
627 escreve_placar ();
628 } else
629 if (Event.xbutton.button == 2)
630 reseta_score ();
631 else
632 return (game_mode_changed);
636 usleep (USLEEP);
640 // ----------------------------------------------------------------------------------
641 // funcao: principal
642 // descricao: funcao principal do jogo
643 // in: argc - numero de argumentos passados por main()
644 // argv - matriz de strings com os argumentos passador por main()
645 // out: nada
646 void
647 principal (int argc, char **argv)
649 int i;
650 XEvent Event;
652 createXBMfromXPM (wmtictactoe_mask_bits, wmtictactoe_master_xpm, wmtictactoe_mask_width, wmtictactoe_mask_height);
653 openXwindow (argc, argv, wmtictactoe_master_xpm, wmtictactoe_mask_bits, wmtictactoe_mask_width, wmtictactoe_mask_height);
655 for (i = 0; i < MAX_MOUSE_REGION; i++)
656 AddMouseRegion (i, quadrantes[i].left, quadrantes[i].top, quadrantes[i].right, quadrantes[i].bottom);
658 reseta_tabuleiro ();
660 if (!isDeadmatch)
661 readfile ();
662 mostra_score ();
664 if (!isDeadmatch && escolheJogador ())
665 jogaX ();
667 desenhaAvisoJoga ();
669 while (1) {
670 RedrawWindow ();
672 while (XPending (display)) {
673 XNextEvent (display, &Event);
674 switch (Event.type) {
675 case Expose:
676 RedrawWindow ();
677 break;
678 case DestroyNotify:
679 XCloseDisplay (display);
680 exit (0);
681 break;
682 case ButtonRelease:
683 i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
684 switch (Event.xbutton.button) {
685 case 1:
686 if (validaJogada (i)) {
687 jogaHumano (i);
688 if (isDeadmatch)
689 desenhaAvisoJoga ();
690 else
691 jogaX ();
693 break;
694 case 2:
695 reseta_tabuleiro ();
696 break;
697 case 3:
698 mostra_score ();
703 usleep (USLEEP);
708 // ------------------------------------------------------------------------------
709 // funcao: livre_desempilha
710 // descricao: esta rotina retira o quadrante "quad" da matriz de posicoes vazias
711 // in: quadrante
712 // out: nada
713 void
714 livre_desempilha (int quad)
716 int i = 0;
718 // localiza quadrante no vetor de quadrantes livres
719 while (livre[i] < quad)
720 i++;
722 // desempilha
723 while (i < livre_max) {
724 livre[i] = livre[i + 1];
725 i++;
728 // seta o ultimo elemento como -1
729 // *assim fica + facil debugar :) *
730 livre[--livre_max] = -1;
733 // ------------------------------------------------------------------------------
734 // funcao: tapa_buraco
735 // descricao: verifica se o usuario nao estah por fechar alguma sequencia,
736 // retornando o quadrante onde o X deverah jogar para anular a jogada
737 // in: nada
738 // out: -1 - nao ha buraco
739 // > -1 - quadrante que tapa
741 tapa_buraco (void)
743 int sucesso = 0;
744 int desocupado, seta;
745 int i, i2;
747 for (i = 0; i < 8; i++) {
748 sucesso = 0;
749 desocupado = 0;
750 seta = 0;
751 for (i2 = 0; i2 < 3; i2++) {
752 if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
753 sucesso++;
754 if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO) {
755 desocupado = sequencias[i][i2];
756 seta = 1;
759 if ((sucesso == 2) && seta)
760 return (desocupado);
762 return (-1);
765 // ------------------------------------------------------------------------------
766 // funcao: tenta_fechar
767 // descricao: verifica se nao existe alguma sequencia do jogador X por fechar
768 // in: nada
769 // out: -1 - nao ha sequencia
770 // > -1 - quadrante que fecha
772 tenta_fechar (void)
774 int sucesso;
775 int desocupado, seta;
776 int i, i2;
778 for (i = 0; i < 8; i++) {
779 sucesso = 0;
780 desocupado = 0;
781 seta = 0;
782 for (i2 = 0; i2 < 3; i2++) {
783 if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
784 sucesso++;
785 if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO) {
786 desocupado = sequencias[i][i2];
787 seta = 1;
790 if ((sucesso == 2) && seta)
791 return (desocupado);
793 return (-1);
796 // ------------------------------------------------------------------------------
797 // funcao: chuta_jogada
798 // descricao: como ultima opcao de jogada para X, chuta um quadrante qualquer
799 // in: nada
800 // out: quadrante livre
802 chuta_jogada (void)
804 srand ((int) time (NULL));
805 return (livre[(int) ((float) random () / (float) RAND_MAX * livre_max)]);
808 // ------------------------------------------------------------------------------
809 // funcao: analisa_jogo
810 // descricao: analisa a melhor jogada, verificando as chances de cada jogador
811 // in: nada
812 // out: -1 - nao ha sequencia
813 // > -1 - quadrante para tentar criar sequencia
815 analisa_jogo (void)
817 int jogadas_usuario;
818 int jogadas_X;
819 int i, i2, maior_chance_X, maior_chance_usuario;
820 int status_jogo[8][2]; // numero de jogadas em cada sequencia
821 int chance[9][2];
822 int possibilidades_de_jogadas[9];
823 int limite_possibilidades;
825 // contabiliza o numero de jogadas do usuario e do X
826 for (i = 0; i < 8; i++) {
827 jogadas_usuario = 0;
828 jogadas_X = 0;
829 for (i2 = 0; i2 < 3; i2++) {
830 if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
831 jogadas_usuario++;
832 if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
833 jogadas_X++;
835 status_jogo[i][0] = jogadas_X;
836 status_jogo[i][1] = jogadas_usuario;
839 // zera a matriz... *preguiça*
840 for (i = 0; i < 9; i++) {
841 chance[i][0] = 0;
842 chance[i][1] = 0;
845 // estima a chance de jogo em cada _quadrante_ para cada jogador
846 for (i = 0; i < 8; i++)
847 for (i2 = 0; i2 < 3; i2++) {
848 if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO && status_jogo[i][0] > 0 && status_jogo[i][1] == 0)
849 chance[sequencias[i][i2]][0]++;
850 if (tabuleiro[sequencias[i][i2]] == LEGENDA_VAZIO && status_jogo[i][1] > 0 && status_jogo[i][0] == 0)
851 chance[sequencias[i][i2]][1]++;
854 // rotina p'ra verificar se existe alguma chance
855 // se nao houver, cai fora...
856 for (i = 0; i < 8 && (((chance[i][0] == chance[i][1]) == chance[i][0]) == 0); i++);
857 if (i == 8)
858 return(-1);
860 // seleciona _quadrante_ com maior probabilidade d jogo
861 // aqui a porca torce o rabo... :DDDD
862 limite_possibilidades = 0;
863 maior_chance_X = -1;
864 maior_chance_usuario = -1;
865 for (i = 0; i < 9; i++) {
866 if ( game_mode == JOGO_DEFENSIVO ? chance[i][1] > maior_chance_usuario : chance[i][0] > maior_chance_X) {
867 limite_possibilidades = 0;
868 possibilidades_de_jogadas[limite_possibilidades] = i;
869 maior_chance_X = chance[i][0];
870 maior_chance_usuario = chance[i][1];
871 } else {
872 if ( game_mode == JOGO_DEFENSIVO ? chance[i][1] == maior_chance_usuario : chance[i][0] == maior_chance_X) {
873 if ( game_mode == JOGO_DEFENSIVO ? chance[i][0] > maior_chance_X : chance[i][1] > maior_chance_usuario) {
874 limite_possibilidades = 0;
875 possibilidades_de_jogadas[limite_possibilidades] = i;
876 if (game_mode == JOGO_DEFENSIVO)
877 maior_chance_X = chance[i][0];
878 else
879 maior_chance_usuario = chance[i][1];
880 } else if ( game_mode == JOGO_DEFENSIVO ? chance[i][0] == maior_chance_X : chance[i][1] == maior_chance_usuario) {
881 limite_possibilidades++;
882 possibilidades_de_jogadas[limite_possibilidades] = i;
888 // seleciona a jogadas que estao em "limite_possibilidades"
889 i = (float) random () / (float) RAND_MAX * (limite_possibilidades+1);
891 return(possibilidades_de_jogadas[i]);
894 // ------------------------------------------------------------------------------
895 // funcao: tenta_matar_jogada
896 // descricao: procura matar uma sequencia que o usuario planeja fazer
897 // in: nada
898 // out: -1 - nao ha sequencia
899 // > -1 - quadrante para tentar criar sequen`cia
901 tenta_matar_jogada (void)
903 int sucesso;
904 int jogadasX;
905 int i, i2, maior_chance, opcao_escolhida, nr_opcoes;
906 int p = -1;
907 int provavel_jogada[8][2];
908 int chance[9] =
909 {0, 0, 0, 0, 0, 0, 0, 0, 0};
911 // procura por jogadas em aberto,
912 // contabilizando o numero de quadrantes jah ocupados das sequencias
913 for (i = 0; i < 8; i++) {
914 sucesso = 0;
915 jogadasX = 0;
916 for (i2 = 0; i2 < 3; i2++) {
917 if (tabuleiro[sequencias[i][i2]] == LEGENDA_USUARIO)
918 sucesso++;
919 if (tabuleiro[sequencias[i][i2]] == LEGENDA_X)
920 jogadasX++;
922 if (jogadasX == 0) {
923 p++;
924 provavel_jogada[p][0] = i;
925 provavel_jogada[p][1] = sucesso;
929 // procura jogar nas sequencias q jah tem casa preenchida
930 if (p >= 0) {
931 for (i = 0; i <= p; i++)
932 if (provavel_jogada[i][1] >= 0)
933 for (i2 = 0; i2 < 3; i2++)
934 if (tabuleiro[sequencias[provavel_jogada[i][0]][i2]] == LEGENDA_VAZIO)
935 chance[sequencias[provavel_jogada[i][0]][i2]]++;
936 maior_chance = chance[0];
937 nr_opcoes = 1;
938 for (i = 1; i <= 8; i++) {
939 if (maior_chance < chance[i]) {
940 nr_opcoes = 1;
941 maior_chance = chance[i];
942 } else {
943 if (maior_chance == chance[i]) {
944 nr_opcoes++;
949 opcao_escolhida = (float) random () / (float) RAND_MAX *(nr_opcoes);
951 i2 = 0;
952 for (i = 0; i <= 8; i++) {
953 if ((maior_chance == chance[i]) && (maior_chance >= 1)) {
954 if (i2 == opcao_escolhida)
955 return (i);
956 i2++;
960 // se nao tiver jeito, passa adiante... :)
961 return (-1);
965 // ------------------------------------------------------------------------------
966 // funcao: jogaX
967 // descricao: cerebro do jogador X, nesta rotina que ele escolhe onde jogara
968 // in: nada
969 // out: nada
970 void
971 jogaX (void)
973 int q;
975 q = tenta_fechar ();
976 if (q == -1)
977 q = tapa_buraco ();
978 if (q == -1)
979 q = analisa_jogo ();
980 if (q == -1)
981 q = chuta_jogada();
983 livre_desempilha (q);
985 tabuleiro[q] = LEGENDA_X;
987 desenhaX (q);
989 game_over ();
992 // ------------------------------------------------------------------------------
993 // funcao: jogaHumano
994 // descricao: rotina de verificacao da jogada do usuario
995 // in: quadrante clicado pelo usuario
996 // out: game over?
997 void
998 jogaHumano (int quadrante)
1000 if (adversario && isDeadmatch)
1001 desenhaAdversario (quadrante);
1002 else
1003 desenhaJogador (quadrante);
1004 adversario = !adversario;
1005 livre_desempilha (quadrante);
1006 game_over ();
1009 // ------------------------------------------------------------------------------
1010 // funcao: usage
1011 // descricao: help da aplicacao
1012 // in: nada
1013 // out: nada
1014 void
1015 usage (void)
1017 fprintf (stderr, "\nwmTicTacToe %s - The Ultimate TicTacToe for WindowMaker... :) \n", WMTICTACTOE_VERSION);
1018 fprintf (stderr, "Copyright © 1999 André Ribeiro Camargo\n\n");
1019 fprintf (stderr, "usage:\n");
1020 fprintf (stderr, "\t-display <display name>\n");
1021 fprintf (stderr, "\t-deadmatch\n");
1022 fprintf (stderr, "\t-h\tthis screen\n");
1023 fprintf (stderr, "\t-v\tprint the version number\n");
1024 fprintf (stderr, "\t-o\tofensive mode\n");
1025 fprintf (stderr, "\t-q\tquiet mode(for Debian's user)\n");
1026 fprintf (stderr, "\t\tdefault: defensive mode\n");
1027 fprintf (stderr, "\n");
1030 // ------------------------------------------------------------------------------
1031 // funcao: printversion
1032 // descricao: imprime a versao da aplicacao
1033 // in: nada
1034 // out: nada
1035 void
1036 printversion (void)
1038 if (!strcmp (ProgName, "wmtictactoe"))
1039 fprintf (stderr, "%s\n", WMTICTACTOE_VERSION);
1042 // ------------------------------------------------------------------------------
1043 // funcao: readfile
1044 // descricao: lê o arquivo de configuracao da aplicação
1045 // in: nada
1046 // out: nada
1047 void
1048 readfile (void)
1050 FILE *rcfile;
1051 char rcfilen[256];
1052 char buf[256];
1053 int done;
1055 sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
1057 if ((rcfile=fopen(rcfilen, "r")) != NULL){
1058 do {
1059 fgets(buf, 250, rcfile);
1060 if((done = feof(rcfile)) == 0){
1061 buf[strlen(buf)-1]=0;
1062 if(strncmp(buf, "score_user_offensive ", strlen("score_user "))==0)
1063 sscanf(buf, "score_user_offensive %i", &score_user_offensive);
1064 if(strncmp(buf, "score_X_offensive ", strlen("score_X "))==0)
1065 sscanf(buf, "score_X_offensive %i", &score_X_offensive);
1066 if(strncmp(buf, "score_deuce_offensive ", strlen("score_deuce "))==0)
1067 sscanf(buf, "score_deuce_offensive %i", &score_deuce_offensive);
1069 if(strncmp(buf, "score_user_defensive ", strlen("score_user "))==0)
1070 sscanf(buf, "score_user_defensive %i", &score_user_defensive);
1071 if(strncmp(buf, "score_X_defensive ", strlen("score_X "))==0)
1072 sscanf(buf, "score_X_defensive %i", &score_X_defensive);
1073 if(strncmp(buf, "score_deuce_defensive ", strlen("score_deuce "))==0)
1074 sscanf(buf, "score_deuce_defensive %i", &score_deuce_defensive);
1076 } while(done == 0);
1077 fclose(rcfile);
1081 // ------------------------------------------------------------------------------
1082 // funcao: writefile
1083 // descricao: grava o arquivo de configuracao da aplicação
1084 // in: nada
1085 // out: nada
1086 void
1087 writefile (void)
1089 FILE *rcfile;
1090 char rcfilen[256];
1092 sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
1094 if ((rcfile=fopen(rcfilen, "w")) != NULL){
1095 fprintf(rcfile, "score_user_offensive %d\nscore_deuce_offensive %d\nscore_X_offensive %d\n", score_user_offensive, score_deuce_offensive, score_X_offensive);
1096 fprintf(rcfile, "score_user_defensive %d\nscore_deuce_defensive %d\nscore_X_defensive %d\n", score_user_defensive, score_deuce_defensive, score_X_defensive);
1097 fclose(rcfile);
1101 // ------------------------------------------------------------------------------
1102 // funcao: troca_game_mode
1103 // descricao: troca o modo de jogo
1104 // in: nada
1105 // out: nada
1106 void
1107 troca_game_mode (void)
1109 game_mode = !game_mode;
1111 if (!mute_mode)
1112 fprintf (stderr, "\nPlaying on %s mode... %s", (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
1114 reseta_tabuleiro ();