用Dart写的黑白棋游戏
2013年11月,Dart语言1.0稳定版SDK发布,普天同庆。从此,网页编程不再纠结了。
在我看来,Dart语法简直就是C#的升级版,太像了。之所以喜欢Ruby的一个重要理由是支持mixin功能,而Dart也引入了mixin特性。
最棒的是Google提供了集成开发环境——Dart Editor和Dartium,有非常强大的编辑和调试功能,既能编写网页程序,也能编写服务器端程序。
把网站上的主要文档看完一遍后,再把SDK下载解压,就能用Dart编程了。
第一个程序写什么呢?做了一个黑白棋游戏。
直接上代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Reversi</title> <link rel="stylesheet" href="reversi.css"> </head> <body> <h1>黑白棋</h1> <p id="score"><span class="black piece"></span> <span id="blackScore">2</span> <span class="spacer"></span><span class="white piece"></span> <span id="whiteScore">2</span></p> <table id="board"> </table> <p id="message"></p> <script type="application/dart" src="reversi_ui.dart"></script> <script src="packages/browser/dart.js"></script> </body> </html>
棋盘界面的生成和用户事件处理:
import 'dart:html'; import 'reversi_game.dart'; var chess = new ChessBoard(); var cells = new Map<DivElement,BoardCell>(); var blackScore = querySelector("#blackScore"); var whiteScore = querySelector("#whiteScore"); var message = querySelector("#message"); void main() { TableElement board = querySelector("#board"); for(int i=0;i<ChessBoard.BoardSize;i++){ var row = board.addRow(); for(int j=0;j<ChessBoard.BoardSize;j++){ var cell = row.addCell(); var piece = new DivElement(); cell.children.add(piece); piece.onClick.listen(placePiece); cells[piece] = chess.cells[i][j]; } } updateCells(); } void updateCells(){ cells.forEach((piece, boardCell){ piece.classes.clear(); if(!boardCell.isEmpty){ piece.classes.add(boardCell.piece); } }); blackScore.text = chess.blackScore.toString(); whiteScore.text = chess.whiteScore.toString(); message.text = chess.message; } void placePiece(MouseEvent event) { var piece = event.target; var boardCell = cells[piece]; if(chess.placePiece(boardCell)){ updateCells(); piece.classes.add('last'); }else if(boardCell.isEmpty){ message.text = chess.message; piece.classes.add('last'); } }
游戏的逻辑部分:
class BoardCell { int row; int col; var piece; BoardCell(this.row, this.col); bool get isEmpty{ return piece == null; } } class CellPos { int row; int col; CellPos(this.row, this.col); } class ChessBoard { static const BoardSize = 8; static const white = 'white'; static const black = 'black'; var currentTurn = black; List<List<BoardCell>> cells; int blackScore = 2; int whiteScore = 2; bool gameOver = false; String tip; ChessBoard(){ cells = new List<List<BoardCell>>(); for(int i=0;i<BoardSize;i++){ var row = new List<BoardCell>(); for(int j=0;j<BoardSize;j++){ var cell = new BoardCell(i, j); row.add(cell); } cells.add(row); } cells[3][3].piece = white; cells[3][4].piece = black; cells[4][3].piece = black; cells[4][4].piece = white; tip = "游戏开始"; } switchTurn(){ currentTurn = getReverse(currentTurn); } String getReverse(String piece){ if(piece == black){ return white; }else if(piece == white){ return black; }else{ return null; } } bool placePiece(BoardCell cell){ if(cell.isEmpty){ var success = reverseOpponents(cell, currentTurn); if(success){ cell.piece = currentTurn; calculateScore(); switchTurn(); if(canPlacePiece(currentTurn)){ tip = null; }else{ switchTurn(); if(canPlacePiece(currentTurn)){ tip = "${players[getReverse(currentTurn)]}无棋"; }else{ gameOver = true; } } return true; }else{ tip = "落子无效"; } } return false; } static List<CellPos> w(int row, int col){ List<CellPos> adjacentCells = []; for(int j = col - 1; j >= 0; j--){ adjacentCells.add(new CellPos(row, j)); } return adjacentCells; } static List<CellPos> e(int row, int col){ List<CellPos> adjacentCells = []; for(int j = col + 1; j < BoardSize; j++){ adjacentCells.add(new CellPos(row, j)); } return adjacentCells; } static List<CellPos> n(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row - 1; i >= 0; i--){ adjacentCells.add(new CellPos(i, col)); } return adjacentCells; } static List<CellPos> s(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row + 1; i < BoardSize; i++){ adjacentCells.add(new CellPos(i, col)); } return adjacentCells; } static List<CellPos> ne(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row - 1, j = col + 1; i >= 0 && j < BoardSize; i--, j++){ adjacentCells.add(new CellPos(i, j)); } return adjacentCells; } static List<CellPos> se(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row + 1, j = col + 1; i < BoardSize && j < BoardSize; i++, j++){ adjacentCells.add(new CellPos(i, j)); } return adjacentCells; } static List<CellPos> sw(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row + 1, j = col - 1; i < BoardSize && j >= 0; i++, j--){ adjacentCells.add(new CellPos(i, j)); } return adjacentCells; } static List<CellPos> nw(int row, int col){ List<CellPos> adjacentCells = []; for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){ adjacentCells.add(new CellPos(i, j)); } return adjacentCells; } var directions = [n, ne, e, se, s, sw, w, nw]; List<BoardCell> findReverible(BoardCell cell, String piece){ List<BoardCell> allOpponents = []; for(var direction in directions){ List<BoardCell> opponents = []; for(var cellPos in direction(cell.row, cell.col)){ var nextCell = cells[cellPos.row][cellPos.col]; if(nextCell.piece == getReverse(piece)){ opponents.add(nextCell); }else{ if(nextCell.piece == piece){ allOpponents.addAll(opponents); } break; } } } return allOpponents; } bool reverseOpponents(BoardCell cell, String piece){ List<BoardCell> allOpponents = findReverible(cell, piece); if(allOpponents.length > 0){ allOpponents.forEach((opp){opp.piece=piece;}); return true; }else{ return false; } } bool canPlacePiece(String piece){ for(int i=0;i<BoardSize;i++){ for(int j=0;j<BoardSize;j++){ var cell = cells[i][j]; if(cell.isEmpty && findReverible(cell, piece).length > 0){ return true; } } } return false; } calculateScore(){ whiteScore = 0; blackScore = 0; for(int i=0;i<BoardSize;i++){ for(int j=0;j<BoardSize;j++){ var piece = cells[i][j].piece; if(piece == white){ whiteScore++; }else if(piece == black){ blackScore++; } } } } var players = {black:"黑方", white:"白方"}; String get message { if(gameOver){ if(whiteScore > blackScore){ return "白方胜!"; }else if(whiteScore < blackScore){ return "黑方胜!"; }else{ return "双方平局!"; } } if(tip == null){ return "${players[currentTurn]}走棋"; }else{ return "$tip,${players[currentTurn]}走棋"; } } }
开发完成后,用dart2js转成javascript,然后拷贝到网站服务器上,就可以在线玩了。
以上只是一个简单的界面和走棋逻辑,接下来要做的是加入人工智能,可以人机对战;使用WebSocket通信,实现联网对战。
这部分的代码就不贴上来了。
点此打开试玩
联网对弈功能需要运行游戏服务器程序,目前只能在局域网使用。
想要完整源代码的朋友可以发邮件给我:251024877@qq.com。不要在评论中留下email,这种的我不会回的。