-
-
Save baltazarparra/2c00a151c42cb3513775c750314deb83 to your computer and use it in GitHub Desktop.
(function(jokenpo){ | |
'use strict'; | |
var $rock = document.querySelector('[data-js="rock"]'); | |
var $paper = document.querySelector('[data-js="paper"]'); | |
var $scissor = document.querySelector('[data-js="scissor"]'); | |
var $userChoice = document.querySelector('[data-js="user-choice"]'); | |
var $cpuChoice = document.querySelector('[data-js="cpu-choice"]'); | |
var $userScore = document.querySelector('[data-js="userScore"]'); | |
var $cpuScore = document.querySelector('[data-js="cpuScore"]'); | |
var app = (function appController() { | |
return { | |
init: function init() { | |
this.initEvents(); | |
}, | |
initEvents: function initEvents() { | |
$rock.addEventListener('click', this.optionChoice('rock')); | |
$paper.addEventListener('click', this.optionChoice('paper')); | |
$scissor.addEventListener('click', this.optionChoice('scissor')); | |
}, | |
cpuChoice: function cpuChoice() { | |
var cpuChoice = Math.random(); | |
if (cpuChoice < 0.3) { | |
var cpuChoiceOutput = 'rock'; | |
$cpuChoice.setAttribute("src", cpuChoiceOutput + ".svg"); | |
return cpuChoiceOutput; | |
} else if (cpuChoice < 0.6) { | |
var cpuChoiceOutput = 'paper'; | |
$cpuChoice.setAttribute("src", cpuChoiceOutput + ".svg"); | |
return cpuChoiceOutput; | |
} | |
var cpuChoiceOutput = 'scissor'; | |
$cpuChoice.setAttribute("src", cpuChoiceOutput + ".svg"); | |
return cpuChoiceOutput; | |
}, | |
optionChoice: function optionChoice(option) { | |
return function () { | |
var cpuOption = app.cpuChoice(); | |
$userChoice.setAttribute("src", option + ".svg"); | |
jokenpo.play(option, cpuOption); | |
} | |
} | |
}; | |
})(); | |
app.init(); | |
})(window.jokenpo); |
Dá uma olhada no código que postei acima: essa é a interface do jogo, que consome somente dados. Uma função que recebe dados, e retorna dados. Só isso, independente de onde você vai consumir ela. Ela é genérica o suficiente para ser consumida de qualquer forma:
- diretamente no DOM;
- com um componente do React;
- até no backend, com NodeJS, se assim você quiser =)
Vou detalhar a ideia de como eu fiz, e deixar mais um dia para você tentar implementar. Se não conseguir, amanhã eu posto a solução de como eu implementei:
- Você precisa de uma função chamada
jokenpo
, que recebe dois parâmetros, que serão os nomes dos dois jogadores que irão participar do jogo; - Essa função, ao ser executada, deve retornar um objeto com duas funções:
score
eplay
; score
é uma função que, ao ser chamada, retorna um objeto que tem como chave os nomes dos usuários passados como parâmetro na funçãojokenpo
, e os valores são os pontos de cada um:{ fernando: 0, machine: 0 }
;- A função
play
recebe um objeto, com o nome dos jogadores, e a escolha de cada um, e retorna a mesma funçãoscore
anterior, que ao ser executada, vai sempre trazer o valor atualizado da pontuação dos jogadores selecionados.
A ideia é basicamente essa. Se você usar a função jokenpo
com jogadores diferentes, um novo jogo será iniciado. No exemplo acima, eu usei os jogadores fernando
e machine
. Esse objeto que a função jokenpo
retorna tem o estado do jogo para esses dois jogadores. Se você usar a função jokenpo
novamente, com outros dois jogadores, isso se torna um novo jogo, com um novo placar =)
Uma dica: lembre-se que funções podem ser closures
. Ao executar jokenpo
, ela vai guardar os valores de suas variáveis internas, por isso você consegue atualizar os pontos dos usuários sem que eles sejam zerados a cada vez que você chama score
ou play
=)
Não é tão simples, mas também não é tão complicado. Se você conseguiu entender todo o conceito passado no curso, você consegue fazer. Lembre-se que você só aprende realmente botando a mão na massa. É normal ter dificuldades no início, você vai aprendendo, entendendo como relacionar as coisas, e cada vez fica mais fácil de pensar em novos algoritmos =)
(function(){
'use strict';
var jokenpo = (function dataController(user, cpu) {
return {
play: function play(user, cpu) {
if(user === 'rock') {
return jokenpo.rockChoice(cpu);
} else if (user === 'paper') {
return jokenpo.paperChoice(cpu);
}
return jokenpo.scissorChoice(cpu);
},
rockChoice: function rockChoice(cpu) {
if(cpu === 'rock') {
console.log('draw');
} else if (cpu === 'paper') {
console.log('lose');
} else {
console.log('win');
}
},
paperChoice: function paperChoice(cpu) {
if(cpu === 'paper') {
console.log('draw');
} else if (cpu === 'scissor') {
console.log('lose');
} else {
console.log('win');
}
},
scissorChoice: function scissorChoice(cpu) {
if(cpu === 'scissor') {
console.log('draw');
} else if (cpu === 'rock') {
console.log('lose');
} else {
console.log('win');
}
},
score: function score(user, cpu) {
return { user: 0, cpu: 0 };
}
};
})();
window.jokenpo = jokenpo;
})();
Show cara! Tá indo bem! A ideia é essa mesmo: faz funcionar, depois refatora =)
Só pra ver se te ajuda, vou colocar como eu resolvi a parte de dados (sem manipulação de DOM):
;(function (win) {
'use strict';
function jokenpo (firstUser, secondUser) {
var usersPoints = {};
usersPoints[firstUser] = 0;
usersPoints[secondUser] = 0;
function play (choices) {
var users = Object.keys(usersPoints);
var usersChoices = users.reduce(function (acc, user) {
acc[user] = choices[user];
return acc;
}, {});
return whoWins(usersChoices);
}
function whoWins (usersChoices) {
var combinations = {
'rock paper': 'paper',
'rock scisor': 'rock',
'paper scisor': 'scisor'
};
var choices = Object.keys(usersChoices).map((user) => {
return usersChoices[user];
});
if (areChoicesTheSame(choices)) {
return generateScore({
usersChoices: usersChoices,
result: null
});
}
var combinationMatched = Object.keys(combinations).filter(function (combination) {
return combination.indexOf(choices[0]) > -1 &&
combination.indexOf(choices[1]) > -1
})[0];
var result = combinations[combinationMatched];
return generateScore({
usersChoices: usersChoices,
result: result
});
}
function areChoicesTheSame (choices) {
return choices[0] === choices[1];
}
function generateScore (result) {
Object.keys(usersPoints).forEach(function (user) {
if (result.usersChoices[user] === result.result) {
usersPoints[user] += 1;
}
});
return score;
}
function score (user) {
if (user && !isValidUser(user)) {
throw new Error('Usuário não existe');
}
return user ? usersPoints[user] : usersPoints;
}
function isValidUser (user) {
return Object.keys(usersPoints).some(function (u) {
return user === u;
});
}
return {
score: score,
play: play
};
}
win.jokenpo = jokenpo;
})(window);
Um teste de uso:
var game = jokenpo('fernando', 'machine');
console.log(game.score());
game.play({
fernando: 'rock',
machine: 'scisor'
});
console.log(game.score());
Veja se você consegue entender tudo.
Baixe ele e tente ir modificando as opções, colocando console.log
para ver o que acontece em cada momento do código. Assim vai ficar mais fácil de entender =)
Se ficou alguma dúvida com relação a esse código, só avisar =)
Vou tentar explicar a ideia base de como você pode manter os valores usando uma "closure":
- Você cria uma função que vai conter todo o código;
- Dentro dessa função, você vai iniciar as variáveis que você quer guardar os valores;
- Essa função retorna um objeto, com algum método que vai alterar os valores internos dela.
Só isso! Fazendo isso, a cada vez que você executar essa função, os valores internos serão diferentes. Mas se você usar o objeto retornado, você estará trabalhando com os valores guardados pela "closure".
Como fica na prática, seguindo os passos acima?
// Passo 1: Criar a função que vai guardar toda a minha aplicação.
function main () {
// Passo 2: Iniciar a variável que vai guardar os valores.
var value = 0;
// Passo 3: Retornar um objeto que contenha um método que modifica o valor guardado. Só como exemplo, a cada vez que chamar esse método, vou somar 1 ao valor de "value", e retornar esse valor:
return {
sum: function sum () {
value += 1;
return value;
}
};
}
É só isso! Como é o funcionamento da closure? Vamos criar uma aplicação usando essa função:
var app = main();
console.log(app.sum()); // 1
console.log(app.sum()); // 2
console.log(app.sum()); // 3
Veja que, a cada vez que eu chamo app.sum()
, é incrementado 1
em value
. app
é o objeto retornado pela função main
.
O real uso da closure se dá quando você precisa criar mais de uma aplicação ao mesmo tempo, fazendo uma "concorrência" entre as duas aplicações, mas usando a mesma função:
var app = main();
var app2 = main();
console.log(app.sum()); // 1
console.log(app.sum()); // 2
console.log(app2.sum()); // 1
console.log(app.sum()); // 3
console.log(app2.sum()); // 2
Olha só que legal! Uma não interfere na outra! Essa é a ideia de usar closures =)
Consegui entender?
A função jokenpo, vai fazer parte do modulo que vou criar, para tratar os dados correto?
Nela vou verificar quem venceu a sessão e tratar esses dados?
Estou apanhando um pouco pra entender sobre esses estados da aplicação.
Se eu declaro uma var userPoints, como eu vou alterando ela no decorrer do uso?