用 React 编写2048游戏
2015-12-25 20:42
651 查看
1.代码
2.结果
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>万能的React</title> <style> .app{ margin:10px; font-family: arial; } .board{ display:block; position:relative; margin:10px 0px 10px 0px; border:1px solid #ccc; width:215px; height:215px; padding:5px; } .board span{ font-family: arial; letter-spacing: -1px; display:block; width:50px; height:36px; position:absolute; text-align:center; color:white; font-weight:bold; font-size:20px; padding-top:14px; background-color:#ebe76f; border-radius: 5px; transition: all 100ms linear; } .a1, .b1, .c1, .d1{ left:5px; } .a2, .b2, .c2, .d2{ left:60px; } .a3, .b3, .c3, .d3{ left:115px; } .a4, .b4, .c4, .d4{ left:170px; } .a1, .a2, .a3, .a4{ top:5px; } .b1, .b2, .b3, .b4{ top:60px; } .c1, .c2, .c3, .c4{ top:115px; } .d1, .d2, .d3, .d4{ top:170px; } span.value2{ background-color:#ebb26f; } span.value4{ background-color:#ea6feb; } span.value8{ background-color:#eb6fa3; } span.value16{ background-color:#7a6feb; } span.value32{ background-color:#af6feb; } span.value64{ background-color:#6febcf; } span.value128{ background-color:#6fbeeb; } span.value256{ background-color:#afeb6f; } span.value512{ background-color:#7aeb6f; } span.value1024{ background-color:#e4eb6f; } </style> </head> <body> <script src="./react-0.13.2/react-0.13.2/build/react.js"></script> <script src="./react-0.13.2/react-0.13.2/build/JSXTransformer.js"></script> <script type="text/jsx"> var initial_board = { a1:null,a2:null,a3:null,a4:null, b1:null,b2:null,b3:null,b4:null, c1:null,c2:null,c3:null,c4:null, d1:null,d2:null,d3:null,d4:null }; function available_spaces(board){ return Object.keys(board).filter(function(key){ return board[key] == null }); } function used_spaces(board){ return Object.keys(board).filter(function(key){ return board[key] !== null }); } function score_board(board){ return used_spaces(board).map(function(key){ return (board[key].values.reduce(function(a, b) { return a + b; //sum tile values })) - board[key].values[0]; //don't count initial value }).reduce(function(a,b){return a+b}, 0); } function tile_value(tile){ return tile ? tile.values[tile.values.length-1] : null; } function can_move(board){ var new_board = [up,down,left,right].reduce(function(b, direction){ return fold_board(b, direction); }, board); return available_spaces(new_board).length > 0 } function same_board(board1, board2){ return Object.keys(board1).reduce(function(ret, key){ return ret && board1[key] == board2[key]; }, true); } function fold_line(board, line){ var tiles = line.map(function(key){ return board[key]; }).filter(function(tile){ return tile !== null }); var new_tiles = []; if(tiles){ //must loop so we can skip next if matched for(var i=0; i < tiles.length; i++){ var tile = tiles[i]; if(tile){ var val = tile_value(tile); var next_tile = tiles[i+1]; if(next_tile && val == tile_value(next_tile)){ //skip next tile; i++; new_tiles.push({ id: next_tile.id, //keep id values: tile.values.concat([val * 2]) }); } else{ new_tiles.push(tile); } } } } var new_line = {}; line.forEach(function(key, i){ new_line[key] = new_tiles[i] || null; }); return new_line; } function fold_order(xs, ys, reverse_keys){ return xs.map(function(x){ return ys.map(function(y){ var key = [x,y]; if(reverse_keys){ return key.reverse().join(""); } return key.join(""); }); }); } function fold_board(board, lines){ //copy reference var new_board = board; lines.forEach(function(line){ var new_line = fold_line(board, line); Object.keys(new_line).forEach(function(key){ //mutate reference while building up board new_board = set_tile(new_board, key, new_line[key]); }); }); return new_board; } var tile_counter = 0; function new_tile(initial){ return { id: tile_counter++, values: [initial] }; } function set_tile(board, where, tile){ //do not destory the old board var new_board = {}; Object.keys(board).forEach(function(key, i){ //copy by reference for structual sharing new_board[key] = (key == where) ? tile : board[key]; }); return new_board; } var left = fold_order(["a","b","c","d"], ["1","2","3","4"], false); var right = fold_order(["a","b","c","d"], ["4","3","2","1"], false); var up = fold_order(["1","2","3","4"], ["a","b","c","d"], true); var down = fold_order( ["1","2","3","4"], ["d","c","b","a"], true); var GameBoard = React.createClass({ getInitialState: function(){ return this.addTile(this.addTile(initial_board)); }, keyHandler:function(e){ var directions = { 37: left, 38: up, 39: right, 40: down }; if(directions[e.keyCode] && this.setBoard(fold_board(this.state, directions[e.keyCode])) && Math.floor(Math.random() * 30, 0) > 0){ setTimeout(function(){ this.setBoard(this.addTile(this.state)); }.bind(this), 100); } }, setBoard:function(new_board){ if(!same_board(this.state, new_board)){ this.setState(new_board); return true; } return false; }, addTile:function(board){ var location = available_spaces(board).sort(function() { return .5 - Math.random(); }).pop(); if(location){ var two_or_four = Math.floor(Math.random() * 2, 0) ? 2 : 4; return set_tile(board, location, new_tile(two_or_four)); } return board; }, newGame:function(){ this.setState(this.getInitialState()); }, componentDidMount:function(){ window.addEventListener("keydown", this.keyHandler, false); }, render:function(){ var status = !can_move(this.state)?" - Game Over!":""; return <div className="app"> <span className="score"> Score: {score_board(this.state)}{status} </span> <Tiles board={this.state}/> <button onClick={this.newGame}>New Game</button> </div> } }); var Tiles = React.createClass({ render: function(){ var board = this.props.board; //sort board keys first to stop re-ordering of DOM elements var tiles = used_spaces(board).sort(function(a, b) { return board[a].id - board[b].id; }); return <div className="board">{ tiles.map(function(key){ var tile = board[key]; var val = tile_value(tile); return <span key={tile.id} className={key + " value" + val}> {val} </span>; })}</div> } }); React.render(<GameBoard />, document.body); </script> </body> </html>
2.结果
相关文章推荐
- Mac下安装React Native
- 在iOS6机子上运行 React-Native Demo, 自己编译 JavaScriptCore 源码,支持 iOS5.1 ,iOS 6
- react-native for android windows开发环境搭建详细记录
- ReactiveCocoa学习(一)
- 【Codeforces Round 336 (Div 2) C】【贪心 DP思维】Chain Reaction 每个灯塔位置为a[]破坏b[]范围所有灯塔 设置一个灯塔使得最多灯塔被保留
- ReactiveCocoa源码拆分解析(二)
- Codeforces Round #336 (Div. 2) C. Chain Reaction set维护dp
- 利用CocoaPods集成ReactiveCocoa
- Codeforces Round #336 (Div. 1) 607A Chain Reaction 简单dp
- React 学习一 运行
- React测试Mixin
- windows下react-native android环境安装
- React组件测试(模拟组件、函数和事件)
- Codeforces 607A:Chain Reaction 二分+递推
- 用React.addons.TestUtils、Jasmine进行单元测试
- 基于React实现项目中状态型变量的数据驱动可视化
- react 写的省市三级联动
- ReactiveCocoa
- 手把手教你在Windows下搭建React Native Android开发环境
- 手把手教你在Windows下搭建React Native Android开发环境