-
-
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); |
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?
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?
Um exemplo usando somente dados. A ideia de uso é essa: uma função
jokenpo
que receba por parâmetro o nome de dois jogadores e retorne dois métodos:play
para jogar escore
para mostrar o resultado. O uso é esse:Deu pra sacar a ideia? Eu fiz uma implementação, mas tente fazer você. No final do dia eu compartilho contigo a solução que eu fiz =)