您的位置:首页 > Web前端 > React

用 React 编写2048游戏

2015-12-25 20:42 651 查看
1.代码

<!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.结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: