2048 рдПрд░реНрд▓рд╛рдВрдЧ рдореЗрдВ

рдЫрд╡рд┐ рд╕рдВрднрд╡рддрдГ рдореЗрд░реЗ рдкрд╛рд╕ рд╣рдм рдкрд░ 2048 рдЧреЗрдо рдХреЗ рд▓рд┐рдП рд╕рдордп рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд▓реЗрдЦ рдЧреЗрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЗрддрдирд╛ рдирд╣реАрдВ рд╣реИ рдЬрд┐рддрдирд╛ рдХрд┐ рдПрд░рд▓рд╛рдВрдЧ рдкрд░ рд╡реЗрдмрд╕реЛрдХреЗрдЯ рд╕рд░реНрд╡рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред рдереЛрдбрд╝реА рдкреГрд╖реНрдарднреВрдорд┐ред рдЬрдм рдЙрдиреНрд╣реЛрдВрдиреЗ 2048 рдореЗрдВ рдЦреЗрд▓рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рддреЛ рд╡рд╣ рдмрд╕ рдирд╣реАрдВ рд░реЛрдХ рд╕рдХреЗред рдХрд╛рдо рдФрд░ рдкрд░рд┐рд╡рд╛рд░ рдХреЗ рдиреБрдХрд╕рд╛рди рдХреЗ рд▓рд┐рдПред рдЗрд╕рд▓рд┐рдП, рдЙрдиреНрд╣реЛрдВрдиреЗ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рдмреЙрдЯ рдХреЛ рдореЗрд░реЗ рд▓рд┐рдП рдЦреЗрд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди рдкрдХрдбрд╝ рдпрд╣ рд╣реИ рдХрд┐ рдЦреЗрд▓ рдХреНрд▓рд╛рдЗрдВрдЯ-рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╡реИрд╢реНрд╡рд┐рдХ рд░реЗрдЯрд┐рдВрдЧ рдХреЛ рдмрдирд╛рдП рдирд╣реАрдВ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рдмрд┐рдирд╛ рдЦреЗрд▓рдирд╛ рдЗрддрдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕рд░реНрд╡рд░ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬрд╣рд╛рдВ рд░реЗрдЯрд┐рдВрдЧ рд╣реЛрдЧреАред рдФрд░ рдореЗрд░рд╛ рдмреЙрдЯ рдмрд┐рдирд╛ рдмреНрд░рд╛рдЙрдЬрд░ рдХреЗ рдХрд╣рд╛рдВ рдЪрд▓ рд╕рдХрддрд╛ рд╣реИред


рдореИрдВрдиреЗ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдХрд┐ рдпрд╣ рдореЗрд░реА рдкрд╣рд▓реА рдПрд░реНрд▓рд╛рдВрдЧ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╣реИред рдХрдИ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдПрд░рд▓рд╛рдВрдЧ рд╕реЗ рдбрд░рддреЗ рд╣реИрдВ, рдпрд╣ рд╕реБрдЭрд╛рд╡ рджреЗрддреЗ рд╣реБрдП рдХрд┐ рдпрд╣ рдореБрд╢реНрдХрд┐рд▓ рд╣реИред рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВ рдЙрди рдХреНрд╖рдгреЛрдВ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдЬреЛ рдПрд░реНрд▓рд╛рдВрдЧ рдореЗрдВ рдПрдХ рдиреМрд╕рд┐рдЦрд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИрдВред

рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╣реБрдд рд╕реА рдЪреАрдЬреЗрдВ рд╣рд╛рд░реНрдбрдХреЛрдб рдХреА рдЬрд╛рддреА рд╣реИрдВред рд▓реЗрдХрд┐рди рдореИрдВ рд╣рдореЗрд╢рд╛ рд░рдЪрдирд╛рддреНрдордХ рдЖрд▓реЛрдЪрдирд╛ рдФрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рд╕реЗ рдЦреБрд╢ рд╣реВрдВред
Github рдХрд╛ рд▓рд┐рдВрдХ erl2048 рд╣реИ ред
рдХрд╛рдо рдХреЗ рдорд╕реМрджреЗ рд╕реЗ рд▓рд┐рдВрдХ - erl2048 рд▓реЗрдХрд┐рди, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рд╡рд╣ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рд╣реИрдмрд░рдлреИрдХреНрдЯ рдХреЗ рдиреАрдЪреЗ рдирд╣реАрдВ рд░рд╣реЗрдЧрд╛ред

рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ


рдЕрдЬреАрдм рддрд░рд╣ рд╕реЗ, рдореИрдВ JS рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░реВрдБрдЧрд╛ред рдореИрдВрдиреЗ рдореВрд▓ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдиреЗ рдкрд░ рдкреНрд░рд╛рдердорд┐рдХ рднрдВрдбрд╛рд░ рд╕реЗ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдореИрдВрдиреЗ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛:

рдореИрдВрдиреЗ "main.js" рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдИред рддрд░реНрдХ рд╕рд░рд▓ рд╣реИ - рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рд░реНрд╡рд░ рдХреЛ рдИрд╡реЗрдВрдЯ рднреЗрдЬрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдлрд╝реАрд▓реНрдб рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, animframe_polyfill рдЗрд╕ рддрд░рд╣ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЙрддреНрдкрдиреНрди рдЧреНрд░рд┐рдб рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред

рдореИрдВрдиреЗ рдХреНрдпрд╛ рдЬреЛрдбрд╝рд╛ред рдХрдиреЗрдХреНрд╢рди рдЖрд░рдВрднреАрдХрд░рдг:

var websocket = new Websocket(SERVER); websocket .connect() .done(function(){ var myGame = new MyGame(websocket); }); 

рдЙрдиреНрд╣реЛрдВрдиреЗ рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдкрд░ рдПрдХ рд░реИрдкрд░ рдорд╛рд░ рджрд┐рдпрд╛ред рдпрд╣рд╛рдВ рд╕реЛрд░реНрд╕ рдХреЛрдб рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред
рдПрдХ рдирдпрд╛ рдЦреЗрд▓ рд╢реБрд░реВ рдХрд░реЗрдВ:

 self.restart = function(evt){ websocket.send(JSON.stringify({ action:'start' })); }; 

рдПрдХ рдЪрд╛рд▓ рдмрдирд╛рдУ:
 self.move = function(direction){ // 0: up, 1: right, 2:down, 3: left if(!toMove){ return false; } if(direction === 0){ direction = 'up'; }else if(direction === 1){ direction = 'right'; }else if(direction === 2){ direction = 'down'; }else if(direction === 3){ direction = 'left'; } websocket.send(JSON.stringify({ action:'move', value: direction })); }; 


рдФрд░ рд╕рдмрд╕реЗ рдмрдбрд╝рд╛ред
рд╕рд░реНрд╡рд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг:
 self.wsHandler = function(evt){ var game = JSON.parse(evt.data); if(game.grid){ var grid = {cells: []}; game.grid.forEach(function (column, y) { var row = []; column.forEach(function (cell, x) { if(cell){ if(cell.mergedFrom){ cell.mergedFrom.forEach(function(tile){ tile['x'] = x; tile['y'] = y; }); } row.push({ value: cell.value, x: x, y: y, previousPosition: cell.previousPosition, mergedFrom: cell.mergedFrom }); } }); grid.cells.push(row); }); var scores = game.scores, bestScore = 0; if(scores && scores.length>0){ bestScore = scores[0].score; while (scoresEl.firstChild) { scoresEl.removeChild(scoresEl.firstChild); } scores.forEach(function(score){ var div = document.createElement('Div'); var name = document.createElement('Div'); var scoreEl = document.createElement('Div'); div.setAttribute("class", 'score'); name.setAttribute("class", 'name'); scoreEl.setAttribute("class", 'score'); name.appendChild(document.createTextNode(score.name)); scoreEl.appendChild(document.createTextNode(score.score)); div.appendChild(name); div.appendChild(scoreEl); scoresEl.appendChild(div); }); } actuator.actuate(grid, { score: game.score, bestScore: bestScore, score: game.score, won: game.won, over: game.over, keepPlaying: game.keepPlaying }); } //playername actuator if(game.user){ if(playername.value !== playername){ playername.value = game.user.name; } } }; 


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЧреЗрдо рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд░реНрд╡рд░ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╕рднреА рдЧрдгрдирд╛ рд╡рд╣рд╛рдВ рд╣реЛрддреА рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореЗрд░реЗ рдЦреЗрд▓ рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рдореЗрдВ , рдЬрд╣рд╛рдВ рддрд░реНрдХ рджреЛрд╣рд░рд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдкрд╕рдВрдж рдирд╣реАрдВ рд╣реИред
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореБрдЭреЗ рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрдпрд╛ рдХрд┐ рдЯрд╛рдЗрд▓ рдореЗрдВ рдореВрд▓ рдПрдХреНрд╕ рдФрд░ рд╡рд╛рдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕рд░реНрд╡рд░ рдЙрдирдХреЗ рдмрд┐рдирд╛ рдХрд░рддрд╛ рд╣реИред рдФрд░ рдЧреНрд░рд╛рд╣рдХ рдкрд░ рдореИрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХреНрдЯреВрдПрдЯрд░ рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛрдбрд╝ рд░рд╣рд╛ рд╣реВрдВред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рд╕рд░реНрд╡рд░ рд╕реЗ рд╢реАрд░реНрд╖ 10 рд╕рд░реНрд╡рд╢реНрд░реЗрд╖реНрда рдЦрд┐рд▓рд╛рдбрд╝рд┐рдпреЛрдВ рдХреА рд╕реВрдЪреА рдЖрддреА рд╣реИред рдпрд╣ рдореЗрд░реЗ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдПрдХ рдирд╡рд╛рдЪрд╛рд░ рд╣реИред рдФрд░ рдЦрд┐рд▓рд╛рдбрд╝реА рдЕрдкрдирд╛ рдЙрдкрдирд╛рдо рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИред рдХреЛрдИ рдкрдВрдЬреАрдХрд░рдг рдпрд╛ рд╕реБрд░рдХреНрд╖рд╛ рдирд╣реАрдВред рдПрдХ рдирд╛рдо рдФрд░ рдЦреЗрд▓ рджрд░реНрдЬ рдХрд┐рдпрд╛ред рдЖрдкрдХреЛ рдУрд╡рд░рдСрд▓ рд░реЗрдЯрд┐рдВрдЧ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреЗ рд╕реНрдХреЛрд░ рд╡рд╛рд▓реЗ рдмреЙрдХреНрд╕ рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдРрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИред



рджреЗрд╢реА рдХреАрдмреЛрд░реНрдб_рдЗрдирдкреБрдЯ_рдордирдЧрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИред рдХреНрдпреЛрдВрдХрд┐ рдЕрдм рд╕рднреА рд╡рд░реНрдг рдЙрдкрдирд╛рдо рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдореЗрдВ рджрд░реНрдЬ рдирд╣реАрдВ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЖрдк рдЕрдкрдиреЗ рдЙрдкрдирд╛рдо рдХреЛ рдХреНрд▓рд┐рдкрдмреЛрд░реНрдб рд╕реЗ рдЪрд┐рдкрдХрд╛ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рд╛рде рд╣реА, рдореИрдВрдиреЗ рд╕рднреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ред "рд╣рд╛рдирд┐" рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣рд┐рд╕реНрд╕рд╛ рдЕрднреА рднреА рдПрдХ рд╕реНрдЯрдм рджреНрд╡рд╛рд░рд╛ рдмрдВрдж рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЧреЗрдордкреНрд▓реЗ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдФрд░ рдЬреАрддрдиреЗ рдХреЗ рдмрд╛рдж рдЦреЗрд▓ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдЬреАрддрдирд╛ рдлрд┐рд░ рднреА рдЕрд╕рдлрд▓ рд░рд╣рд╛ред

Erlang


рдЗрд╕ рд╣рд┐рд╕реНрд╕реЗ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдЪрд┐рддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдкрд╣рд▓реЗ рдЖрдкрдХреЛ rebar рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЖрдк рдЗрд╕реЗ рдпрд╣рд╛рдБ рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред Rebar рдЖрд░рдВрднрд┐рдХ рдлрд╛рдЗрд▓реЗрдВ рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЙрдиреНрд╣реЗрдВ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмрдирд╛рдпрд╛ рд╣реИред
"Rebar.config" - рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдирд┐рд░реНрднрд░рддрд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда
 % The next option is required so we can use lager. {erl_opts, [{parse_transform, lager_transform}]}. {lib_dirs,["deps"]}. % Our dependencies. {deps, [ {'lager', ".*", { git, "git://github.com/basho/lager.git", "master"} }, {'cowboy', ".*", { git, "git://github.com/extend/cowboy.git", "master"} }, {'mochiweb', ".*", { git, "git://github.com/mochi/mochiweb.git", "master"} }, {'sqlite3', ".*", { git, "git://github.com/alexeyr/erlang-sqlite3.git", "master"} } ]}. 

 # rebar gd # rebar co 

рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдЗрдХрдЯреНрдард╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдЖрдкрдХреЛ sqlite рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рд▓рд┐рдП "libsqlite3-dev" рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред

рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ:
 # rebar compile skip_deps=true; erl -pa ebin deps/*/ebin -eval 'starter:start().' -noshell -detached 

рдЙрд╕рдХреЗ рдмрд╛рдж, рдЦреЗрд▓ рдкреЛрд░реНрдЯ 8080 рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реЛрдЧрд╛ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд▓реЙрдиреНрдЪ рдХрд░рдирд╛ рд╕реАрдЦрдирд╛ рд╕рдмрд╕реЗ рдХрдард┐рди рдерд╛ред рдЖрдЧреЗ рдпрд╣ рдЖрд╕рд╛рди рд╣реИред рдореИрдВрдиреЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдореЙрдбреНрдпреВрд▓ "рд╕реНрдЯрд╛рд░реНрдЯрд░" рдмрдирд╛рдпрд╛ рдЬреЛ рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛рдУрдВ рдФрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЪрд▓рд╛рддрд╛ рд╣реИред

 -module(starter). -export([start/0]). start() -> application:start(ranch), application:start(crypto), application:start(cowlib), application:start(cowboy), application:start(inets), application:start(mochiweb), application:start(erl2048). 

рдЕрдм src рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреА рд╕рд╛рдордЧреНрд░реА рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рдкрд╣рд▓реА erl2048.app.src рдлрд╝рд╛рдЗрд▓ рд╣реИред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рд╕рд┐рд░реНрдл рдорд╛рдорд▓реЗ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рд╣реИред

рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда
 {application, erl2048, [ {description, "2048 game server."}, {vsn, "1"}, {modules, []}, {registered, [erl2048_sup]}, {applications, [ kernel, stdlib, cowboy ]}, {mod, {erl2048_app, []}}, {env, []} ]}. 


erl2048_sup.erl
 %% Feel free to use, reuse and abuse the code in this file. %% @private -module(erl2048_sup). -behaviour(supervisor). %% API. -export([start_link/0]). %% supervisor. -export([init/1]). %% API. -spec start_link() -> {ok, pid()}. start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). %% supervisor. init([]) -> Procs = [], {ok, {{one_for_one, 10, 10}, Procs}}. 

рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдмрд╛рдд рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреНрд░реИрд╢ рди рд╣реЛ рдФрд░ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ рддреЛ рдкреБрдирд░рд╛рд░рдВрдн рд╣реЛред рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рд▓рд┐рдпрд╛ - рдЫреЛрдбрд╝рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред

рдЕрдм рдореБрдЦреНрдп рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдлрд╝рд╛рдЗрд▓ "erl2048_app.erl" рд╣реИред

рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда
 %% Feel free to use, reuse and abuse the code in this file. %% @private -module(erl2048_app). -behaviour(application). %% API. -export([start/2]). -export([stop/1]). %% API. start(_Type, _Args) -> Dispatch = cowboy_router:compile([ {'_', [ {"/", cowboy_static, {file, "../client/index.html"}}, {"/websocket", ws_handler, []}, {"/static/[...]", cowboy_static, {dir, "../client/static"}} ]} ]), {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [{env, [{dispatch, Dispatch}]}]), {ok, _} = db:start_link(), erl2048_sup:start_link(). stop(_State) -> {ok, _} = db:stop(), ok. 

рдпрд╣рд╛рдВ рдореИрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреБрдЫ рд╕рдордЭрд╛ рд╕рдХрддрд╛ рд╣реВрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЪрд░рд╡рд╛рд╣реЗ рдХреЗ рд▓рд┐рдП рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдлрд┐рд░ рдЪрд░рд╡рд╛рд╣рд╛ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдЬреБрдбрд╝рддрд╛ рд╣реИред
рдЙрдк рдХреА рднреВрдорд┐рдХрд╛ sqlite рд╣реИред рдореИрдВрдиреЗ Postgresql, mongoDB рдФрд░ Redis рдХреЛ рднреА рдорд╛рдирд╛ред рд▓реЗрдХрд┐рди рд╕рд╛рдЗрдХреНрд▓рд╛рдЗрдЯ рдкрд░ рдмрд╕реЗ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╣реИред рдкреБрдирд░рд╛рд░рдВрдн рдХреЗ рдмрд╛рдж рдкреНрд▓рд╕ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рдпрд╣ рдЖрд╡реЗрджрди рдкрд░ рдПрдХ рдмрдбрд╝рд╛ рднрд╛рд░ рдкреИрджрд╛ рдХрд░реЗрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдЭреВрда рд╣реЛрдЧрд╛ред рд╡реИрд╕реЗ рднреА - рдореЙрдбреНрдпреВрд▓ рдХреЛрдб:

рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда
 -module(db). -export([start_link/0,stop/0]). -export([insert/2, select/0, createUser/1, changeName/2]). start_link() -> {ok, PID} = sqlite3:open(db, [{file, "db.sqlite3"}]), Tables = sqlite3:list_tables(db), case lists:member("scores", Tables) of false -> sqlite3:create_table(db, scores, [{id, integer, [{primary_key, [asc, autoincrement]}]}, {userid, integer}, {score, integer}]) end, case lists:member("users", Tables) of false -> sqlite3:create_table(db, users, [{id, integer, [{primary_key, [asc, autoincrement]}]}, {name, text}]) end, {ok, PID}. stop() -> sqlite3:close(db). select() -> Ret = sqlite3:sql_exec(db, "select users.name, scores.score from scores LEFT JOIN users ON (users.id = scores.userid) ORDER BY score desc;"), [{columns,_},{rows,Rows}] = Ret, formatScores(Rows). insert(Score, Player) -> [{columns,_},{rows,Rows}] = sqlite3:sql_exec(db, "SELECT score FROM scores WHERE userid = ?", [{1,Player}]), DBScore = if length(Rows) > 0 -> element(1,hd(Rows)); true -> 0 end, if Score > DBScore -> sqlite3:delete(db, scores, {userid, Player}), sqlite3:write(db, scores, [{userid, Player}, {score, Score}]), sqlite3:sql_exec(db, "DELETE FROM scores WHERE id IN (SELECT id FROM scores ORDER BY score desc LIMIT 1 OFFSET 10)"); true -> undefined end. formatScores([]) -> []; formatScores([{Name, Score} | Rows]) -> [{struct, [{name, Name},{score, Score}]} | formatScores(Rows)]. createUser(UserName) -> sqlite3:write(db, users, [{name, UserName}]). changeName(Id, NewName) -> sqlite3:update(db, users, {id, Id}, [{name, NewName}]). 


рдЖрдЗрдП рд╡реЗрдмрд╕реИрдЯ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдореЙрдбреНрдпреВрд▓ рдкрд░ рдЪрд▓рддреЗ рд╣реИрдВред

ws_handler.erl
 -module(ws_handler). -behaviour(cowboy_websocket_handler). -export([init/3]). -export([websocket_init/3]). -export([websocket_handle/3]). -export([websocket_info/3]). -export([websocket_terminate/3]). init({tcp, http}, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. websocket_init(_TransportName, Req, _Opts) -> State = {struct, [ { user, { struct, [{id, null},{name, <<"Player">>}] } } ]}, {ok, Req, State}. websocket_handle({text, Msg}, Req, State) -> Message = mochijson2:decode(Msg, [{format, proplist}]), Action = binary_to_list(proplists:get_value(<<"action">>, Message)), {NewState, Response} = case Action of "start" -> TmpState = game:init(State), {TmpState, TmpState}; "move" -> TmpState = game:move(list_to_atom(binary_to_list(proplists:get_value(<<"value">>, Message))), State), {TmpState, TmpState}; "newName" -> NewName = proplists:get_value(<<"value">>, Message), JsonData = element(2, State), User = proplists:get_value(user, JsonData), {struct,UserJsonData} = User, Id = proplists:get_value(id, UserJsonData), db:changeName(Id, NewName), TmpState = {struct, [ { user, { struct, [ { name, NewName },{ id, Id } ] } } | proplists:delete(user, JsonData) ]}, { TmpState, {struct, [{ user, { struct, [ { name, NewName },{ id, Id } ] } }]} }; _Else -> State end, {reply, {text, mochijson2:encode(Response)}, Req, NewState}; websocket_handle(_Data, Req, State) -> {ok, Req, State}. websocket_info({send, Msg}, Req, State) -> {reply, {text, Msg}, Req, State}; websocket_info(_Info, Req, State) -> {ok, Req, State}. websocket_terminate(_Reason, _Req, _State) -> ok. 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореБрдЭреЗ рд╕рдордЭ рдирд╣реАрдВ рдЖрдпрд╛ рдХрд┐ рдпрд╣ рд╕рдм рдХреИрд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рдПрдХ рд░рд╛рдЬреНрдп рд╣реИ рдЬреЛ рддрдм рд╕реНрдерд╛рдкрд┐рдд рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдХрдиреЗрдХреНрд╢рди рд╕реНрдерд╛рдкрд┐рдд рд╣реЛрддрд╛ рд╣реИред рдФрд░ рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ рдЧреНрд░рд╛рд╣рдХ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рд╣реИрдВрдбрд▓рд░ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдореБрдЦреНрдп рд╡рд┐рдзрд┐ "websocket_handle" рд╣реИред рдпрд╣ рд╕рдВрджреЗрд╢ рдФрд░ рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдФрд░ рд╕реНрдерд┐рддрд┐ рджреЗрддрд╛ рд╣реИред
рд╕рдВрдЪрд╛рд░ рдХреЗ рд▓рд┐рдП, JSON рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдПрд░реНрд▓реИрдВрдЧ рдореЗрдВ, рдпрд╣ рд╕рдВрд░рдЪрдирд╛ рдХреА рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ:

 {struct, [ {key1, Value1}, {key2, Value2}, .... ]} 


рдЕрдм рд╕реАрдзреЗ рдЦреЗрд▓ рдХреА рдлрд╛рдЗрд▓реЗрдВред рд╕рдмрд╕реЗ рд╕рд░рд▓ "рдЯрд╛рдЗрд▓" рд╣реИред

tile.erl
 -module(tile). -export([init/1, init/0, prepare/2]). prepare(null, _) -> null; prepare(Tile, { X, Y }) -> { struct, [ {value, proplists:get_value(value, element(2, Tile))}, {mergedFrom, null}, {previousPosition, {struct, [{ x, X - 1},{ y, Y - 1 }]}} ] }. init(Value) -> { struct, [ {value, Value}, {mergedFrom, null}, {previousPosition, null} ] }. init() -> init(2). 

рд╡рд╣ рдХреЗрд╡рд▓ рдПрдХ рдирдИ рдЯрд╛рдЗрд▓ рдмрдирд╛рдирд╛ рдФрд░ рдкрд┐рдЫрд▓реЗ рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрдирд╛рдП рд░рдЦрдирд╛ рдЬрд╛рдирддрд╛ рд╣реИред
"Grid.erl" рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИред

grid.erl
 -module(grid). -export([ build/0, cellsAvailable/1, randomAvailableCell/1, insertTile/3, availableCells/1, cellContent/2, removeTile/2, moveTile/3, size/0, withinBounds/1, cellAvailable/2 ]). -define(SIZE, 4). size() -> ?SIZE. build() -> [[null || _ <- lists:seq(1, ?SIZE)] || _ <- lists:seq(1, ?SIZE)]. availableCells(Grid) -> lists:append( setY( availableCells(Grid, 1) ) ). availableCells([Grid | Tail ], N) when is_list(Grid) -> [{availableCells(Grid, 1), N} | availableCells(Tail, N +1)]; availableCells([Grid | Tail ], N) -> case Grid =:= null of true -> [ N | availableCells(Tail, N +1)]; false -> availableCells(Tail, N +1) end; availableCells([], _) -> []. setY([{Cell, Y}|Tail]) -> [ setY(Cell, Y) | setY(Tail)]; setY([]) -> []. setY([Head | Tail], Y) -> [ {Head, Y} | setY(Tail, Y)]; setY([], _) -> []. cellsAvailable(Grid) -> length(availableCells(Grid)) > 0. randomAvailableCell(Grid) -> Cells = availableCells(Grid), lists:nth(random:uniform(length(Cells)) ,Cells). insertTile({X, Y}, Tile, Grid) -> Row = lists:nth(Y,Grid), lists:sublist(Grid,Y - 1) ++ [ lists:sublist(Row,X - 1) ++ [Tile] ++ lists:nthtail(X,Row)] ++ lists:nthtail(Y,Grid). cellContent({ X, Y }, Grid) -> case withinBounds({ X, Y }) of true -> lists:nth(X,lists:nth(Y,Grid)); false -> null end. removeTile({ X, Y }, Grid) -> insertTile({X, Y}, null, Grid). moveTile(Cell, Cell, Grid) -> Grid; moveTile(Cell, Next, Grid) -> insertTile(Next, grid:cellContent(Cell, Grid), removeTile(Cell, Grid)). withinBounds({X, Y}) when (X > 0), (X =< ?SIZE), (Y > 0), (Y =< ?SIZE) -> true; withinBounds(_) -> false. cellAvailable(Cell, Grid) -> case grid:withinBounds(Cell) of true -> cellContent(Cell, Grid) =:= null; false -> false end. 

рдЙрдкрд▓рдмреНрдз рдХреЙрд▓реНрд╕ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред рдПрд░реНрд▓реИрдВрдЧ рдХреЛ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рдореИрдВ рдмрд╣реБрдд рдЪрд╛рд▓рд╛рдХ рд╣реВрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рд╢реАрдЯ рдЙрддреНрдкрдиреНрди рдХреА рдЧрдИ рдереА рдЬрд┐рд╕рдореЗрдВ рдПрдХ рд╕рдордиреНрд╡рдп рдХреЗ рд╕рд╛рде рдЪрд╛рджрд░реЗрдВ рдереАрдВ рдФрд░ рджреВрд╕рд░рд╛ рд╕рдордиреНрд╡рдпред рдФрд░ рдлрд┐рд░ рдЙрд╕рдиреЗ рджреВрд╕рд░реЗ рдХреЛ рдкрд╣рд▓реА рдмрд╛рд░ рдкреЗрд╢ рдХрд┐рдпрд╛ред рдореИрдВрдиреЗ рддрдп рдХрд┐рдпрд╛ рдХрд┐ рдЕрдм рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдореЗрд░реЗ рд╡рд┐рдЪрд╛рд░ рд╕реЗ рдЕрдиреНрдп рдХрд╛рд░реНрдп рд╕реНрдкрд╖реНрдЯ рд╣реИрдВред
рдФрд░, рдореБрдЦреНрдп рдЦреЗрд▓ рдлрд╝рд╛рдЗрд▓ред рдЗрд╕реЗ "game.erl" рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред

game.erl
 -module(game). -export([init/1, move/2]). init(State) -> StateUser = proplists:get_value(user, element(2, State)), StateUserJsonData = element(2, StateUser), User = case proplists:get_value(id, StateUserJsonData) of null -> Name = proplists:get_value(name, StateUserJsonData), {rowid, Id} = db:createUser(Name), { struct, [{name, Name},{id, Id}]}; _Else -> StateUser end, { struct, [ {grid ,addStartTiles(grid:build())}, {user , User}, {score,0}, {scores, db:select()}, {won, false}, {over, false}, {keepPlaying, false} ] }. addStartTiles(Grid, 0) -> Grid; addStartTiles(Grid, N) -> NewGrid = addRandomTile(Grid), addStartTiles(NewGrid, N - 1). addStartTiles(Grid) -> addStartTiles(Grid, 2). addRandomTile(Grid) -> random:seed(now()), case grid:cellsAvailable(Grid) of true -> case random:uniform(10) < 9 of true -> Tile = tile:init(); false -> Tile = tile:init(grid:size()) end, grid:insertTile(grid:randomAvailableCell(Grid), Tile, Grid); false -> Grid end. getVector(left) -> { -1, 0 }; getVector(up) -> { 0, -1 }; getVector(right) -> { 1, 0 }; getVector(down) -> { 0, 1 }. buildTraversals() -> Traver = lists:seq(1, grid:size()), { Traver, Traver }. buildTraversals({ 1 , _ }) -> { T1, T2} = buildTraversals(), { lists:reverse(T1), T2 }; buildTraversals({ _ , 1 }) -> { T1, T2} = buildTraversals(), { T1, lists:reverse(T2) }; buildTraversals({ _ , _ }) -> buildTraversals(). prepareTiles( [{_Key, _Value} | _Tail ] ) -> JsonData = [{_Key, _Value} | _Tail ], [{ grid, prepareTiles(proplists:get_value(grid, JsonData)) } | proplists:delete(grid, JsonData) ]; prepareTiles( Grid ) -> prepareTiles( Grid, 1). prepareTiles([], _) -> []; prepareTiles([Row | Tail], Y) -> [ prepareTileY(Row, 1, Y) | prepareTiles(Tail, Y + 1)]. prepareTileY([], _, _) -> []; prepareTileY([Cell | Tail], X, Y) -> [prepareTileX(Cell, X, Y) | prepareTileY(Tail, X + 1, Y) ]. prepareTileX(Tile, X, Y) -> tile:prepare(Tile, {X, Y}). process_travesals_y([], _, _, JsonData) -> JsonData; process_travesals_y(_, [], _, JsonData) -> JsonData; process_travesals_y([ Y | Tail ], TraversalsX, Vector, JsonData) -> process_travesals_y( Tail, TraversalsX, Vector, process_travesals_y( Y, TraversalsX, Vector, JsonData) ); process_travesals_y(Y, [ X | Tail ], Vector, JsonData) -> process_travesals_y(Y, Tail, Vector, process_travesals_y( Y, X, Vector, JsonData )); process_travesals_y( Y, X, Vector, JsonData ) -> moveTile({ X, Y }, Vector, JsonData). findFarthestPosition({X, Y}, {VecX, VecY}, Grid) -> Next = { X + VecX, Y + VecY }, case grid:cellAvailable(Next, Grid) of true -> findFarthestPosition(Next, {VecX, VecY}, Grid); false -> { {X, Y}, Next % Used to check if a merge is required } end. moveTile(Cell, Vector, JsonData) -> Grid = proplists:get_value(grid, JsonData), Tile = grid:cellContent(Cell, Grid), case Tile =:= null of true -> JsonData; false -> { Farthest, Next } = findFarthestPosition(Cell, Vector, Grid), {struct, CurrJsonData} = Tile, CurrValue = proplists:get_value(value, CurrJsonData), NextTile = if Next =:= null -> null; true -> grid:cellContent(Next, Grid) end, {NextValue, NextMerged} = if NextTile =:= null -> {null, null}; true -> NextJsonData = element(2, NextTile), {proplists:get_value(value, NextJsonData), proplists:get_value(mergedFrom, NextJsonData)} end, if CurrValue =:= NextValue, NextMerged =:= null -> MergedValue = CurrValue * 2, Merged = { struct, [ {value, MergedValue}, {mergedFrom, [Tile,NextTile]}, {previousPosition, null} ] }, NewGrid = grid:insertTile(Next, Merged, grid:removeTile(Cell, Grid)), % Update the score Score = proplists:get_value(score, JsonData) + MergedValue, % The mighty 2048 tile Won = if MergedValue =:= 2048 -> true; true -> false end, Removed = proplists:delete(score, proplists:delete(won, proplists:delete(grid, JsonData))), [ {grid,NewGrid}, {won,Won}, {score,Score} | Removed ]; true -> [ { grid, grid:moveTile(Cell, Farthest, proplists:get_value(grid, JsonData)) } | proplists:delete(grid, JsonData) ] end end. move(left, State) -> move(getVector(left), State); move(right, State) -> move(getVector(right), State); move(up, State) -> move(getVector(up), State); move(down, State) -> move(getVector(down), State); move(Vector, State) -> {struct, JsonData} = State, case proplists:get_value(over, JsonData) or ( proplists:get_value(won, JsonData) and (not proplists:get_value(keepPlaying, JsonData)) ) of true -> State; _Else -> PreparedJsonData = updateBestScore(prepareTiles(JsonData)), { TraversalsX, TraversalsY } = buildTraversals(Vector), NewJsonData = process_travesals_y( TraversalsY, TraversalsX, Vector, PreparedJsonData ), NewGrid = proplists:get_value(grid, NewJsonData), Grid = proplists:get_value(grid, PreparedJsonData), if NewGrid =/= Grid -> %If changed - add new tile {struct, UserJsonData} = proplists:get_value(user, NewJsonData), NewScore = proplists:get_value(score, NewJsonData), Score = proplists:get_value(score, PreparedJsonData), case NewScore > Score of true -> db:insert( proplists:get_value(score, NewJsonData), proplists:get_value(id, UserJsonData) ); _Else -> undefined end, Over = case movesAvailable(NewGrid) of true -> false; fale -> true % Game over! end, Removed = proplists:delete(grid, proplists:delete(over, NewJsonData)), {struct,[{ grid, addRandomTile(NewGrid) }, { over, Over } | Removed ]}; true -> %return state otherwise {struct,PreparedJsonData} end end. movesAvailable(_) -> true. updateBestScore(JsonData) -> [{ scores, db:select() } | proplists:delete(scores, JsonData) ]. 

Init рдлрд╝рдВрдХреНрд╢рди - рдпрджрд┐ рдХреЛрдИ рдмрдирд╛рдпрд╛ рдирд╣реАрдВ рдЧрдпрд╛ рд╣реИ рддреЛ рдПрдХ рдирдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдмрдирд╛рддрд╛ рд╣реИред рдпрд╛ рдкрд┐рдЫрд▓реЗ рдЧреЗрдо рд╕реЗ рд▓реЗрддрд╛ рд╣реИред

 init(State) -> StateUser = proplists:get_value(user, element(2, State)), StateUserJsonData = element(2, StateUser), User = case proplists:get_value(id, StateUserJsonData) of null -> Name = proplists:get_value(name, StateUserJsonData), {rowid, Id} = db:createUser(Name), { struct, [{name, Name},{id, Id}]}; _Else -> StateUser end, { struct, [ {grid ,addStartTiles(grid:build())}, {user , User}, {score,0}, {scores, db:select()}, {won, false}, {over, false}, {keepPlaying, false} ] }. 

рдореБрдЦреНрдп рдХрд╛рд░реНрдп рдЪрд╛рд▓ рд╣реИред рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдХреА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ред рдпрд╣рд╛рдВ рдореБрд╢реНрдХрд┐рд▓реЗрдВ рдереАрдВ, рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЗрдВ рдЕрдиреБрднрд╡ рдХреА рдХрдореА рдХреЗ рдХрд╛рд░рдгред

 move(left, State) -> move(getVector(left), State); move(right, State) -> move(getVector(right), State); move(up, State) -> move(getVector(up), State); move(down, State) -> move(getVector(down), State); move(Vector, State) -> {struct, JsonData} = State, case proplists:get_value(over, JsonData) or ( proplists:get_value(won, JsonData) and (not proplists:get_value(keepPlaying, JsonData)) ) of true -> State; _Else -> PreparedJsonData = updateBestScore(prepareTiles(JsonData)), { TraversalsX, TraversalsY } = buildTraversals(Vector), NewJsonData = process_travesals_y( TraversalsY, TraversalsX, Vector, PreparedJsonData ), NewGrid = proplists:get_value(grid, NewJsonData), Grid = proplists:get_value(grid, PreparedJsonData), if NewGrid =/= Grid -> %If changed - add new tile {struct, UserJsonData} = proplists:get_value(user, NewJsonData), NewScore = proplists:get_value(score, NewJsonData), Score = proplists:get_value(score, PreparedJsonData), case NewScore > Score of true -> db:insert( proplists:get_value(score, NewJsonData), proplists:get_value(id, UserJsonData) ); _Else -> undefined end, Over = case movesAvailable(NewGrid) of true -> false; fale -> true % Game over! end, Removed = proplists:delete(grid, proplists:delete(over, NewJsonData)), {struct,[{ grid, addRandomTile(NewGrid) }, { over, Over } | Removed ]}; true -> %return state otherwise {struct,PreparedJsonData} end end. 

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рдЪрд╛рд▓ рдкреВрд░реА рд╣реБрдИ рд╣реИ, рдореИрдВ рдкреБрд░рд╛рдиреЗ рд░рд╛рдЬреНрдп рдФрд░ рдирдП рдХреА рддреБрд▓рдирд╛ рдХрд░рддрд╛ рд╣реВрдВред рдЬреЗрдПрд╕ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдПрдХ рдмрд╛рд╣рд░реА рдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдЗрд╕рд╕реЗ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдХрдореА рдЖрдПрдЧреА рдпрд╛ рдирд╣реАрдВред рдФрд░ рдлрд┐рд░ рдореИрдВ рдЬрд╛рдВрдЪрддрд╛ рд╣реВрдВ рдХрд┐ рдХреНрдпрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдкреНрд░рд╢реНрди рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦрд╛рддрд╛ рдмрджрд▓ рдЧрдпрд╛ рд╣реИред
рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде, рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдХрдИ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╢рд╛рдпрдж рд╣реА рдХрднреА рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддрд╛ рд╣реИред рдореБрдЭреЗ рд╕рдмрд╕реЗ рдЬреНрдпрд╛рджрд╛ рдЙрд▓рдЭрди рдЗрд╕ рдмрд╛рдд рдХреА рд╣реИ рдХрд┐ рдореИрдВ TraversalsY, TraversalsX, рд╡реЗрдХреНрдЯрд░ рдХреЛ process_travesals_y рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ, рд╣рд╛рд▓рд╛рдВрдХрд┐ TraversalsY рдФрд░ TraversalsX рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╡реЗрдХреНрдЯрд░ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИрдВред рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЫреЛрдбрд╝рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред
"рдЙрдкрд▓рдмреНрдз рдХреЙрд▓реНрд╕" рдЕрдиреБрднрд╡ рдХреЛ рдирд╣реАрдВ рджреЛрд╣рд░рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдлрд╝рдВрдХреНрд╢рди "process_travesals_y" рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд▓рд┐рдЦрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдм рдпрд╣ рдПрдХреНрд╕ рдкрд░ рдЕрд▓рдЧ рд╕реЗ рдФрд░ рд╡рд╛рдИ рдкрд░ рдЕрд▓рдЧ рд╕реЗ рд╣реИред рдФрд░ рдЕрдВрдд рдореЗрдВ, рдпрд╣ рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдЧреИрд░-рд╢реВрдиреНрдп рддрддреНрд╡ рдХреЗ рд▓рд┐рдП "рдореВрд╡рдореЗрдВрдЯ" рдХрд╣рддрд╛ рд╣реИред рдЬреЛ, рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдЬреЗрдПрд╕-рдореВрд▓ рдХреЗ рд╕рд╛рде рд▓рдЧрднрдЧ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдВрдЧрдд рд╣реИред

 moveTile(Cell, Vector, JsonData) -> Grid = proplists:get_value(grid, JsonData), Tile = grid:cellContent(Cell, Grid), case Tile =:= null of true -> JsonData; false -> { Farthest, Next } = findFarthestPosition(Cell, Vector, Grid), {struct, CurrJsonData} = Tile, CurrValue = proplists:get_value(value, CurrJsonData), NextTile = if Next =:= null -> null; true -> grid:cellContent(Next, Grid) end, {NextValue, NextMerged} = if NextTile =:= null -> {null, null}; true -> NextJsonData = element(2, NextTile), {proplists:get_value(value, NextJsonData), proplists:get_value(mergedFrom, NextJsonData)} end, if CurrValue =:= NextValue, NextMerged =:= null -> MergedValue = CurrValue * 2, Merged = { struct, [ {value, MergedValue}, {mergedFrom, [Tile,NextTile]}, {previousPosition, null} ] }, NewGrid = grid:insertTile(Next, Merged, grid:removeTile(Cell, Grid)), % Update the score Score = proplists:get_value(score, JsonData) + MergedValue, % The mighty 2048 tile Won = if MergedValue =:= 2048 -> true; true -> false end, Removed = proplists:delete(score, proplists:delete(won, proplists:delete(grid, JsonData))), [ {grid,NewGrid}, {won,Won}, {score,Score} | Removed ]; true -> [ { grid, grid:moveTile(Cell, Farthest, proplists:get_value(grid, JsonData)) } | proplists:delete(grid, JsonData) ] end end. 


рдЗрд╕ рдкрд░, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рдПрд░рд▓рд╛рдВрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХрд╣рд╛рдиреА рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИред рдореБрдЭреЗ рд╕рднреА рд╕рд╡рд╛рд▓реЛрдВ рдХреЗ рдЬрд╡рд╛рдм рджреЗрдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реЛрдЧреАред

Source: https://habr.com/ru/post/In216517/


All Articles