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