1 /*
2 wmtictactoe - the ultimate tictactoe for WindowMaker
3 =-=-=-=-=-= ======================================
4 Copyright (C) 1999 Andr� R. Camargo
5
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.
10
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.
15
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.
21
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
28 */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <string.h>
35
36 #include <X11/Xlib.h>
37 #include <X11/xpm.h>
38 #include <X11/extensions/shape.h>
39
40 #include "../wmgeneral/wmgeneral.h"
41 #include "wmtictactoe-master.xpm"
42
43 // ---------------------------------------------------------------
44 // definicoes :)
45
46 #define WMTICTACTOE_VERSION "1.1"
47
48 #define TRUE 1
49 #define FALSE 0
50
51 #define USLEEP 20000
52 #define BLINK 200000
53
54 #define LEGENDA_VAZIO 0
55 #define LEGENDA_USUARIO 1
56 #define LEGENDA_X 2
57
58 #define JOGO_OFENSIVO 0
59 #define JOGO_DEFENSIVO 1
60
61 // ---------------------------------------------------------------
62 // Vari�veis Globais
63
64 char *ProgName;
65
66 typedef struct {
67 int left;
68 int top;
69 int right;
70 int bottom;
71 } regioes;
72
73 regioes quadrantes[MAX_MOUSE_REGION] =
74 {
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}};
84
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};
89
90 int sequencias[8][3] =
91 {
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}};
100
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;
117
118 // mascara
119 char wmtictactoe_mask_bits[64 * 64];
120 int wmtictactoe_mask_width = 64;
121 int wmtictactoe_mask_height = 64;
122
123 // ----------------------------------------------------------
124 // declaracao das funcoes do sistema
125
126 int main (int argc, char *argv[]);
127 void usage (void);
128 void printversion (void);
129 void readfile (void);
130 void writefile (void);
131
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);
141
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);
147
148 void reseta_tabuleiro (void);
149 void livre_desempilha (int);
150
151 void principal (int, char **);
152 int escolheJogador (void);
153
154 void joga (int);
155 void jogaHumano (int);
156
157 void jogaX (void);
158 int tapa_buraco (void);
159 int analisa_jogo (void);
160 int chuta_jogada (void);
161
162 int validaJogada (int);
163 void game_over (void);
164
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
main(int argc,char * argv[])171 int main (int argc, char *argv[])
172 {
173 int i;
174
175 ProgName = argv[0];
176 if (strlen (ProgName) >= 11)
177 ProgName += (strlen (ProgName) - 11);
178
179 game_mode = JOGO_DEFENSIVO;
180 mute_mode = FALSE;
181
182 for (i = 1; i < argc; i++) {
183 char *arg = argv[i];
184
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;
195 }
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);
209 }
210 }
211 }
212
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");
219
220 fprintf (stderr, "\nPlaying on %s mode... %s", isDeadmatch ? "deadmatch" : (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", isDeadmatch ? ":) <-> (:" : (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
221 }
222
223 principal (argc, argv);
224 }
225
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
desenhaAdversario(int quadrante)232 desenhaAdversario (int quadrante)
233 {
234 tabuleiro[quadrante] = LEGENDA_X;
235 copyXPMArea(97, 74, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
236 }
237
238 // -------------------------------------------------------------------------------------------
239 // funcao: desenhaJogador(int quadrante)
240 // descricao: desenha o jogador no tabuleiro
241 // in: quadrante - quadrante do tabuleiro
242 // out: nada
243 void
desenhaJogador(int quadrante)244 desenhaJogador (int quadrante)
245 {
246 tabuleiro[quadrante] = LEGENDA_USUARIO;
247 copyXPMArea (68, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
248 }
249
250 // --------------------------------------------------------------------------------------------
251 // funcao: desenhaX(int quadrante)
252 // descricao: desenha o X no tabuleiro
253 // in: quadrante - quadrante do tabuleiro
254 // out: nada
255 void
desenhaX(int quadrante)256 desenhaX (int quadrante)
257 {
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);
265 }
266
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
desenhaLimpa(int quadrante)273 desenhaLimpa (int quadrante)
274 {
275 copyXPMArea (82, 4, 13, 8, quadrantes[quadrante].left + 1, quadrantes[quadrante].top + 1);
276 }
277
278 // ---------------------------------------------------------------------------------------------
279 // funcao: desenhaAvisoJoga
280 // descricao: desenha "play" na tela
281 // in: nada
282 // out: nada
283 void
desenhaAvisoJoga(void)284 desenhaAvisoJoga (void)
285 {
286 if (isDeadmatch && adversario) {
287 copyXPMArea(68, 103, 60, 9, 4, 47);
288 copyXPMArea(71, 93, 16, 8, 5, 47);
289 return;
290 }
291 if (isDeadmatch && !adversario) {
292 copyXPMArea(68, 103, 60, 9, 4, 47);
293 return;
294
295 }
296 copyXPMArea (68, 13, 60, 9, 4, 47);
297 }
298
299 // ----------------------------------------------------------------------------------------------
300 // funcao: desenhaAvisoVoceVenceu
301 // descricao: desenha "you win" na tela
302 // in: nada
303 // out: nada
304 void
desenhaAvisoVoceVenceu(void)305 desenhaAvisoVoceVenceu (void)
306 {
307 if (isDeadmatch)
308 copyXPMArea (68, 83, 60, 9, 4, 47);
309 else
310 copyXPMArea (68, 23, 60, 9, 4, 47);
311 }
312
313 // -----------------------------------------------------------------------------------------------
314 // funcao: desenhaAvisoEuVenci
315 // descricao: desenha "I win" na tela
316 // in: nada
317 // out: nada
318 void
desenhaAvisoEuVenci(void)319 desenhaAvisoEuVenci (void)
320 {
321 if (isDeadmatch)
322 copyXPMArea (68, 93, 60, 9, 4, 47);
323 else
324 copyXPMArea (68, 33, 60, 9, 4, 47);
325 }
326
327 // -----------------------------------------------------------------------------------------------
328 // funcao: desenhaAvisoEmpate
329 // descricao: desenha "deuce" na tela
330 // in: nada
331 // out: nada
332 void
desenhaAvisoEmpate(void)333 desenhaAvisoEmpate (void)
334 {
335 copyXPMArea (68, 43, 60, 9, 4, 47);
336 }
337
338 // -----------------------------------------------------------------------------------------------
339 // funcao: desenhaAvisoLimpa
340 // descricao: "apaga" os displays da tela
341 // in: nada
342 // out: nada
343 void
desenhaAvisoLimpa(void)344 desenhaAvisoLimpa (void)
345 {
346 copyXPMArea (68, 53, 60, 9, 4, 47);
347 }
348
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!
355 int
validaJogada(int quadrante)356 validaJogada (int quadrante)
357 {
358 return ((quadrante > -1) ? tabuleiro[quadrante] == 0 : 0);
359 }
360
361 // ------------------------------------------------------------------------------------------------
362 // funcao: reseta_tabuleiro
363 // descricao: reseta o jogo
364 // in: nada
365 // out: nada
366 void
reseta_tabuleiro(void)367 reseta_tabuleiro (void)
368 {
369 int i;
370
371 for (i = 0; i < 9; i++) {
372 tabuleiro[i] = LEGENDA_VAZIO;
373 desenhaLimpa (i);
374 livre[i] = i;
375 }
376 livre_max = i;
377
378 desenhaAvisoJoga ();
379 }
380
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
387 int
escolheJogador(void)388 escolheJogador (void)
389 {
390 srand ((int) time (NULL));
391 adversario = ((int) ((float) random () / (float) RAND_MAX * 2));
392 return adversario;
393 }
394
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
402 int
verificaSequencia()403 verificaSequencia ()
404 {
405 /*
406 matriz d jogadas contem o numero da posicao
407
408 0 | 1 | 2
409 ---+---+---
410 3 | 4 | 5
411 ---+---+---
412 6 | 7 | 8
413 */
414
415 int sucesso = 0;
416 int padrao;
417 int i;
418
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;
427 }
428
429 // verifica se ha algum quadrante para se jogar
430 if (!sucesso && !livre_max)
431 return (-2);
432
433 return ((sucesso) ? i : -1);
434 }
435
436 // ------------------------------------------------------------------------------------
437 // funcao: game_over
438 // descricao: caso o jogo tenha acabado, pisca vencedor
439 // in: nada
440 // out: nada
441 void
game_over()442 game_over ()
443 {
444 if (verificaSequencia () != -1)
445 piscaVencedor ();
446 }
447
448 // -------------------------------------------------------------------------------------
449 // funcao: piscaVencedor
450 // descricao: pisca as jogadas da sequencia especifica vencedora
451 // in: nada
452 // out: nada
453 void
piscaVencedor()454 piscaVencedor ()
455 {
456 int mostra = 0;
457 int i;
458 int seq = verificaSequencia ();
459 int jogador = tabuleiro[sequencias[seq][0]];
460 XEvent Event;
461
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++;
479 }
480
481 if (!isDeadmatch)
482 writefile ();
483
484 while (1) {
485 RedrawWindow ();
486
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;
507 }
508 }
509
510 }
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]);
524 }
525 } else {
526 desenhaAvisoLimpa ();
527 if (seq != -2)
528 for (i = 0; i < 3; i++)
529 desenhaLimpa (sequencias[seq][i]);
530 }
531 mostra = !mostra;
532 }
533 }
534
535 // -------------------------------------------------------------------------------------
536 // funcao: escreve_placar
537 // descricao: escreve o placar do jogo na tela de score
538 // in: nada
539 // out: nada
540 void
escreve_placar()541 escreve_placar ()
542 {
543 int i;
544 int coluna_xpm = 65;
545 int coluna_score[6] =
546 {8, 15, 26, 33, 43, 50 };
547 char placar[7];
548
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);
557 }
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);
568 }
569
570 for (i = 0; i < 6; i++)
571 copyXPMArea (coluna_xpm+((placar[i]-48)*6), 65, 6, 9, coluna_score[i], 100);
572 }
573
574 // -------------------------------------------------------------------------------------
575 // funcao: reseta_score
576 // descricao: zera o placar do jogo
577 // in: nada
578 // out: nada
579 void
reseta_score()580 reseta_score ()
581 {
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;
589
590 writefile ();
591
592 escreve_placar ();
593 }
594
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
602 int
mostra_score()603 mostra_score ()
604 {
605 XEvent Event;
606 int game_mode_changed = 0;
607
608 escreve_placar ();
609 while (1) {
610 RedrawWindowXY (0, 60);
611
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);
633 }
634
635 }
636 usleep (USLEEP);
637 }
638 }
639
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
principal(int argc,char ** argv)647 principal (int argc, char **argv)
648 {
649 int i;
650 XEvent Event;
651
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);
654
655 for (i = 0; i < MAX_MOUSE_REGION; i++)
656 AddMouseRegion (i, quadrantes[i].left, quadrantes[i].top, quadrantes[i].right, quadrantes[i].bottom);
657
658 reseta_tabuleiro ();
659
660 if (!isDeadmatch)
661 readfile ();
662 mostra_score ();
663
664 if (!isDeadmatch && escolheJogador ())
665 jogaX ();
666
667 desenhaAvisoJoga ();
668
669 while (1) {
670 RedrawWindow ();
671
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 ();
692 }
693 break;
694 case 2:
695 reseta_tabuleiro ();
696 break;
697 case 3:
698 mostra_score ();
699 }
700 }
701
702 }
703 usleep (USLEEP);
704 }
705
706 }
707
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
livre_desempilha(int quad)714 livre_desempilha (int quad)
715 {
716 int i = 0;
717
718 // localiza quadrante no vetor de quadrantes livres
719 while (livre[i] < quad)
720 i++;
721
722 // desempilha
723 while (i < livre_max) {
724 livre[i] = livre[i + 1];
725 i++;
726 }
727
728 // seta o ultimo elemento como -1
729 // *assim fica + facil debugar :) *
730 livre[--livre_max] = -1;
731 }
732
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
740 int
tapa_buraco(void)741 tapa_buraco (void)
742 {
743 int sucesso = 0;
744 int desocupado, seta;
745 int i, i2;
746
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;
757 }
758 }
759 if ((sucesso == 2) && seta)
760 return (desocupado);
761 }
762 return (-1);
763 }
764
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
771 int
tenta_fechar(void)772 tenta_fechar (void)
773 {
774 int sucesso;
775 int desocupado, seta;
776 int i, i2;
777
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;
788 }
789 }
790 if ((sucesso == 2) && seta)
791 return (desocupado);
792 }
793 return (-1);
794 }
795
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
801 int
chuta_jogada(void)802 chuta_jogada (void)
803 {
804 srand ((int) time (NULL));
805 return (livre[(int) ((float) random () / (float) RAND_MAX * livre_max)]);
806 }
807
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
814 int
analisa_jogo(void)815 analisa_jogo (void)
816 {
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;
824
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++;
834 }
835 status_jogo[i][0] = jogadas_X;
836 status_jogo[i][1] = jogadas_usuario;
837 }
838
839 // zera a matriz... *pregui�a*
840 for (i = 0; i < 9; i++) {
841 chance[i][0] = 0;
842 chance[i][1] = 0;
843 }
844
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]++;
852 }
853
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);
859
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;
883 }
884 }
885 }
886 }
887
888 // seleciona a jogadas que estao em "limite_possibilidades"
889 i = (float) random () / (float) RAND_MAX * (limite_possibilidades+1);
890
891 return(possibilidades_de_jogadas[i]);
892 }
893
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
900 int
tenta_matar_jogada(void)901 tenta_matar_jogada (void)
902 {
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};
910
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++;
921 }
922 if (jogadasX == 0) {
923 p++;
924 provavel_jogada[p][0] = i;
925 provavel_jogada[p][1] = sucesso;
926 }
927 }
928
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++;
945 }
946 }
947 }
948
949 opcao_escolhida = (float) random () / (float) RAND_MAX *(nr_opcoes);
950
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++;
957 }
958 }
959 }
960 // se nao tiver jeito, passa adiante... :)
961 return (-1);
962 }
963
964
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
jogaX(void)971 jogaX (void)
972 {
973 int q;
974
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();
982
983 livre_desempilha (q);
984
985 tabuleiro[q] = LEGENDA_X;
986
987 desenhaX (q);
988
989 game_over ();
990 }
991
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
jogaHumano(int quadrante)998 jogaHumano (int quadrante)
999 {
1000 if (adversario && isDeadmatch)
1001 desenhaAdversario (quadrante);
1002 else
1003 desenhaJogador (quadrante);
1004 adversario = !adversario;
1005 livre_desempilha (quadrante);
1006 game_over ();
1007 }
1008
1009 // ------------------------------------------------------------------------------
1010 // funcao: usage
1011 // descricao: help da aplicacao
1012 // in: nada
1013 // out: nada
1014 void
usage(void)1015 usage (void)
1016 {
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");
1028 }
1029
1030 // ------------------------------------------------------------------------------
1031 // funcao: printversion
1032 // descricao: imprime a versao da aplicacao
1033 // in: nada
1034 // out: nada
1035 void
printversion(void)1036 printversion (void)
1037 {
1038 if (!strcmp (ProgName, "wmtictactoe"))
1039 fprintf (stderr, "%s\n", WMTICTACTOE_VERSION);
1040 }
1041
1042 // ------------------------------------------------------------------------------
1043 // funcao: readfile
1044 // descricao: l� o arquivo de configuracao da aplica��o
1045 // in: nada
1046 // out: nada
1047 void
readfile(void)1048 readfile (void)
1049 {
1050 FILE *rcfile;
1051 char rcfilen[256];
1052 char buf[256];
1053 int done;
1054
1055 sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
1056
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);
1068
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);
1075 }
1076 } while(done == 0);
1077 fclose(rcfile);
1078 }
1079 }
1080
1081 // ------------------------------------------------------------------------------
1082 // funcao: writefile
1083 // descricao: grava o arquivo de configuracao da aplica��o
1084 // in: nada
1085 // out: nada
1086 void
writefile(void)1087 writefile (void)
1088 {
1089 FILE *rcfile;
1090 char rcfilen[256];
1091
1092 sprintf(rcfilen, "%s/.wmtictactoe", getenv("HOME"));
1093
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);
1098 }
1099 }
1100
1101 // ------------------------------------------------------------------------------
1102 // funcao: troca_game_mode
1103 // descricao: troca o modo de jogo
1104 // in: nada
1105 // out: nada
1106 void
troca_game_mode(void)1107 troca_game_mode (void)
1108 {
1109 game_mode = !game_mode;
1110
1111 if (!mute_mode)
1112 fprintf (stderr, "\nPlaying on %s mode... %s", (game_mode == JOGO_DEFENSIVO) ? "DEFENSIVE" : "OFFENSIVE", (game_mode == JOGO_DEFENSIVO) ? ":(" : ":)");
1113
1114 reseta_tabuleiro ();
1115 }
1116
1117
1118