码迷,mamicode.com
首页 > 其他好文 > 详细

用 React 编写2048游戏

时间:2015-12-25 22:14:35      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:

1.代码

  1 <!DOCTYPE html>
  2 <html lang="zh-cn">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>万能的React</title>
  6     <style>
  7         .app{
  8             margin:10px;
  9             font-family: arial;
 10         }
 11         .board{
 12             display:block;
 13             position:relative;
 14             margin:10px 0px 10px 0px;
 15             border:1px solid #ccc;
 16             width:215px;
 17             height:215px;
 18             padding:5px;
 19         }
 20         .board span{
 21             font-family: arial;
 22             letter-spacing: -1px;
 23             display:block;
 24             width:50px;
 25             height:36px;
 26             position:absolute;
 27             text-align:center;
 28             color:white;
 29             font-weight:bold;
 30             font-size:20px;
 31             padding-top:14px;
 32             background-color:#ebe76f;
 33             border-radius: 5px;
 34             transition: all 100ms linear;
 35         }
 36         .a1, .b1, .c1, .d1{ left:5px; }
 37         .a2, .b2, .c2, .d2{ left:60px; }
 38         .a3, .b3, .c3, .d3{ left:115px; }
 39         .a4, .b4, .c4, .d4{ left:170px; }
 40         .a1, .a2, .a3, .a4{ top:5px; }
 41         .b1, .b2, .b3, .b4{ top:60px; }
 42         .c1, .c2, .c3, .c4{ top:115px; }
 43         .d1, .d2, .d3, .d4{ top:170px; }
 44         span.value2{ background-color:#ebb26f; }
 45         span.value4{ background-color:#ea6feb; }
 46         span.value8{ background-color:#eb6fa3; }
 47         span.value16{ background-color:#7a6feb; }
 48         span.value32{ background-color:#af6feb; }
 49         span.value64{ background-color:#6febcf; }
 50         span.value128{ background-color:#6fbeeb; }
 51         span.value256{ background-color:#afeb6f; }
 52         span.value512{ background-color:#7aeb6f; }
 53         span.value1024{ background-color:#e4eb6f; }
 54     </style>
 55 </head>
 56 <body>
 57     <script src="./react-0.13.2/react-0.13.2/build/react.js"></script>
 58     <script src="./react-0.13.2/react-0.13.2/build/JSXTransformer.js"></script>
 59     <script type="text/jsx">
 60         var initial_board = {
 61             a1:null,a2:null,a3:null,a4:null,
 62             b1:null,b2:null,b3:null,b4:null,
 63             c1:null,c2:null,c3:null,c4:null,
 64             d1:null,d2:null,d3:null,d4:null
 65         };
 66 
 67         function available_spaces(board){
 68             return Object.keys(board).filter(function(key){
 69                 return board[key] == null
 70             });
 71         }
 72 
 73         function used_spaces(board){
 74             return Object.keys(board).filter(function(key){
 75                 return board[key] !== null
 76             });
 77         }
 78 
 79         function score_board(board){
 80             return used_spaces(board).map(function(key){
 81                 return (board[key].values.reduce(function(a, b) {
 82                     return a + b; //sum tile values
 83                 })) - board[key].values[0]; //don‘t count initial value
 84             }).reduce(function(a,b){return a+b}, 0);
 85         }
 86 
 87         function tile_value(tile){
 88             return tile ? tile.values[tile.values.length-1] : null;
 89         }
 90 
 91         function can_move(board){
 92             var new_board = [up,down,left,right].reduce(function(b, direction){
 93                 return fold_board(b, direction);
 94             }, board);
 95             return available_spaces(new_board).length > 0
 96         }
 97 
 98         function same_board(board1, board2){
 99             return Object.keys(board1).reduce(function(ret, key){
100                 return ret && board1[key] == board2[key];
101             }, true);
102         }
103 
104         function fold_line(board, line){
105             var tiles = line.map(function(key){
106                 return board[key];
107             }).filter(function(tile){
108                  return tile !== null
109             });   
110             var new_tiles = [];
111             if(tiles){
112                 //must loop so we can skip next if matched
113                 for(var i=0; i < tiles.length; i++){
114                    var tile = tiles[i];
115                    if(tile){
116                        var val = tile_value(tile);
117                        var next_tile = tiles[i+1];
118                         if(next_tile && val == tile_value(next_tile)){
119                             //skip next tile;
120                             i++;
121                             new_tiles.push({
122                                 id: next_tile.id, //keep id
123                                 values: tile.values.concat([val * 2])
124                             });
125                         }
126                         else{
127                             new_tiles.push(tile);
128                         }
129                     }
130                 }
131             }
132             var new_line = {};
133             line.forEach(function(key, i){
134                 new_line[key] = new_tiles[i] || null;
135             });
136             return new_line;
137         }
138 
139         function fold_order(xs, ys, reverse_keys){
140             return xs.map(function(x){
141                 return ys.map(function(y){
142                     var key = [x,y];
143                     if(reverse_keys){
144                         return key.reverse().join("");
145                     }
146                     return key.join("");
147                 });
148             });
149         }
150 
151         function fold_board(board, lines){
152             //copy reference
153             var new_board = board;
154             lines.forEach(function(line){
155                 var new_line = fold_line(board, line);
156                 Object.keys(new_line).forEach(function(key){
157                     //mutate reference while building up board
158                     new_board = set_tile(new_board, key, new_line[key]);
159                 });
160             });
161             return new_board;
162         }
163 
164         var tile_counter = 0;
165         function new_tile(initial){
166             return {
167                 id: tile_counter++,
168                 values: [initial]
169             };
170         }
171 
172         function set_tile(board, where, tile){
173             //do not destory the old board
174             var new_board = {};
175             Object.keys(board).forEach(function(key, i){
176                 //copy by reference for structual sharing
177                 new_board[key] = (key == where) ? tile : board[key];
178             });
179             return new_board;
180         }
181 
182         var left = fold_order(["a","b","c","d"], ["1","2","3","4"], false);
183         var right = fold_order(["a","b","c","d"], ["4","3","2","1"], false);
184         var up = fold_order(["1","2","3","4"], ["a","b","c","d"], true);
185         var down = fold_order( ["1","2","3","4"], ["d","c","b","a"], true);
186 
187         var GameBoard = React.createClass({
188             getInitialState: function(){
189                 return this.addTile(this.addTile(initial_board));
190             },
191             keyHandler:function(e){
192                 var directions = {
193                     37: left,
194                     38: up,
195                     39: right,
196                     40: down
197                 };
198                 if(directions[e.keyCode]
199                 && this.setBoard(fold_board(this.state, directions[e.keyCode]))
200                 && Math.floor(Math.random() * 30, 0) > 0){
201                     setTimeout(function(){
202                          this.setBoard(this.addTile(this.state));
203                     }.bind(this), 100);
204                 }
205             },
206             setBoard:function(new_board){
207                 if(!same_board(this.state, new_board)){
208                     this.setState(new_board);
209                     return true;
210                 }
211                 return false;
212             },
213             addTile:function(board){
214                 var location = available_spaces(board).sort(function() {
215                   return .5 - Math.random();
216                 }).pop();
217                 if(location){
218                     var two_or_four = Math.floor(Math.random() * 2, 0) ? 2 : 4;
219                     return set_tile(board, location, new_tile(two_or_four));
220                 }
221                 return board;
222             },
223             newGame:function(){
224                 this.setState(this.getInitialState());
225             },
226             componentDidMount:function(){
227                 window.addEventListener("keydown", this.keyHandler, false);
228             },
229             render:function(){
230                 var status = !can_move(this.state)?" - Game Over!":"";
231                 return <div className="app">
232                     <span className="score">
233                         Score: {score_board(this.state)}{status}
234                     </span>
235                     <Tiles board={this.state}/>
236                     <button onClick={this.newGame}>New Game</button>
237                 </div>
238             }
239         });
240 
241         var Tiles = React.createClass({
242             render: function(){
243                 var board = this.props.board;
244                 //sort board keys first to stop re-ordering of DOM elements
245                 var tiles = used_spaces(board).sort(function(a, b) {
246                     return board[a].id - board[b].id;
247                 });
248                 return <div className="board">{
249                     tiles.map(function(key){
250                         var tile = board[key];
251                         var val = tile_value(tile);
252                         return <span key={tile.id} className={key + " value" + val}>
253                                 {val}
254                                </span>;
255                 })}</div>
256             }
257         });
258 
259         React.render(<GameBoard />, document.body);
260     </script>
261 </body>
262 </html>

2.结果

技术分享

用 React 编写2048游戏

标签:

原文地址:http://www.cnblogs.com/shamgod/p/5076930.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!