<pedrocorreia.net ⁄>
corner
<mySearch ⁄> <mySearch ⁄>

corner
 
corner
<mySnippets order="rand" ⁄> <mySnippets order="rand" ⁄>

corner
 
corner
<myContacts ⁄> <myContacts ⁄>

<email ⁄>


pc@pedrocorreia.net

<windows live messenger ⁄>


pedrojacorreia@hotmail.com

<myCurriculum type="pdf" ⁄>


Download
corner
 
corner
<myBlog show="last" ⁄> <myBlog show="last" ⁄>

corner
 
corner
<myNews show="rand" ⁄> <myNews show="rand" ⁄>

corner
 
corner
<myNews type="cat" ⁄> <myNews type="cat" ⁄>

corner
 
corner
<myQuote order="random" ⁄> <myQuote order="random" ⁄>

corner
 
corner
<myPhoto order="random" ⁄> <myPhoto order="random" ⁄>

<pedrocorreia.net ⁄>
corner
 
corner
<myAdSense ⁄> <myAdSense ⁄>

corner
 
corner
<myVisitorsMap ⁄> <myVisitorsMap ⁄>

corner
 
 

<O Jogo do Galo em Javascript ⁄ >




clicks: 13440 13440 2008-10-05 2008-10-05 goto mySnippets mySnippets javascript  Download  Bookmark This Bookmark This



Não é que isto vá trazer a felicidade a alguém, mas depois de escrever alguns snippets na ligua materna de William Shakespeare, eis que volto a escrever tendo como base a lingua de Camões.

É um exemplo lúdico, o Jogo do Galo!

Quem é que nunca o jogou? Numa sala de aula, numa reunião, na fila para uma qualquer instituição do estado, enfim, num rol infinito de sítios todo e qualquer um é bom para jogarmos este grande jogo.

Por terras de Vera Cruz, os nossos irmãos Brasileiros, dão-lhe o nome de O Jogo da Velha.


Esta versão não está dotada de Inteligência Artificial, ou seja é um jogo de humano vs humano, por isso podem ir buscar um(a) amigo(a), ou então podem mesmo passar algumas horas a tentar ver se ganham a vocês próprios ^_^''

Talvez numa futura versão "perca algum tempo" a tentar implementar humano vs computador.

Para quem ainda não souber de que raio estou para aqui a falar, podem consultar a wikipedia, explica detalhadamente o jogo e se reparem do lado direito há umas imagens, qualquer semelhança entre essas imagens e as que vão ver neste snippet, não é pura coincidência /me assobiando para o ar.


O algoritmo do jogo do galo que adoptei é provavelmente o mais fácil, devido ao facto de os caminhos vencedores serem poucos, torna-se praticável verificar quem ganhou (ou não) o jogo fazendo um check às casas selecionadas, ou seja verificar se por ex. o jogador X preencheu consecutivamente as casas na horizontal, ou vertical, etc, etc.

A cada casa é atribuido um número, começando no 1 até ao 9 (internamente no código será de 0 a 8), começando no topo esquerdo, como é ilustrado na figura em baixo:



Será uma espécie de algoritmo por brute-force.

O código é fácil e está documentado.


style.css
  1. *{padding: 0; margin: 0;}
  2.  
  3.  
  4. body{
  5. font-family: Verdana, Tahoma, Arial, sans-serif;font-size: 62.5%;
  6. color: #000;background-color: #fff;text-align: center;
  7. }
  8.  
  9.  
  10. div#board_title{
  11. margin: 0 auto; text-align: center; font-weight: 900;color: #cc0000;
  12. font-size: 3em;width: 27.4em; margin-bottom: .5em;
  13. }
  14.  
  15.  
  16. div#board{margin: 0 auto;width: 27.4em;height: 27.4em;}
  17. div#board div{
  18. float: left;border: solid 0.2em #ce5c00;cursor: pointer;
  19. width: 8.6em;height: 8.6em; line-height: 8.6em;
  20. }
  21. div#board div#square0,div#board div#square1,
  22. div#board div#square3,div#board div#square4,
  23. div#board div#square6,div#board div#square7{border-left: 0; border-top: 0;}
  24. div#board div#square2,div#board div#square5,
  25. div#board div#square8{border-right: 0; border-top: 0; border-left: 0;}
  26. div#board div#square6,div#board div#square7,
  27. div#board div#square8{border-bottom: 0;}
  28. div#board div.player1,
  29. div#info div#board_info div.player1{background: url("player1.gif") no-repeat center center; color: #fff;}
  30. div#board div.player2,
  31. div#info div#board_info div.player2{background: url("player2.gif") no-repeat center center;}
  32. div#board div.win{background-color: #ffff99;}
  33. div#board div.clear{background: none;}
  34.  
  35.  
  36. div#info{margin: 0 auto; width: 46em;}
  37.  
  38. div#info div#board_console{
  39. float: left;
  40. width: 26.5em;
  41. border: dashed .2em #cc0000;
  42. padding: .4em;line-height: 2em;
  43. }
  44. div#info div#board_console span{
  45. color: #fff;font-weight: 700;padding: .1em;
  46. }
  47. div#info div#board_console span.player1{background-color: #204a87;}
  48. div#info div#board_console span.player2{background-color: #4e9a06;}
  49. div#info div#board_console span.draw{background-color: #cc0000;}
  50.  
  51. div#info div#board_control, div#info div#board_info{
  52. float: right;
  53. border: solid .5em #ce5C00;
  54. line-height: 1.8em;
  55. padding: .2em;width: 16.5em;
  56. }
  57. div#info div#board_control input{
  58. background-color: #ffffd4; border: solid .1em #e9b96e;
  59. font-size: 1em; font-weight: 700; padding: .4em;
  60. }
  61. div#info div#board_control label.player{font-weight: 700; font-size: 2em;float: right;}
  62. div#info div#board_control label.one{color: #204a87;}
  63. div#info div#board_control label.two{color: #4e9a06;}
  64. div#info div#board_control label.draw{color: #cc0000;}
  65. div#info div#board_control span{float: left;}
  66.  
  67. div#info div#board_info{margin-top: .4em; clear: right; height: 8em;color: #000;}
  68. div#info div#board_info div{height: 5.8em;background-position: center top;}



Events.js, este ficheiro será responsável por adicionar ou remover eventos a elementos/ objectos da página, por ex. load da página, quanto um elemento é actualizado, etc, etc.
  1. /**
  2. * Class Estática
  3. * Gerir Eventos
  4. */
  5. Events = function(){}
  6.  
  7. /**
  8. * Adicionar Evento
  9. *
  10. * Adaptada do seguinte url:
  11. * http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
  12. *
  13. * @param Object
  14. * @param Object
  15. * @param Object
  16. */
  17. Events.AddEvent = function(obj, type, fn){
  18. if(!obj) return;
  19.  
  20. this.RemoveEvent(obj, type, fn);
  21. if (obj.addEventListener) {
  22. obj.addEventListener(type, fn, false);
  23. }
  24. else {
  25. if (obj.attachEvent) {
  26. obj["e" + type + fn] = fn;
  27. obj[type + fn] = function(){
  28. obj["e" + type + fn](window.event);
  29. }
  30. obj.attachEvent("on" + type, obj[type + fn]);
  31. }
  32. }
  33. }
  34.  
  35. /**
  36. * Remover Evento
  37. *
  38. * Adaptada do seguinte url:
  39. * http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
  40. *
  41. * @param Object
  42. * @param Object
  43. * @param Object
  44. */
  45. Events.RemoveEvent = function(obj, type, fn){
  46. if (obj.removeEventListener) {
  47. try{obj.removeEventListener(type, fn, false);}catch(e){}
  48. }
  49. else{
  50. if (obj.detachEvent) {
  51. obj.detachEvent("on" + type, fn);
  52. obj[type + fn] = null;
  53. obj["e" + type + fn] = null;
  54. }
  55. }
  56. }



Dom.js, será o responsável por interagir com o DOM
  1. /**
  2. * Class estática
  3. *
  4. * Class de suporte à interacção com o DOM
  5. *
  6. * @author: pedrocorreia.net
  7. */
  8. Dom = function(){}
  9.  
  10. /**
  11. * Obter objecto Html
  12. *
  13. * @param String Id Objecto
  14. */
  15. $=function(id){return document.getElementById(id);}
  16.  
  17. /**
  18. * Obter, atribuir ou acrescentar a Class Css
  19. * a um objecto Html
  20. *
  21. * @param Object Objecto Html
  22. * @param Optional String Nome da Class
  23. * @param Optional Int Acrescentar Class?
  24. */
  25. $class=function(obj /**, css_class**/ /**, append*/){
  26. if(arguments[1] && arguments[2]){$(obj).className+=" "+arguments[1];}
  27. else if(arguments[1]){$(obj).className=arguments[1];}
  28. else{return $(obj).className;}
  29. }



Messages.js, as mensagens a serem mostradas ao utilizador ficam neste ficheiro
  1. /**
  2. * Class estática
  3. *
  4. * Class que contém as mensagens a serem
  5. * mostradas ao utilizador
  6. *
  7. * @author: pedrocorreia.net
  8. */
  9. Messages = function(){}
  10.  
  11. /**
  12. * Mensagem a ser exibidida se depois do fim do jogo
  13. * tentarmos clickar numa casa
  14. *
  15. * @param String Nome do Jogador
  16. * @param Int Quem ganhou o jogo
  17. */
  18. Messages.AlreadyFinished = function (name, number){
  19. var str="";
  20. switch (number){
  21. case 0:
  22. str="Houve um empate.";
  23. break;
  24. default:
  25. str=name+" "+number+", foi o Vencedor!";
  26. break;
  27.  
  28. }
  29. return "O jogo já terminou. "+str+"\n\nPressione o botão \"Novo Jogo\"";
  30. }
  31.  
  32. /**
  33. * Mensagem de aviso que a casa já foi selecionada por um jogador
  34. */
  35. Messages.SquareFilled = function(){
  36. return "Esta Casa já se encontra preenchida";
  37. }
  38.  
  39. /**
  40. * Mensagem com informações de quem ganhou o jogo
  41. */
  42. Messages.Winner = function(clss, name, number, path){
  43. return "<span class='"+clss+"'>Vitória para "+name+": "+number+"<span> | Casas: "+path;
  44. }
  45.  
  46. /**
  47. * Mensagem de empate
  48. */
  49. Messages.Draw = function(clss){
  50. return "<span class='"+clss+"'>O jogo terminou empatado!</span>"
  51. }
  52.  
  53. /**
  54. * Mensagem a ser adicionada à consola. Descreve a jogada.
  55. *
  56. * @param String Nome do Jogador
  57. * @param Int Id do Jogador
  58. * @param Int Casa selecionada
  59. */
  60. Messages.TraceMove = function(name, number, square){
  61. return "<b>"+name+":</b> "+number+" | <b>Casa:</b> "+square;
  62. }








JogoGalo.js, o ficheiro principal deste snippet, irá gerir o jogo todo, passar a vez aos jogadores, marcar as casas, verificar quem ganhou, preencher as pontuações, etc, etc.
  1. /**
  2. * Esta class tem como objectivo implementar o Jogo do Galo.
  3. *
  4. * O algoritmo de suporte à resolução do jogo, é baseado num
  5. * esquema brute-force, ou seja, são testadas todas as hipóteses possiveis.
  6. *
  7. * @author: pedrocorreia.net
  8. */
  9. JogoGalo = function (){
  10.  
  11. //necessário para permitir os métodos privados
  12. //acederem aos métodos não-privados da Class
  13. var self=this;
  14.  
  15. //guardar todas as jogadas
  16. var _board_moves;
  17.  
  18. //possiveis combinações de jogadas vencedoras
  19. var _win_moves = {
  20. 1: {pos1: 0, pos2: 1, pos3: 2},
  21. 2: {pos1: 3, pos2: 4, pos3: 5},
  22. 3: {pos1: 6, pos2: 7, pos3: 8},
  23. 4: {pos1: 2, pos2: 4, pos3: 6},
  24. 5: {pos1: 0, pos2: 3, pos3: 6},
  25. 6: {pos1: 1, pos2: 4, pos3: 7},
  26. 7: {pos1: 2, pos2: 5, pos3: 8},
  27. 8: {pos1: 0, pos2: 4, pos3: 8}
  28. }
  29.  
  30. //definições do jogo
  31. var _settings = {
  32. num_squares: 9, //numero de casas
  33. min_plays_check: 5, //numero de casas apartir das quais se verifica o jogo
  34. player: "Jogador", //nome genérico dos jogadores
  35. prefix_square: "square", //prefixo do nome da casa
  36. class_player1: "player1", //class css do jogador 1
  37. class_player2: "player2",//class css do jogador 1
  38. lbl_points_player1: "lbl_player1", //label com a pontuação do jogador 1
  39. lbl_points_player2: "lbl_player2", //label com a pontuação do jogador 2
  40. lbl_points_draw: "lbl_draw", //label com o número de empates
  41. class_winning: "win", //class css das casas com a jogada vencedora
  42. class_draw: "draw", //class css da mensagem de empate
  43. console: "board_console" //para onde será escrito as informações
  44. }
  45.  
  46. //estatisticas do jogo, importantes para tomar decisões
  47. var _stats = {
  48. current_player: 1, //jogador corrente
  49. num_plays: 1, //número de jogadadas totais
  50. winning_player: -1, //jogador vencedor
  51. points_player1: 0, //pontuação jogador 1
  52. points_player2: 0, //pontuação jogador 2
  53. points_draw: 0 //número de empates
  54. }
  55.  
  56. /**
  57. * Método privado
  58. * Passar a vez ao próximo jogador
  59. */
  60. var _NextPlayer = function(){
  61. _stats.current_player=(_stats.current_player==1)?2:1;
  62. _stats.num_plays++;
  63. $class("next_player",_CurPlayerClass());
  64. }
  65.  
  66. /**
  67. * Método privado
  68. * Obter a class css do jogador corrente
  69. */
  70. var _CurPlayerClass = function(){
  71. return (_stats.current_player==1)?_settings.class_player1:_settings.class_player2;
  72. }
  73.  
  74. /**
  75. * Método privado
  76. * Adicionar eventos às casas, para que exista uma
  77. * interacção com o click do rato e com o botão "Novo Jogo" e "Reset"
  78. */
  79. var _EventHandlers = function(){
  80. var fn;
  81. for (var i=0;i<_settings.num_squares;i++){
  82. fn=(function(i){return function(){ _Select (i);}})(i);
  83. Events.AddEvent($(_settings.prefix_square+i),"click",fn);
  84. }
  85.  
  86. Events.AddEvent($("bt_new_game"),"click",self.NewGame);
  87. Events.AddEvent($("bt_reset"),"click",_Reset);
  88. }
  89.  
  90. /**
  91. * Método privado
  92. * Marcar casa selecionada pelo utilizador, verificando se a mesma já se
  93. * encontra ou não preenchida.
  94. *
  95. * Verificar se a jogada presente representa um caminho vencedor, caso não
  96. * seja, passar a vez ao próximo jogador
  97. *
  98. * @param Int Número da Casa
  99. */
  100. var _Select = function(i){
  101.  
  102. //verificar se o jogo já terminou, havendo ou não um vencedor
  103. if(_stats.winning_player>-1 || _stats.num_plays>_settings.num_squares){
  104. alert(Messages.AlreadyFinished(_settings.player,_stats.winning_player));
  105. return;
  106. }
  107.  
  108. if(_IsSquareEmpty(i)){ //verificar se a casa está vazia
  109. $class(_settings.prefix_square+i,_CurPlayerClass());
  110. _MarkSquare(i,_stats.current_player);
  111. _TraceValidMove(i);
  112. _CheckBoard(_stats.current_player);
  113. _NextPlayer();
  114. }
  115. else{
  116. alert(Messages.SquareFilled()); //a casa já está preenchida
  117. }
  118. }
  119.  
  120. /**
  121. * Método privado
  122. * Verificar se a casa se encontra preenchida
  123. *
  124. * @param Int Número da Casa
  125. * @return Bool
  126. */
  127. var _IsSquareEmpty = function(pos){return (_board_moves[pos]==0);}
  128.  
  129. /**
  130. * Método privado
  131. * Marcar casa como preenchida
  132. *
  133. * @param Int Número da Casa
  134. * @param Int Número do Jogador
  135. */
  136. var _MarkSquare = function(pos, player){_board_moves[pos]=player;}
  137.  
  138. /**
  139. * Método privado
  140. * Escrever informação para a consola
  141. *
  142. * @param Int Número da Casa
  143. */
  144. var _TraceValidMove = function(square){
  145. var str=Messages.TraceMove(_settings.player,_stats.current_player,square+1);
  146. $(_settings.console).innerHTML+=str+"<br/>";
  147. }
  148.  
  149. /**
  150. * Método privado
  151. * Verificar se na presente jogada existe
  152. * algum caminho vitorioso
  153. *
  154. * @param Int Número do Jogador
  155. */
  156. var _CheckBoard = function(player){
  157. //se o número de jogadas for inferior ao minimo, não verificar soluções
  158. if(_stats.num_plays<_settings.min_plays_check){return;}
  159.  
  160. var count=0;
  161. var square="";
  162.  
  163. for (var move in _win_moves){ //percorrer todas as combinações vencedoras
  164. for (var i=1;i<=3;i++){ //percorrer as 3 coordenadas
  165. square=_board_moves[_win_moves[move]["pos"+i]];
  166. if(square==player){count++;} //verificar se estão selecionadas no mesmo jogador
  167. }
  168.  
  169. //se o jogador tiver selecionadas as 3 coordenadas correctamente, então ganhou o jogo
  170. if (count==3){
  171. var path="";
  172. for (var i=1;i<=3;i++){
  173. square=_settings.prefix_square+_win_moves[move]["pos"+i];
  174. $class(square,_settings.class_winning,1);//marcar as casas vencedoras
  175. path+=(_win_moves[move]["pos"+i]+1)+";"; //caminho selecionado
  176. }
  177.  
  178. _stats.winning_player = player;
  179. $(_settings.console).innerHTML+=Messages.Winner(_CurPlayerClass(),_settings.player,player,path);
  180.  
  181. _stats["points_player"+player]++; //incrementar contador vitórias
  182. $(_settings["lbl_points_player"+player]).innerHTML=_stats["points_player"+player]; //escrever pontuação
  183. return;
  184. }
  185.  
  186. count=0;
  187. }
  188.  
  189. //verificar se o jogo terminou empatado
  190. if(_stats.num_plays==_settings.num_squares){
  191. _stats.points_draw++; //incrementar contador empates
  192. _stats.winning_player = 0; //marcar jogo como empate
  193. $(_settings.lbl_points_draw).innerHTML=_stats.points_draw;
  194. $(_settings.console).innerHTML+=Messages.Draw(_settings.class_draw);
  195. }
  196. }
  197.  
  198. /**
  199. * Método privado
  200. * Reinicializar Estatisticas
  201. */
  202. var _Reset = function(){
  203. _stats.points_player1=0;
  204. _stats.points_player2=0;
  205. _stats.points_draw=0;
  206. $(_settings.lbl_points_player1).innerHTML=_stats.points_player1;
  207. $(_settings.lbl_points_player2).innerHTML=_stats.points_player2;
  208. $(_settings.lbl_points_draw).innerHTML=_stats.points_draw;
  209.  
  210. self.NewGame();
  211. }
  212.  
  213. /**
  214. * Iniciar um novo jogo
  215. */
  216. this.NewGame = function(){
  217. for (var i=0;i<_settings.num_squares;i++){
  218. $class(_settings.prefix_square+i,"clear");
  219. $(_settings.prefix_square+i).innerHTML=(i+1);
  220. }
  221.  
  222. _stats.num_plays=1;
  223. _stats.current_player=1;
  224. _stats.winning_player=-1;
  225. _board_moves = new Array(0,0,0,0,0,0,0,0,0);
  226. $(_settings.console).innerHTML="";
  227. $class("next_player",_settings.class_player1);
  228. }
  229.  
  230. //inicializar EventHandlers
  231. _EventHandlers();
  232.  
  233. }



Init.js, o nome esclarece a finalidade deste ficheiro, será o responsável pela criação do objecto JogoGalo, bem como iniciar o 1º jogo.
  1. /**
  2. * Função de Inicialização
  3. *
  4. * @author pedrocorreia.net
  5. */
  6. Init = function(){
  7. var jogo_galo=new JogoGalo();
  8. jogo_galo.NewGame();
  9. }
  10.  
  11. Events.AddEvent(window,"load",Init);



index.htm, o nosso amigo html
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" >
  4. <head>
  5. <title>Jogo do Galo</title>
  6. <link rel="stylesheet" href="style.css" />
  7. <script type="text/javascript" src="Events.js"></script>
  8. <script type="text/javascript" src="Dom.js"></script>
  9. <script type="text/javascript" src="Messages.js"></script>
  10. <script type="text/javascript" src="JogoGalo.js"></script>
  11. <script type="text/javascript" src="Init.js"></script>
  12. </head>
  13.  
  14. <body>
  15. <div id="board_title">Jogo do Galo</div>
  16.  
  17. <div id="board">
  18. <div id="square0"></div>
  19. <div id="square1"></div>
  20. <div id="square2"></div>
  21. <div id="square3"></div>
  22. <div id="square4"></div>
  23. <div id="square5"></div>
  24. <div id="square6"></div>
  25. <div id="square7"></div>
  26. <div id="square8"></div>
  27. </div>
  28.  
  29. <div id="info">
  30. <div id="board_console"></div>
  31.  
  32. <div id="board_control">
  33. <span>Pontuação Jogador 1:</span> <label id="lbl_player1" class="player one">0</label>
  34. <br />
  35. <span>Pontuação Jogador 2:</span> <label id="lbl_player2" class="player two">0</label>
  36. <br />
  37. <span>Empates:</span> <label id="lbl_draw" class="player draw">0</label>
  38. <br /><br />
  39. <input type="button" value="Novo Jogo" id="bt_new_game" />
  40. <input type="button" value="Reset" id="bt_reset" />
  41. </div>
  42.  
  43. <div id="board_info">Próxima Jogada<div id="next_player"></div></div>
  44. </div>
  45. </body>
  46.  
  47. </html>




Aqui fica um screenshot do jogo:





Qualquer erro/ dúvida é só dizer!









clicks: 13440 13440 2008-10-05 2008-10-05 goto mySnippets mySnippets javascript  Download  Bookmark This Bookmark This