├── README.md ├── .gitignore ├── velha.html ├── css └── velha.css └── js └── velha.js /README.md: -------------------------------------------------------------------------------- 1 | # jogo-da-velha 2 | Simples jogo da velha feito com HTML, CSS3 e JavaScript 3 | 4 | Este jogo foi feito para práticar com aos alunos lógica de programação com HTML5, CSS3 e JavaScript. 5 | Tudo foi feito de maneira bem simples. 6 | 7 | Atualizado dia 10/12/2021. 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /velha.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Joguinho da velhinha 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 | 19 | Pontos: 0 20 |
21 | 22 |
23 | 24 | Pontos: 0 25 |
26 | 27 |
28 | Próximo a jogar: 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 | 38 |
39 | 40 |
41 | 42 | 43 |
44 | 45 | 46 | 47 |
48 | 49 |
50 | 51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 66 |
67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /css/velha.css: -------------------------------------------------------------------------------- 1 | /* Aqui eu posso declarar variáveis. */ 2 | :root{ 3 | --color-primary:rgb(40,140,40); 4 | --color-secundary:rgb(40,100,40); 5 | --color-geral: #121214; 6 | --font-color: rgb(255,255,250); 7 | } 8 | 9 | /* Aqui estou zerando o CSS do navegador */ 10 | html, body { 11 | margin: 0; 12 | padding: 0; 13 | width: 100%; 14 | height: 100%; 15 | box-sizing: border-box; 16 | } 17 | 18 | /* meu container principal */ 19 | .container { 20 | display: grid; 21 | grid-template-columns: 200px 200px 200px; 22 | grid-template-rows: 20vh 20vh 20vh 20vh calc(20vh - 20px); 23 | background-color: var(--color-geral); 24 | color: var(--font-color); 25 | 26 | grid-template-areas: "h h h" 27 | "v1 v2 v3" 28 | "v4 v5 v6" 29 | "v7 v8 v9" 30 | "f f f"; 31 | 32 | grid-gap:5px; 33 | justify-content: center; 34 | align-content: center; 35 | } 36 | 37 | header { 38 | grid-area: h; 39 | display: grid; 40 | grid-gap: 5px; 41 | justify-content: start; 42 | align-content: center; 43 | margin-top: 6px; 44 | } 45 | 46 | footer{ 47 | grid-area: f; 48 | text-align: center; 49 | } 50 | 51 | .container > div { 52 | background-color: var(--color-primary); 53 | display: grid; 54 | justify-content: center; 55 | align-content: center; 56 | border-radius: 10px; 57 | font-size: 50px; 58 | font-weight: 800; 59 | } 60 | 61 | .container > div:hover{ 62 | background-color: var(--color-secundary); 63 | cursor: pointer; 64 | } 65 | 66 | /* Daqui para baixo CSS especifico */ 67 | 68 | 69 | 70 | .opcoes-jogo{ 71 | display: grid; 72 | grid-template-columns: 1fr 1fr; 73 | grid-template-rows: 1fr 1fr; 74 | grid-template-areas: "hgx bg" 75 | "hgo bg"; 76 | 77 | justify-content: center; 78 | align-content: center; 79 | } 80 | 81 | .header-group #usuario-x{ 82 | margin-bottom: 5px; 83 | grid-area: hgx; 84 | 85 | } 86 | .header-group #usuario-O{ 87 | margin-bottom: 5px; 88 | grid-area: hgo; 89 | 90 | } 91 | 92 | #btn-jogar{ 93 | grid-area: bg; 94 | width: 200px; 95 | height: 120px; 96 | align-self: center; 97 | justify-self: end; 98 | background-color: var(--color-primary); 99 | border:0; 100 | font-size: 20px; 101 | font-weight: 600; 102 | color: var(--font-color); 103 | } 104 | 105 | #btn-jogar:hover{ 106 | background-color: var(--color-secundary); 107 | cursor: pointer; 108 | } 109 | 110 | .header-group > label { 111 | font-size: 18px; 112 | } 113 | 114 | .header-group > input { 115 | padding: 5px; 116 | text-transform: none; 117 | text-decoration: none; 118 | border:0; 119 | background-color: transparent; 120 | border: 1px solid var(--color-primary); 121 | color: var(--color-secundary); 122 | font-weight: 800; 123 | font-size: 20px; 124 | margin-left: 15px; 125 | } 126 | 127 | .painel-group{ 128 | font-size: 20px; 129 | padding-top: 10px; 130 | } 131 | .pontos{ 132 | margin-left: 50px; 133 | float: right; 134 | } 135 | .pontos > strong { 136 | font-size: 20px; 137 | } 138 | 139 | .proximo-jogar{ 140 | margin-top: 50px; 141 | } 142 | 143 | .esconder{ 144 | display: none; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /js/velha.js: -------------------------------------------------------------------------------- 1 | // Criando um módulo para deixar o código privado. 2 | (()=>{ 3 | 4 | // Declarando variáveis e objetos utilizados para o jogo. 5 | const TEXTO_USUARIO_X = 'Usuário X: '; 6 | const TEXTO_USUARIO_O = 'Usuário O: '; 7 | 8 | let jogadorAtual = {}; 9 | let jogadas = []; 10 | let emJogo = false; 11 | let jogo = { 12 | jogada1: document.querySelector('.jogo-velha-1'), 13 | jogada2: document.querySelector('.jogo-velha-2'), 14 | jogada3: document.querySelector('.jogo-velha-3'), 15 | jogada4: document.querySelector('.jogo-velha-4'), 16 | jogada5: document.querySelector('.jogo-velha-5'), 17 | jogada6: document.querySelector('.jogo-velha-6'), 18 | jogada7: document.querySelector('.jogo-velha-7'), 19 | jogada8: document.querySelector('.jogo-velha-8'), 20 | jogada9: document.querySelector('.jogo-velha-9') 21 | } 22 | 23 | let jogadorX = { 24 | nome:'', 25 | valor: 'X', 26 | pontos: 0 27 | } 28 | 29 | let jogadorO = { 30 | nome:'', 31 | valor: 'O', 32 | pontos: 0 33 | } 34 | 35 | var opcoes = { 36 | divOpcoesJogo : document.querySelector('.opcoes-jogo'), 37 | usuarioX : document.getElementById('usuario-x'), 38 | usuarioO : document.getElementById('usuario-o'), 39 | btnJogar : document.getElementById('btn-jogar') 40 | }; 41 | 42 | var painel = { 43 | painelOpcoesJogo : document.querySelector('.painel-opcoes'), 44 | nomeX : document.getElementById('painel-usuario-x-nome'), 45 | nomeO : document.getElementById('painel-usuario-o-nome'), 46 | pontosX : document.getElementById('painel-usuario-x-pontos'), 47 | pontosO : document.getElementById('painel-usuario-o-pontos'), 48 | nomeProximoJogador: document.getElementById('proximo-jogador') 49 | }; 50 | 51 | // Capturando os eventos de click 52 | opcoes.btnJogar.addEventListener('click', () => { 53 | 54 | jogadorX.nome = opcoes.usuarioX.value; 55 | jogadorO.nome = opcoes.usuarioO.value; 56 | 57 | if(!jogadorX.nome || !jogadorO.nome){ 58 | alert('Favor informar os usuarios X e O para iniciar o jogo.'); 59 | return; 60 | } 61 | 62 | // Alterar os nomes dos jogadores... 63 | painel.nomeX.textContent = TEXTO_USUARIO_X + jogadorX.nome; 64 | painel.nomeO.textContent = TEXTO_USUARIO_O + jogadorO.nome; 65 | 66 | jogadorAtual = jogadorX; 67 | painel.nomeProximoJogador.textContent = jogadorAtual.nome; 68 | emJogo = true; 69 | 70 | // Aqui tenho que esconder as opções e mostrar o painel. 71 | opcoes.divOpcoesJogo.classList.add('esconder'); 72 | painel.painelOpcoesJogo.classList.remove('esconder'); 73 | }); 74 | 75 | 76 | jogo.jogada1.addEventListener('click', (e)=>{ 77 | jogada(e, 1); 78 | }); 79 | 80 | jogo.jogada2.addEventListener('click', (e)=>{ 81 | jogada(e, 2); 82 | }); 83 | 84 | jogo.jogada3.addEventListener('click', (e)=>{ 85 | jogada(e, 3); 86 | }); 87 | 88 | jogo.jogada4.addEventListener('click', (e)=>{ 89 | jogada(e, 4); 90 | }); 91 | 92 | jogo.jogada5.addEventListener('click', (e)=>{ 93 | jogada(e, 5); 94 | }); 95 | 96 | jogo.jogada6.addEventListener('click', (e)=>{ 97 | jogada(e, 6); 98 | }); 99 | 100 | jogo.jogada7.addEventListener('click', (e)=>{ 101 | jogada(e, 7); 102 | }); 103 | 104 | jogo.jogada8.addEventListener('click', (e)=>{ 105 | jogada(e, 8); 106 | }); 107 | 108 | jogo.jogada9.addEventListener('click', (e)=>{ 109 | jogada(e, 9); 110 | }); 111 | 112 | 113 | // Funções utilizadas no jogo 114 | 115 | function validarJogada(){ 116 | let valor = jogadorAtual.valor; 117 | 118 | if(_estrategia_1(valor) || 119 | _estrategia_2(valor) || 120 | _estrategia_3(valor) || 121 | _estrategia_4(valor) || 122 | _estrategia_5(valor) || 123 | _estrategia_6(valor) || 124 | _estrategia_7(valor) || 125 | _estrategia_8(valor)){ 126 | 127 | return true; 128 | } 129 | 130 | return false; 131 | } 132 | 133 | function _estrategia_1(valor){ 134 | return (jogadas[1] == valor && jogadas[2] == valor && jogadas[3] == valor); 135 | } 136 | function _estrategia_2(valor){ 137 | return (jogadas[4] == valor && jogadas[5] == valor && jogadas[6] == valor); 138 | } 139 | function _estrategia_3(valor){ 140 | return (jogadas[7] == valor && jogadas[8] == valor && jogadas[9] == valor); 141 | } 142 | function _estrategia_4(valor){ 143 | return (jogadas[1] == valor && jogadas[4] == valor && jogadas[7] == valor); 144 | } 145 | function _estrategia_5(valor){ 146 | return (jogadas[2] == valor && jogadas[5] == valor && jogadas[8] == valor); 147 | } 148 | function _estrategia_6(valor){ 149 | return (jogadas[3] == valor && jogadas[6] == valor && jogadas[9] == valor); 150 | } 151 | function _estrategia_7(valor){ 152 | return (jogadas[1] == valor && jogadas[5] == valor && jogadas[9] == valor); 153 | } 154 | function _estrategia_8(valor){ 155 | return (jogadas[3] == valor && jogadas[5] == valor && jogadas[7] == valor); 156 | } 157 | 158 | 159 | function _marcarJogada(e, indice){ 160 | e.target.textContent = jogadorAtual.valor; 161 | jogadas[indice] = jogadorAtual.valor; 162 | } 163 | 164 | 165 | function jogada(e, indice){ 166 | 167 | if(!emJogo || e.target.textContent){ 168 | return; 169 | } 170 | 171 | _marcarJogada(e, indice); 172 | 173 | 174 | if(validarJogada()){ 175 | 176 | setTimeout(() =>{ 177 | alert(`Parabéns, jogador ${jogadorAtual.nome} acaba de marcar ponto. \\o/`); 178 | _atualizarPainel(); 179 | _reiniciarJogo(); 180 | }, 100) 181 | 182 | return; 183 | } 184 | 185 | if(jogadas.filter(e => e).length == 9){ 186 | 187 | setTimeout(()=>{ 188 | alert('Deu velha ...'); 189 | _reiniciarJogo(); 190 | },100) 191 | 192 | return; 193 | } 194 | 195 | // Continuar jogando. 196 | jogadorAtual = (jogadorAtual == jogadorX) ? jogadorO : jogadorX; 197 | 198 | painel.nomeProximoJogador.textContent = jogadorAtual.nome; 199 | } 200 | 201 | function _reiniciarJogo(){ 202 | 203 | jogadas = []; 204 | jogo.jogada1.textContent = ''; 205 | jogo.jogada2.textContent = ''; 206 | jogo.jogada3.textContent = ''; 207 | jogo.jogada4.textContent = ''; 208 | jogo.jogada5.textContent = ''; 209 | jogo.jogada6.textContent = ''; 210 | jogo.jogada7.textContent = ''; 211 | jogo.jogada8.textContent = ''; 212 | jogo.jogada9.textContent = ''; 213 | } 214 | 215 | function _atualizarPainel(){ 216 | 217 | jogadorAtual.pontos += 1; 218 | 219 | if(jogadorAtual.valor == "X"){ 220 | painel.pontosX.textContent = jogadorAtual.pontos; 221 | }else{ 222 | painel.pontosO.textContent = jogadorAtual.pontos; 223 | } 224 | 225 | jogadorAtual = (jogadorAtual == jogadorX) ? jogadorO : jogadorX; 226 | painel.nomeProximoJogador.textContent = jogadorAtual.nome; 227 | } 228 | 229 | })() --------------------------------------------------------------------------------