提交 3ae2ab1f 编写于 作者: T tuzhaofeng

init

上级 08203374
# Contributing
Changes and improvements are more than welcome! Feel free to fork and open a pull request.
Please follow the house rules to have a bigger chance of your contribution being merged.
## House rules
### How to make changes
- To make changes, create a new branch based on `master` (do not create one from `gh-pages` unless strictly necessary) and make them there, then create a Pull Request to master.
`gh-pages` is different from master in that it contains sharing features, analytics and other things that have no direct bearing with the game. `master` is the "pure" version of the game.
- If you want to modify the CSS, please edit the SCSS files present in `style/`: `main.scss` and others. Don't edit the `main.css`, because it's supposed to be generated.
In order to compile your SCSS modifications, you need to use the `sass` gem (install it by running `gem install sass` once Ruby is installed).
To run SASS, simply use the following command:
`sass --unix-newlines --watch style/main.scss`
SASS will automatically recompile your css when changed.
- `Rakefile` contains some tasks that help during development. Feel free to add useful tasks if needed.
- Please use 2-space indentation when editing the JavaScript. A `.jshintrc` file is present, which will help your code to follow the guidelines if you install and run `jshint`.
- Please test your modification thoroughly before submitting your Pull Request.
### Changes that might not be accepted
We have to be conservative with the core game. This means that some modifications won't be merged, or will have to be evaluated carefully before being merged:
- Undo/redo features
- Save/reload features
- Changes to how the tiles look or their contents
- Changes to the layout
- Changes to the grid size
### Changes that are welcome
- Bug fixes
- Compatibility improvements
- "Under the hood" enhancements
- Small changes that don't have an impact on the core gameplay
The MIT License (MIT)
Copyright (c) 2014 Gabriele Cirulli
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# test
# 2048
A small clone of [1024](https://play.google.com/store/apps/details?id=com.veewo.a1024), based on [Saming's 2048](http://saming.fr/p/2048/) (also a clone).
# Gomoku 五子棋游戏
使用 Typescript 编写的带有简单 AI 的五子棋小游戏 (无禁手)。
Support Cloud IDE
> [Typescript](http://www.typescriptlang.org/) 是微软的一个[开源项目](https://github.com/Microsoft/TypeScript),在 Javascript 现有语法的基础上提供了与 C++、Java 类似的正宗的面向对象与静态类型支持。使用 Visual Studio 或 Visual Studio Code 能够在编译期对代码进行检查,执行安全的重构操作(重命名)。
Made just for fun. [Play it here!](http://gabrielecirulli.github.io/2048/)
The official app can also be found on the [Play Store](https://play.google.com/store/apps/details?id=com.gabrielecirulli.app2048) and [App Store!](https://itunes.apple.com/us/app/2048-by-gabriele-cirulli/id868076805)
*游戏实现了*
### Contributions
1. 基于 HTML Canvas 元素的界面
2. 五子棋 AI
3. 主题切换、查看步数
[Anna Harren](https://github.com/iirelu/) and [sigod](https://github.com/sigod) are maintainers for this repository.
## 运行
* [在线玩](https://wangdongdongc.github.io/Gomoku/index.html)
* 下载源代码,在浏览器中打开 `index.html`
Other notable contributors:
## 编译
> Typescript(.ts) 源文件需要编译成 Javascript(.js) 才能在浏览器中运行
- [TimPetricola](https://github.com/TimPetricola) added best score storage
- [chrisprice](https://github.com/chrisprice) added custom code for swipe handling on mobile
- [marcingajda](https://github.com/marcingajda) made swipes work on Windows Phone
- [mgarciaisaia](https://github.com/mgarciaisaia) added support for Android 2.3
1. 安装 [npm](https://www.npmjs.com/) 包管理器
2. 进入项目根目录执行 `npm install` 以安装 Typescript
3. 安装完成后运行 `npm run build` 以启动编译 (或 `./node_modules/.bin/tsc --sourcemap`, 编译选项见 `tsconfig.json`)
Many thanks to [rayhaanj](https://github.com/rayhaanj), [Mechazawa](https://github.com/Mechazawa), [grant](https://github.com/grant), [remram44](https://github.com/remram44) and [ghoullier](https://github.com/ghoullier) for the many other good contributions.
![image](http://raw.github.com/wangdongdongc/Gomoku/master/images/github/demo.png)
### Screenshot
## MVC 设计模式
游戏使用 [MVC](https://zh.wikipedia.org/wiki/MVC) (model-view-controller) 的模式组织程序
<p align="center">
<img src="https://cloud.githubusercontent.com/assets/1175750/8614312/280e5dc2-26f1-11e5-9f1f-5891c3ca8b26.png" alt="Screenshot"/>
</p>
对应的源码如下
That screenshot is fake, by the way. I never reached 2048 :smile:
### *Model*
```
src/GomokuGame.ts 游戏规则实现
src/Models/GomokuDB.ts 历史记录存取
```
### *View*
实现 UI
```
src/Views/ComokuView.ts 游戏视图
src/Views/MenuView.ts 菜单视图
src/Views/DialogView.ts 对话框视图
```
UI 基于 HTML5 [Canvas](https://zh.wikipedia.org/wiki/Canvas_(HTML%E5%85%83%E7%B4%A0)) 实现。Canvas 是 HTML5 的一个元素,它在页面上嵌入一个画布,并使用 Javascript 在上面绘制线条,形状,图像。
## Contributing
Changes and improvements are more than welcome! Feel free to fork and open a pull request. Please make your changes in a specific branch and request to pull into `master`! If you can, please make sure the game fully works before sending the PR, as that will help speed up the process.
![image](http://raw.github.com/wangdongdongc/Gomoku/master/images/github/view-demo.png)
You can find the same information in the [contributing guide.](https://github.com/gabrielecirulli/2048/blob/master/CONTRIBUTING.md)
### *Controller*
```
src/GomokuViewController.ts
```
> 这个控制器同时管理了游戏视图和菜单栏视图,两个视图上发生的事件都交给这一个控制器处理
## License
2048 is licensed under the [MIT license.](https://github.com/gabrielecirulli/2048/blob/master/LICENSE.txt)
View 接受用户的在 UI 上进行的操作(鼠标点击,鼠标滑动),将动作发送给 Controller,Controller 处理动作。
## Donations
I made this in my spare time, and it's hosted on GitHub (which means I don't have any hosting costs), but if you enjoyed the game and feel like buying me coffee, you can donate at my BTC address: `1Ec6onfsQmoP9kkL3zkpB6c5sA4PVcXU2i`. Thank you very much!
例如:View 发现用户点击了 Canvas 元素的xx位置,告诉 Controller ,Controller 告诉 Model 玩家在棋盘中xx处落子,Model 处理落子,发现玩家获胜,告诉 Controller 玩家已获胜,Controller 最后控制 View 显示 “已获胜” 的字样。
## AI
游戏自带 AI,能够与玩家进行对战
```
src/AIs/AIScore.ts 棋型估分
src/AIs/TestAI_2.ts AI
```
### AI 如何决策
AI 能够看到当前棋盘的棋子分布,就像玩家一样
AI 的决策包含防守和进攻
1. 防守:当玩家摆出能够危险的棋局时,在危险位置上落子防御。危险的棋局非常复杂,这里仅考虑一些基本的类型。例如:四连、两个三连同时出现。
2. 进攻:若无危险棋局,一般选择进攻。正如 AI 能够判断玩家可能摆出危险的棋局,AI 也能判断是否可以下出这些攻击力强的棋局。
### AI 如何判断棋局
AI 对不同的棋局进行估分,在不同的位置落子能够产生不同的棋局,选取分数最高的棋局落子。
AI 将尝试在棋盘的每一个空位置落子,然后检查上下左右与主对角线副对角线方向有多少个连子,连子的两边是否被堵住,连子中是否有间隔,这这些信息交给一个分值判断函数。
e.g.
```javascript
//这是一个进行分值判断的函数,它根据连子的个数(line),两侧是否被堵住(block1, block2),给出分数
//note: 这里分数被表示成了一些很形象的变量(oooo)
scoreOfStyle(line: number, block1: boolean, block2: boolean) {
if (line == 5) return AIScore.ooooo
if (block1 && block2) return 0
switch (line) {
case 4: return (block1 || block2) ? AIScore.Ioooo : AIScore.oooo
case 3: return (block1 || block2) ? AIScore.Iooo : AIScore.ooo
case 2: return (block1 || block2) ? AIScore.Ioo : AIScore.oo
case 1: return 0
}
}
```
这种判断棋型的方法能够判断多个 ooo 交叉的情况。因为不同的方向的棋局所产生的分数是可以叠加的。例如:检查水平方向时,发现了一个 ooo,检查斜方向时,又发现了 |oooo,这样的棋局显然可以获胜,若没有更直接的获胜棋局,AI 应该立刻在这种位置落子。
## 一些抽象
`src/Shapes/` 下存放用于在 Canvas 绘制特定形状的类(如:Circle、Rectangle),这些类包装了 Canvas 的 API,防止 View 中出现大量的 Canvas API。
`src/Models/` 下存放供 Model 使用的一些数据结构,用于简化 Model 的代码。
`src/Themes/` 下包含了几种棋盘棋子的样式类,用于主题切换
\ No newline at end of file
require "date"
namespace :appcache do
desc "update the date in the appcache file (in the gh-pages branch)"
task :update do
appcache = File.read("cache.appcache")
updated = "# Updated: #{DateTime.now}"
File.write("cache.appcache", appcache.sub(/^# Updated:.*$/, updated))
end
end
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>2048 OK</title>
<html lang="zh-CN">
<head>
<title>Gomoku Game</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--Bootstrap CSS-->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<!--jQuery-->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<!--Bootstrap JS-->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
</head>
<link href="style/main.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="favicon.ico">
<link rel="apple-touch-icon" href="meta/apple-touch-icon.png">
<link rel="apple-touch-startup-image" href="meta/apple-touch-startup-image-640x1096.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)"> <!-- iPhone 5+ -->
<link rel="apple-touch-startup-image" href="meta/apple-touch-startup-image-640x920.png" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)"> <!-- iPhone, retina -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div class="container">
<div class="heading">
<h1 class="title">2048</h1>
<div class="scores-container">
<div class="score-container">0</div>
<div class="best-container">0</div>
</div>
</div>
<div class="above-game">
<p class="game-intro">Join the numbers and get to the <strong>2048 tile!</strong></p>
<a class="restart-button">New Game</a>
</div>
<div class="game-container">
<div class="game-message">
<p></p>
<div class="lower">
<a class="keep-playing-button">Keep going</a>
<a class="retry-button">Try again</a>
<body>
<div class="container">
<!--对话框视图-->
<div class="modal fade" id="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header" id="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">历史记录</h4>
</div>
<div class="modal-body" id="modal-body">
<ul class="list-group" id="history-list">
</ul>
</div>
<div class="modal-footer" id="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
</div>
<!-- /.modal -->
<div class="grid-container">
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<canvas id="game" class="center-block"></canvas> <!--五子棋视图-->
<canvas id="menu" class="center-block"></canvas> <!--菜单视图-->
</div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
</div>
<div class="tile-container">
</div>
</div>
</body>
<p class="game-explanation">
<strong class="important">How to play:</strong> Use your <strong>arrow keys</strong> to move the tiles. When two tiles with the same number touch, they <strong>merge into one!</strong>
</p>
<hr>
<p>
<strong class="important">Note:</strong> This site is the official version of 2048. You can play it on your phone via <a href="http://git.io/2048">http://git.io/2048.</a> All other apps or sites are derivatives or fakes, and should be used with caution.
</p>
<hr>
<p>
Created by <a href="http://gabrielecirulli.com" target="_blank">Gabriele Cirulli.</a> Based on <a href="https://itunes.apple.com/us/app/1024!/id823499224" target="_blank">1024 by Veewo Studio</a> and conceptually similar to <a href="http://asherv.com/threes/" target="_blank">Threes by Asher Vollmer.</a>
</p>
</div>
<script src="js/bind_polyfill.js"></script>
<script src="js/classlist_polyfill.js"></script>
<script src="js/animframe_polyfill.js"></script>
<script src="js/keyboard_input_manager.js"></script>
<script src="js/html_actuator.js"></script>
<script src="js/grid.js"></script>
<script src="js/tile.js"></script>
<script src="js/local_storage_manager.js"></script>
<script src="js/game_manager.js"></script>
<script src="js/application.js"></script>
</body>
</html>
<!--下列JS文件对应的Typescript源码均位于src/目录下-->
<script src="out/Shapes/Shape.js"></script>
<script src="out/Shapes/Circle.js"></script>
<script src="out/Shapes/Rectangle.js"></script>
<script src="out/Shapes/Line.js"></script>
<script src="out/Shapes/ChessboardShape.js"></script>
<script src="out/Shapes/ChessShape.js"></script>
<script src="out/Shapes/TextShape.js"></script>
<script src="out/Shapes/TwoHalfCircle.js"></script>
<script src="out/Shapes/TextCircle.js"></script>
<script src="out/Themes/Theme.js"></script>
<script src="out/Themes/DefaultTheme.js"></script>
<script src="out/Themes/VividTheme.js"></script>
<script src="out/Views/CanvasView.js"></script>
<script src="out/Views/GomokuView.js"></script>
<script src="out/Views/MenuView.js"></script>
<script src="out/Views/DialogView.js"></script>
<script src="out/Models/Player.js"></script>
<script src="out/Models/Chess.js"></script>
<script src="out/Models/Chessboard.js"></script>
<script src="out/Models/GomokuDB.js"></script>
<script src="out/AIs/GomokuAI.js"></script>
<script src="out/AIs/AIScore.js"></script>
<script src="out/AIs/Matrix.js"></script>
<!--<script src="out/AIs/TestAI_1.js"></script> -->
<script src="out/AIs/TestAI_2.js"></script>
<script src="out/GomokuGame.js"></script>
<script src="out/GomokuViewController.js"></script>
<script type="text/javascript">
new GomokuViewController(true);
</script>
</html>
\ No newline at end of file
(function () {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
},
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
}());
// Wait till the browser is ready to render the game (avoids glitches)
window.requestAnimationFrame(function () {
new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
});
Function.prototype.bind = Function.prototype.bind || function (target) {
var self = this;
return function (args) {
if (!(args instanceof Array)) {
args = [args];
}
self.apply(target, args);
};
};
(function () {
if (typeof window.Element === "undefined" ||
"classList" in document.documentElement) {
return;
}
var prototype = Array.prototype,
push = prototype.push,
splice = prototype.splice,
join = prototype.join;
function DOMTokenList(el) {
this.el = el;
// The className needs to be trimmed and split on whitespace
// to retrieve a list of classes.
var classes = el.className.replace(/^\s+|\s+$/g, '').split(/\s+/);
for (var i = 0; i < classes.length; i++) {
push.call(this, classes[i]);
}
}
DOMTokenList.prototype = {
add: function (token) {
if (this.contains(token)) return;
push.call(this, token);
this.el.className = this.toString();
},
contains: function (token) {
return this.el.className.indexOf(token) != -1;
},
item: function (index) {
return this[index] || null;
},
remove: function (token) {
if (!this.contains(token)) return;
for (var i = 0; i < this.length; i++) {
if (this[i] == token) break;
}
splice.call(this, i, 1);
this.el.className = this.toString();
},
toString: function () {
return join.call(this, ' ');
},
toggle: function (token) {
if (!this.contains(token)) {
this.add(token);
} else {
this.remove(token);
}
return this.contains(token);
}
};
window.DOMTokenList = DOMTokenList;
function defineElementGetter(obj, prop, getter) {
if (Object.defineProperty) {
Object.defineProperty(obj, prop, {
get: getter
});
} else {
obj.__defineGetter__(prop, getter);
}
}
defineElementGetter(HTMLElement.prototype, 'classList', function () {
return new DOMTokenList(this);
});
})();
function GameManager(size, InputManager, Actuator, StorageManager) {
this.size = size; // Size of the grid
this.inputManager = new InputManager;
this.storageManager = new StorageManager;
this.actuator = new Actuator;
this.startTiles = 2;
this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("restart", this.restart.bind(this));
this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
this.setup();
}
// Restart the game
GameManager.prototype.restart = function () {
this.storageManager.clearGameState();
this.actuator.continueGame(); // Clear the game won/lost message
this.setup();
};
// Keep playing after winning (allows going over 2048)
GameManager.prototype.keepPlaying = function () {
this.keepPlaying = true;
this.actuator.continueGame(); // Clear the game won/lost message
};
// Return true if the game is lost, or has won and the user hasn't kept playing
GameManager.prototype.isGameTerminated = function () {
return this.over || (this.won && !this.keepPlaying);
};
// Set up the game
GameManager.prototype.setup = function () {
var previousState = this.storageManager.getGameState();
// Reload the game from a previous game if present
if (previousState) {
this.grid = new Grid(previousState.grid.size,
previousState.grid.cells); // Reload grid
this.score = previousState.score;
this.over = previousState.over;
this.won = previousState.won;
this.keepPlaying = previousState.keepPlaying;
} else {
this.grid = new Grid(this.size);
this.score = 0;
this.over = false;
this.won = false;
this.keepPlaying = false;
// Add the initial tiles
this.addStartTiles();
}
// Update the actuator
this.actuate();
};
// Set up the initial tiles to start the game with
GameManager.prototype.addStartTiles = function () {
for (var i = 0; i < this.startTiles; i++) {
this.addRandomTile();
}
};
// Adds a tile in a random position
GameManager.prototype.addRandomTile = function () {
if (this.grid.cellsAvailable()) {
var value = Math.random() < 0.9 ? 2 : 4;
var tile = new Tile(this.grid.randomAvailableCell(), value);
this.grid.insertTile(tile);
}
};
// Sends the updated grid to the actuator
GameManager.prototype.actuate = function () {
if (this.storageManager.getBestScore() < this.score) {
this.storageManager.setBestScore(this.score);
}
// Clear the state when the game is over (game over only, not win)
if (this.over) {
this.storageManager.clearGameState();
} else {
this.storageManager.setGameState(this.serialize());
}
this.actuator.actuate(this.grid, {
score: this.score,
over: this.over,
won: this.won,
bestScore: this.storageManager.getBestScore(),
terminated: this.isGameTerminated()
});
};
// Represent the current game as an object
GameManager.prototype.serialize = function () {
return {
grid: this.grid.serialize(),
score: this.score,
over: this.over,
won: this.won,
keepPlaying: this.keepPlaying
};
};
// Save all tile positions and remove merger info
GameManager.prototype.prepareTiles = function () {
this.grid.eachCell(function (x, y, tile) {
if (tile) {
tile.mergedFrom = null;
tile.savePosition();
}
});
};
// Move a tile and its representation
GameManager.prototype.moveTile = function (tile, cell) {
this.grid.cells[tile.x][tile.y] = null;
this.grid.cells[cell.x][cell.y] = tile;
tile.updatePosition(cell);
};
// Move tiles on the grid in the specified direction
GameManager.prototype.move = function (direction) {
// 0: up, 1: right, 2: down, 3: left
var self = this;
if (this.isGameTerminated()) return; // Don't do anything if the game's over
var cell, tile;
var vector = this.getVector(direction);
var traversals = this.buildTraversals(vector);
var moved = false;
// Save the current tile positions and remove merger information
this.prepareTiles();
// Traverse the grid in the right direction and move tiles
traversals.x.forEach(function (x) {
traversals.y.forEach(function (y) {
cell = { x: x, y: y };
tile = self.grid.cellContent(cell);
if (tile) {
var positions = self.findFarthestPosition(cell, vector);
var next = self.grid.cellContent(positions.next);
// Only one merger per row traversal?
if (next && next.value === tile.value && !next.mergedFrom) {
var merged = new Tile(positions.next, tile.value * 2);
merged.mergedFrom = [tile, next];
self.grid.insertTile(merged);
self.grid.removeTile(tile);
// Converge the two tiles' positions
tile.updatePosition(positions.next);
// Update the score
self.score += merged.value;
// The mighty 2048 tile
if (merged.value === 2048) self.won = true;
} else {
self.moveTile(tile, positions.farthest);
}
if (!self.positionsEqual(cell, tile)) {
moved = true; // The tile moved from its original cell!
}
}
});
});
if (moved) {
this.addRandomTile();
if (!this.movesAvailable()) {
this.over = true; // Game over!
}
this.actuate();
}
};
// Get the vector representing the chosen direction
GameManager.prototype.getVector = function (direction) {
// Vectors representing tile movement
var map = {
0: { x: 0, y: -1 }, // Up
1: { x: 1, y: 0 }, // Right
2: { x: 0, y: 1 }, // Down
3: { x: -1, y: 0 } // Left
};
return map[direction];
};
// Build a list of positions to traverse in the right order
GameManager.prototype.buildTraversals = function (vector) {
var traversals = { x: [], y: [] };
for (var pos = 0; pos < this.size; pos++) {
traversals.x.push(pos);
traversals.y.push(pos);
}
// Always traverse from the farthest cell in the chosen direction
if (vector.x === 1) traversals.x = traversals.x.reverse();
if (vector.y === 1) traversals.y = traversals.y.reverse();
return traversals;
};
GameManager.prototype.findFarthestPosition = function (cell, vector) {
var previous;
// Progress towards the vector direction until an obstacle is found
do {
previous = cell;
cell = { x: previous.x + vector.x, y: previous.y + vector.y };
} while (this.grid.withinBounds(cell) &&
this.grid.cellAvailable(cell));
return {
farthest: previous,
next: cell // Used to check if a merge is required
};
};
GameManager.prototype.movesAvailable = function () {
return this.grid.cellsAvailable() || this.tileMatchesAvailable();
};
// Check for available matches between tiles (more expensive check)
GameManager.prototype.tileMatchesAvailable = function () {
var self = this;
var tile;
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
tile = this.grid.cellContent({ x: x, y: y });
if (tile) {
for (var direction = 0; direction < 4; direction++) {
var vector = self.getVector(direction);
var cell = { x: x + vector.x, y: y + vector.y };
var other = self.grid.cellContent(cell);
if (other && other.value === tile.value) {
return true; // These two tiles can be merged
}
}
}
}
}
return false;
};
GameManager.prototype.positionsEqual = function (first, second) {
return first.x === second.x && first.y === second.y;
};
function Grid(size, previousState) {
this.size = size;
this.cells = previousState ? this.fromState(previousState) : this.empty();
}
// Build a grid of the specified size
Grid.prototype.empty = function () {
var cells = [];
for (var x = 0; x < this.size; x++) {
var row = cells[x] = [];
for (var y = 0; y < this.size; y++) {
row.push(null);
}
}
return cells;
};
Grid.prototype.fromState = function (state) {
var cells = [];
for (var x = 0; x < this.size; x++) {
var row = cells[x] = [];
for (var y = 0; y < this.size; y++) {
var tile = state[x][y];
row.push(tile ? new Tile(tile.position, tile.value) : null);
}
}
return cells;
};
// Find the first available random position
Grid.prototype.randomAvailableCell = function () {
var cells = this.availableCells();
if (cells.length) {
return cells[Math.floor(Math.random() * cells.length)];
}
};
Grid.prototype.availableCells = function () {
var cells = [];
this.eachCell(function (x, y, tile) {
if (!tile) {
cells.push({ x: x, y: y });
}
});
return cells;
};
// Call callback for every cell
Grid.prototype.eachCell = function (callback) {
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
callback(x, y, this.cells[x][y]);
}
}
};
// Check if there are any cells available
Grid.prototype.cellsAvailable = function () {
return !!this.availableCells().length;
};
// Check if the specified cell is taken
Grid.prototype.cellAvailable = function (cell) {
return !this.cellOccupied(cell);
};
Grid.prototype.cellOccupied = function (cell) {
return !!this.cellContent(cell);
};
Grid.prototype.cellContent = function (cell) {
if (this.withinBounds(cell)) {
return this.cells[cell.x][cell.y];
} else {
return null;
}
};
// Inserts a tile at its position
Grid.prototype.insertTile = function (tile) {
this.cells[tile.x][tile.y] = tile;
};
Grid.prototype.removeTile = function (tile) {
this.cells[tile.x][tile.y] = null;
};
Grid.prototype.withinBounds = function (position) {
return position.x >= 0 && position.x < this.size &&
position.y >= 0 && position.y < this.size;
};
Grid.prototype.serialize = function () {
var cellState = [];
for (var x = 0; x < this.size; x++) {
var row = cellState[x] = [];
for (var y = 0; y < this.size; y++) {
row.push(this.cells[x][y] ? this.cells[x][y].serialize() : null);
}
}
return {
size: this.size,
cells: cellState
};
};
function HTMLActuator() {
this.tileContainer = document.querySelector(".tile-container");
this.scoreContainer = document.querySelector(".score-container");
this.bestContainer = document.querySelector(".best-container");
this.messageContainer = document.querySelector(".game-message");
this.score = 0;
}
HTMLActuator.prototype.actuate = function (grid, metadata) {
var self = this;
window.requestAnimationFrame(function () {
self.clearContainer(self.tileContainer);
grid.cells.forEach(function (column) {
column.forEach(function (cell) {
if (cell) {
self.addTile(cell);
}
});
});
self.updateScore(metadata.score);
self.updateBestScore(metadata.bestScore);
if (metadata.terminated) {
if (metadata.over) {
self.message(false); // You lose
} else if (metadata.won) {
self.message(true); // You win!
}
}
});
};
// Continues the game (both restart and keep playing)
HTMLActuator.prototype.continueGame = function () {
this.clearMessage();
};
HTMLActuator.prototype.clearContainer = function (container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
};
HTMLActuator.prototype.addTile = function (tile) {
var self = this;
var wrapper = document.createElement("div");
var inner = document.createElement("div");
var position = tile.previousPosition || { x: tile.x, y: tile.y };
var positionClass = this.positionClass(position);
// We can't use classlist because it somehow glitches when replacing classes
var classes = ["tile", "tile-" + tile.value, positionClass];
if (tile.value > 2048) classes.push("tile-super");
this.applyClasses(wrapper, classes);
inner.classList.add("tile-inner");
inner.textContent = tile.value;
if (tile.previousPosition) {
// Make sure that the tile gets rendered in the previous position first
window.requestAnimationFrame(function () {
classes[2] = self.positionClass({ x: tile.x, y: tile.y });
self.applyClasses(wrapper, classes); // Update the position
});
} else if (tile.mergedFrom) {
classes.push("tile-merged");
this.applyClasses(wrapper, classes);
// Render the tiles that merged
tile.mergedFrom.forEach(function (merged) {
self.addTile(merged);
});
} else {
classes.push("tile-new");
this.applyClasses(wrapper, classes);
}
// Add the inner part of the tile to the wrapper
wrapper.appendChild(inner);
// Put the tile on the board
this.tileContainer.appendChild(wrapper);
};
HTMLActuator.prototype.applyClasses = function (element, classes) {
element.setAttribute("class", classes.join(" "));
};
HTMLActuator.prototype.normalizePosition = function (position) {
return { x: position.x + 1, y: position.y + 1 };
};
HTMLActuator.prototype.positionClass = function (position) {
position = this.normalizePosition(position);
return "tile-position-" + position.x + "-" + position.y;
};
HTMLActuator.prototype.updateScore = function (score) {
this.clearContainer(this.scoreContainer);
var difference = score - this.score;
this.score = score;
this.scoreContainer.textContent = this.score;
if (difference > 0) {
var addition = document.createElement("div");
addition.classList.add("score-addition");
addition.textContent = "+" + difference;
this.scoreContainer.appendChild(addition);
}
};
HTMLActuator.prototype.updateBestScore = function (bestScore) {
this.bestContainer.textContent = bestScore;
};
HTMLActuator.prototype.message = function (won) {
var type = won ? "game-won" : "game-over";
var message = won ? "You win!" : "Game over!";
this.messageContainer.classList.add(type);
this.messageContainer.getElementsByTagName("p")[0].textContent = message;
};
HTMLActuator.prototype.clearMessage = function () {
// IE only takes one value to remove at a time.
this.messageContainer.classList.remove("game-won");
this.messageContainer.classList.remove("game-over");
};
function KeyboardInputManager() {
this.events = {};
if (window.navigator.msPointerEnabled) {
//Internet Explorer 10 style
this.eventTouchstart = "MSPointerDown";
this.eventTouchmove = "MSPointerMove";
this.eventTouchend = "MSPointerUp";
} else {
this.eventTouchstart = "touchstart";
this.eventTouchmove = "touchmove";
this.eventTouchend = "touchend";
}
this.listen();
}
KeyboardInputManager.prototype.on = function (event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
};
KeyboardInputManager.prototype.emit = function (event, data) {
var callbacks = this.events[event];
if (callbacks) {
callbacks.forEach(function (callback) {
callback(data);
});
}
};
KeyboardInputManager.prototype.listen = function () {
var self = this;
var map = {
38: 0, // Up
39: 1, // Right
40: 2, // Down
37: 3, // Left
75: 0, // Vim up
76: 1, // Vim right
74: 2, // Vim down
72: 3, // Vim left
87: 0, // W
68: 1, // D
83: 2, // S
65: 3 // A
};
// Respond to direction keys
document.addEventListener("keydown", function (event) {
var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
event.shiftKey;
var mapped = map[event.which];
if (!modifiers) {
if (mapped !== undefined) {
event.preventDefault();
self.emit("move", mapped);
}
}
// R key restarts the game
if (!modifiers && event.which === 82) {
self.restart.call(self, event);
}
});
// Respond to button presses
this.bindButtonPress(".retry-button", this.restart);
this.bindButtonPress(".restart-button", this.restart);
this.bindButtonPress(".keep-playing-button", this.keepPlaying);
// Respond to swipe events
var touchStartClientX, touchStartClientY;
var gameContainer = document.getElementsByClassName("game-container")[0];
gameContainer.addEventListener(this.eventTouchstart, function (event) {
if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
event.targetTouches.length > 1) {
return; // Ignore if touching with more than 1 finger
}
if (window.navigator.msPointerEnabled) {
touchStartClientX = event.pageX;
touchStartClientY = event.pageY;
} else {
touchStartClientX = event.touches[0].clientX;
touchStartClientY = event.touches[0].clientY;
}
event.preventDefault();
});
gameContainer.addEventListener(this.eventTouchmove, function (event) {
event.preventDefault();
});
gameContainer.addEventListener(this.eventTouchend, function (event) {
if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
event.targetTouches.length > 0) {
return; // Ignore if still touching with one or more fingers
}
var touchEndClientX, touchEndClientY;
if (window.navigator.msPointerEnabled) {
touchEndClientX = event.pageX;
touchEndClientY = event.pageY;
} else {
touchEndClientX = event.changedTouches[0].clientX;
touchEndClientY = event.changedTouches[0].clientY;
}
var dx = touchEndClientX - touchStartClientX;
var absDx = Math.abs(dx);
var dy = touchEndClientY - touchStartClientY;
var absDy = Math.abs(dy);
if (Math.max(absDx, absDy) > 10) {
// (right : left) : (down : up)
self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0));
}
});
};
KeyboardInputManager.prototype.restart = function (event) {
event.preventDefault();
this.emit("restart");
};
KeyboardInputManager.prototype.keepPlaying = function (event) {
event.preventDefault();
this.emit("keepPlaying");
};
KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
var button = document.querySelector(selector);
button.addEventListener("click", fn.bind(this));
button.addEventListener(this.eventTouchend, fn.bind(this));
};
window.fakeStorage = {
_data: {},
setItem: function (id, val) {
return this._data[id] = String(val);
},
getItem: function (id) {
return this._data.hasOwnProperty(id) ? this._data[id] : undefined;
},
removeItem: function (id) {
return delete this._data[id];
},
clear: function () {
return this._data = {};
}
};
function LocalStorageManager() {
this.bestScoreKey = "bestScore";
this.gameStateKey = "gameState";
var supported = this.localStorageSupported();
this.storage = supported ? window.localStorage : window.fakeStorage;
}
LocalStorageManager.prototype.localStorageSupported = function () {
var testKey = "test";
try {
var storage = window.localStorage;
storage.setItem(testKey, "1");
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
// Best score getters/setters
LocalStorageManager.prototype.getBestScore = function () {
return this.storage.getItem(this.bestScoreKey) || 0;
};
LocalStorageManager.prototype.setBestScore = function (score) {
this.storage.setItem(this.bestScoreKey, score);
};
// Game state getters/setters and clearing
LocalStorageManager.prototype.getGameState = function () {
var stateJSON = this.storage.getItem(this.gameStateKey);
return stateJSON ? JSON.parse(stateJSON) : null;
};
LocalStorageManager.prototype.setGameState = function (gameState) {
this.storage.setItem(this.gameStateKey, JSON.stringify(gameState));
};
LocalStorageManager.prototype.clearGameState = function () {
this.storage.removeItem(this.gameStateKey);
};
function Tile(position, value) {
this.x = position.x;
this.y = position.y;
this.value = value || 2;
this.previousPosition = null;
this.mergedFrom = null; // Tracks tiles that merged together
}
Tile.prototype.savePosition = function () {
this.previousPosition = { x: this.x, y: this.y };
};
Tile.prototype.updatePosition = function (position) {
this.x = position.x;
this.y = position.y;
};
Tile.prototype.serialize = function () {
return {
position: {
x: this.x,
y: this.y
},
value: this.value
};
};
/**
* 五子棋人工智能棋手抽象类
* (在控制器中使用继承该类的子类)
*/
var GomokuAI = (function () {
function GomokuAI() {
/**
* 规定 AI 执白子
*/
this.player = GomokuPlayer.White;
}
return GomokuAI;
}());
//# sourceMappingURL=AI.js.map
\ No newline at end of file
{"version":3,"file":"AI.js","sourceRoot":"","sources":["../../src/AIs/AI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAAA;QACI;;WAEG;QACgB,WAAM,GAAG,YAAY,CAAC,KAAK,CAAA;IAWlD,CAAC;IAAD,eAAC;AAAD,CAAC,AAfD,IAeC"}
\ No newline at end of file
/**
* 棋型收益估分(不可变)
*/
var AIScore = (function () {
function AIScore() {
}
return AIScore;
}());
/**立即获胜 */
AIScore.WillWin = 1000;
/**无法获胜(一定无法达成5连) */
AIScore.WillFail = 0;
AIScore.Min = 0;
AIScore.Dangerous = 60;
AIScore.ooooo = 1000;
AIScore.oooo = 100;
AIScore.ooo = 40;
AIScore.Ioooo = 40;
AIScore.Iooo = 5;
AIScore.oo = 5;
AIScore.Ioo = 1;
AIScore.o = 0;
AIScore.Io = 0;
AIScore.ooo_oo = AIScore.ooo - 1;
AIScore.Iooo_oo = AIScore.Ioooo - 1;
AIScore.oo_oo = AIScore.ooo_oo;
AIScore.Ioo_oo = AIScore.Iooo_oo;
AIScore.o_oo = AIScore.ooo_oo;
AIScore.Io_oo = AIScore.Io + AIScore.oo;
AIScore.o_o = AIScore.o + AIScore.o;
AIScore.Io_o = AIScore.Io + AIScore.o;
/**
* 棋型威胁估分(不可变)
*/
var AIRivalScore = (function () {
function AIRivalScore() {
}
return AIRivalScore;
}());
AIRivalScore.ooooo = 50;
AIRivalScore.oooo = 50;
AIRivalScore.ooo = 10;
AIRivalScore.Ioooo = 10;
AIRivalScore.Iooo = 3;
AIRivalScore.oo = 3;
AIRivalScore.Ioo = 1;
AIRivalScore.o = 0;
//# sourceMappingURL=AIScore.js.map
\ No newline at end of file
{"version":3,"file":"AIScore.js","sourceRoot":"","sources":["../../src/AIs/AIScore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;IAAA;IAyBA,CAAC;IAAD,cAAC;AAAD,CAAC,AAzBD;AACI,UAAU;AACM,eAAO,GAAG,IAAI,CAAA;AAC9B,oBAAoB;AACJ,gBAAQ,GAAG,CAAC,CAAA;AACZ,WAAG,GAAG,CAAC,CAAA;AACP,iBAAS,GAAG,EAAE,CAAA;AACd,aAAK,GAAG,IAAI,CAAA;AACZ,YAAI,GAAG,GAAG,CAAA;AACV,WAAG,GAAG,EAAE,CAAA;AACR,aAAK,GAAG,EAAE,CAAA;AACV,YAAI,GAAG,CAAC,CAAA;AACR,UAAE,GAAG,CAAC,CAAA;AACN,WAAG,GAAG,CAAC,CAAA;AACP,SAAC,GAAG,CAAC,CAAA;AACL,UAAE,GAAG,CAAC,CAAA;AAEN,cAAM,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,CAAA;AACxB,eAAO,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC,CAAA;AAC3B,aAAK,GAAG,OAAO,CAAC,MAAM,CAAA;AACtB,cAAM,GAAG,OAAO,CAAC,OAAO,CAAA;AACxB,YAAI,GAAG,OAAO,CAAC,MAAM,CAAA;AACrB,aAAK,GAAG,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAA;AAC/B,WAAG,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAA;AAC3B,YAAI,GAAG,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAA;AAIjD;;GAEG;AACH;IAAA;IASA,CAAC;IAAD,mBAAC;AAAD,CAAC,AATD;AACoB,kBAAK,GAAG,EAAE,CAAA;AACV,iBAAI,GAAG,EAAE,CAAA;AACT,gBAAG,GAAG,EAAE,CAAA;AACR,kBAAK,GAAG,EAAE,CAAA;AACV,iBAAI,GAAG,CAAC,CAAA;AACR,eAAE,GAAG,CAAC,CAAA;AACN,gBAAG,GAAG,CAAC,CAAA;AACP,cAAC,GAAG,CAAC,CAAA"}
\ No newline at end of file
/**
* 五子棋人工智能棋手抽象类
* (在控制器中使用继承该类的子类)
*/
var GomokuAI = (function () {
function GomokuAI() {
/**
* 规定 AI 执白子
*/
this.player = GomokuPlayer.White;
}
return GomokuAI;
}());
//# sourceMappingURL=GomokuAI.js.map
\ No newline at end of file
{"version":3,"file":"GomokuAI.js","sourceRoot":"","sources":["../../src/AIs/GomokuAI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAAA;QACI;;WAEG;QACgB,WAAM,GAAG,YAAY,CAAC,KAAK,CAAA;IAWlD,CAAC;IAAD,eAAC;AAAD,CAAC,AAfD,IAeC"}
\ No newline at end of file
function makeMatrix(r, c, value) {
var matrix = new Array(r);
for (var i = 0; i < r; i++)
matrix[i] = new Array(c);
for (var i = 0; i < r; i++)
for (var j = 0; j < c; j++)
matrix[i][j] = value;
return matrix;
}
//# sourceMappingURL=Matrix.js.map
\ No newline at end of file
{"version":3,"file":"Matrix.js","sourceRoot":"","sources":["../../src/AIs/Matrix.ts"],"names":[],"mappings":"AAAA,oBAAuB,CAAS,EAAE,CAAS,EAAE,KAAQ;IACjD,IAAI,MAAM,GAAG,IAAI,KAAK,CAAM,CAAC,CAAC,CAAA;IAC9B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QACtB,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAI,CAAC,CAAC,CAAA;IAC/B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QACtB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YACtB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IAC5B,MAAM,CAAC,MAAM,CAAA;AACjB,CAAC"}
\ No newline at end of file
var AI;
(function (AI) {
/**状态类 */
var State = (function () {
function State() {
}
return State;
}());
AI.State = State;
/**动作类(动作使一个状态转变为另一个状态) */
var Action = (function () {
function Action() {
}
return Action;
}());
AI.Action = Action;
/**玩家类 */
var Player = (function () {
function Player() {
}
return Player;
}());
AI.Player = Player;
/**游戏类(继承该类以描述一个游戏,使其能够利用minmax决策树) */
var Game = (function () {
function Game() {
}
return Game;
}());
AI.Game = Game;
/**
* 对游戏和当前状态进行 minmax 决策
*/
function minmaxDecision(state, game) {
var player = game.toMove(state);
return maxValue(state);
function maxValue(state) {
if (game.isTerminal(state)) {
return game.utility(state, player);
}
var value = -Infinity;
var possibleActions = game.actions(state);
for (var _i = 0, possibleActions_1 = possibleActions; _i < possibleActions_1.length; _i++) {
var action = possibleActions_1[_i];
value = Math.max(value, minValue(game.result(state, action)));
}
return value;
}
function minValue(state) {
if (game.isTerminal(state)) {
return game.utility(state, player);
}
var value = Infinity;
var possibleActions = game.actions(state);
for (var _i = 0, possibleActions_2 = possibleActions; _i < possibleActions_2.length; _i++) {
var action = possibleActions_2[_i];
value = Math.min(value, maxValue(game.result(state, action)));
}
return value;
}
}
AI.minmaxDecision = minmaxDecision;
})(AI || (AI = {})); //namespace AI
//# sourceMappingURL=MinMaxTree.js.map
\ No newline at end of file
{"version":3,"file":"MinMaxTree.js","sourceRoot":"","sources":["../../src/AIs/MinMaxTree.ts"],"names":[],"mappings":"AAAA,IAAU,EAAE,CA0DX;AA1DD,WAAU,EAAE;IAEZ,SAAS;IACT;QAAA;QAA6B,CAAC;QAAD,YAAC;IAAD,CAAC,AAA9B,IAA8B;IAAR,QAAK,QAAG,CAAA;IAE9B,0BAA0B;IAC1B;QAAA;QAA8B,CAAC;QAAD,aAAC;IAAD,CAAC,AAA/B,IAA+B;IAAT,SAAM,SAAG,CAAA;IAE/B,SAAS;IACT;QAAA;QAA8B,CAAC;QAAD,aAAC;IAAD,CAAC,AAA/B,IAA+B;IAAT,SAAM,SAAG,CAAA;IAE/B,sCAAsC;IACtC;QAAA;QAMA,CAAC;QAAD,WAAC;IAAD,CAAC,AAND,IAMC;IANqB,OAAI,OAMzB,CAAA;IAED;;OAEG;IACH,wBAA+B,KAAY,EAAE,IAAU;QACnD,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAEtB,kBAAkB,KAAY;YAC1B,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YACtC,CAAC;YAED,IAAI,KAAK,GAAG,CAAC,QAAQ,CAAA;YACrB,IAAI,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAEzC,GAAG,CAAC,CAAe,UAAe,EAAf,mCAAe,EAAf,6BAAe,EAAf,IAAe;gBAA7B,IAAI,MAAM,wBAAA;gBACX,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;aAChE;YAED,MAAM,CAAC,KAAK,CAAA;QAChB,CAAC;QAED,kBAAkB,KAAY;YAC1B,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YACtC,CAAC;YAED,IAAI,KAAK,GAAG,QAAQ,CAAA;YACpB,IAAI,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAEzC,GAAG,CAAC,CAAe,UAAe,EAAf,mCAAe,EAAf,6BAAe,EAAf,IAAe;gBAA7B,IAAI,MAAM,wBAAA;gBACX,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;aAChE;YAED,MAAM,CAAC,KAAK,CAAA;QAChB,CAAC;IACL,CAAC;IAjCe,iBAAc,iBAiC7B,CAAA;AAED,CAAC,EA1DS,EAAE,KAAF,EAAE,QA0DX,CAAA,cAAc"}
\ No newline at end of file
/**
* 棋型收益估分(不可变)
*/
var AIScore = (function () {
function AIScore() {
}
return AIScore;
}());
AIScore.WillSucceed = 100;
AIScore.ooooo = 100;
AIScore.oooo = 49;
AIScore.ooo = 6;
AIScore.Ioooo = 6;
AIScore.Iooo = 3;
AIScore.oo = 3;
AIScore.Ioo = 1;
AIScore.o = 0;
AIScore.ooxoo = 9;
AIScore.Ioooxoo = 9;
/**
* 棋型威胁估分(不可变)
*/
var AIRivalScore = (function () {
function AIRivalScore() {
}
return AIRivalScore;
}());
AIRivalScore.ooooo = 50;
AIRivalScore.oooo = 50;
AIRivalScore.ooo = 10;
AIRivalScore.Ioooo = 10;
AIRivalScore.Iooo = 3;
AIRivalScore.oo = 3;
AIRivalScore.Ioo = 1;
AIRivalScore.o = 0;
//# sourceMappingURL=Score.js.map
\ No newline at end of file
{"version":3,"file":"Score.js","sourceRoot":"","sources":["../../src/AIs/Score.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;IAAA;IAaA,CAAC;IAAD,cAAC;AAAD,CAAC,AAbD;AACoB,mBAAW,GAAG,GAAG,CAAA;AACjB,aAAK,GAAG,GAAG,CAAA;AACX,YAAI,GAAG,EAAE,CAAA;AACT,WAAG,GAAG,CAAC,CAAA;AACP,aAAK,GAAG,CAAC,CAAA;AACT,YAAI,GAAG,CAAC,CAAA;AACR,UAAE,GAAG,CAAC,CAAA;AACN,WAAG,GAAG,CAAC,CAAA;AACP,SAAC,GAAG,CAAC,CAAA;AAEL,aAAK,GAAG,CAAC,CAAA;AACT,eAAO,GAAG,CAAC,CAAA;AAI/B;;GAEG;AACH;IAAA;IASA,CAAC;IAAD,mBAAC;AAAD,CAAC,AATD;AACoB,kBAAK,GAAG,EAAE,CAAA;AACV,iBAAI,GAAG,EAAE,CAAA;AACT,gBAAG,GAAG,EAAE,CAAA;AACR,kBAAK,GAAG,EAAE,CAAA;AACV,iBAAI,GAAG,CAAC,CAAA;AACR,eAAE,GAAG,CAAC,CAAA;AACN,gBAAG,GAAG,CAAC,CAAA;AACP,cAAC,GAAG,CAAC,CAAA"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 测试AI_1:采用简单估分的方式进行决策
*/
var TestAI_1 = (function (_super) {
__extends(TestAI_1, _super);
function TestAI_1() {
var _this = _super.call(this) || this;
_this.chessboard = makeMatrix(15, 15, 0);
return _this;
}
/**
* AI 先在中间落子
*/
TestAI_1.prototype.putFirstChessInMiddle = function () {
this.chessboard[7][7] = 1;
};
TestAI_1.prototype.analysAction = function (action) {
this.chessboard[action.row - 1][action.col - 1] = -1;
//先防
//计算敌方下一步最高收益的落子
var rivalScores = makeMatrix(15, 15, -1);
for (var i = 0; i < 15; i++)
for (var j = 0; j < 15; j++)
if (this.chessboard[i][j] == 0) {
this.chessboard[i][j] = -1; //尝试落子
rivalScores[i][j] = this.computeScore(i, j, -1); //计算敌方收益
this.chessboard[i][j] = 0; //收回尝试
}
var rI = 0, rJ = 0;
for (var i = 0; i < 15; i++)
for (var j = 0; j < 15; j++)
if (rivalScores[i][j] > rivalScores[rI][rJ]) {
rI = i;
rJ = j;
}
// 后攻
// 遍历每一个位置, 评估分数
this.scores = makeMatrix(15, 15, -1);
for (var i = 0; i < 15; i++)
for (var j = 0; j < 15; j++)
if (this.chessboard[i][j] == 0) {
this.chessboard[i][j] = 1; //尝试落子
this.scores[i][j] = this.computeScore(i, j, 1); //计算己方收益
this.chessboard[i][j] = 0; //收回尝试
}
// 选出进攻分数最高的位置
var I = 0, J = 0;
for (var i = 0; i < 15; i++)
for (var j = 0; j < 15; j++)
if (this.scores[i][j] > this.scores[I][J]) {
I = i;
J = j;
}
if (this.scores[I][J] == 100) {
this.chessboard[I][J] = 1;
//直接获胜
this.next = {
row: I + 1,
col: J + 1,
player: this.player
};
console.log("Attack: (" + this.next.row + ", " + this.next.col + ") s:" + this.scores[I][J]);
}
else if (rivalScores[rI][rJ] >= 20) {
//若出现危险棋局, 选择防守策略
this.chessboard[rI][rJ] = 1;
this.next = {
row: rI + 1,
col: rJ + 1,
player: this.player
};
console.log("Defend: (" + this.next.row + ", " + this.next.col + ") s:" + rivalScores[rI][rJ]);
}
else {
//进攻
this.chessboard[I][J] = 1;
this.next = {
row: I + 1,
col: J + 1,
player: this.player
};
console.log("Attack: (" + this.next.row + ", " + this.next.col + ") s:" + this.scores[I][J]);
}
};
TestAI_1.prototype.getNextAction = function () {
return this.next;
};
/**
* 根据棋型给出分数
*
* 一个棋型由其中连子的个数和前后是否堵截来确定
*/
TestAI_1.prototype.scoreOfStyle = function (line, block1, block2) {
if (line == 5)
return AIScore.ooooo;
if (block1 && block2)
return 0;
switch (line) {
case 4: return (block1 || block2) ? AIScore.Ioooo : AIScore.oooo;
case 3: return (block1 || block2) ? AIScore.Iooo : AIScore.ooo;
case 2: return (block1 || block2) ? AIScore.Ioo : AIScore.oo;
case 1: return 0;
}
};
/**
* 根据棋敌方型给出威胁分数
*
* 一个棋型由其中连子的个数和前后是否堵截来确定
*/
TestAI_1.prototype.scoreOfRivalStyle = function (line, block1, block2) {
if (line == 5)
return AIRivalScore.ooooo;
if (block1 && block2)
return 0;
switch (line) {
case 4: return (block1 || block2) ? AIRivalScore.Ioooo : AIRivalScore.oooo;
case 3: return (block1 || block2) ? AIRivalScore.Iooo : AIRivalScore.ooo;
case 2: return (block1 || block2) ? AIRivalScore.Ioo : AIRivalScore.oo;
case 1: return 0;
}
};
/**
* 假设在(i, j)处落子, 计算落子后获得的分数 scores[i][j]
* @param {number} player 1 计算己方的收益, -1 计算敌方收益
*/
TestAI_1.prototype.computeScore = function (i, j, player) {
var score = 0;
//上、下 (r先减后加, c不变)
var r1 = i, c = j;
while (r1 > 0 && this.chessboard[r1 - 1][c] == player)
r1--;
var upIsBlocked = (r1 == 0) || this.chessboard[r1 - 1][c] == -player;
var r2 = i;
while (r2 < 14 && this.chessboard[r2 + 1][c] == player)
r2++;
var downIsBlocked = (r2 == 14) || this.chessboard[r2 + 1][c] == -player;
var line = (r1 == r2) ? 1 : (r2 - r1 + 1);
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, upIsBlocked, downIsBlocked) :
this.scoreOfRivalStyle(line, upIsBlocked, downIsBlocked);
//左、右 (r不变, c先减后加)
var r = i, c1 = j;
while (c1 > 0 && this.chessboard[r][c1 - 1] == player)
c1--;
var leftIsBlocked = (c1 == 0) || this.chessboard[r][c1 - 1] == -player;
var c2 = j;
while (c2 < 14 && this.chessboard[r][c2 + 1] == player)
c2++;
var rightIsBlocked = (c2 == 14) || this.chessboard[r][c2 + 1] == -player;
line = (c1 == c2) ? 1 : (c2 - c1 + 1);
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftIsBlocked, rightIsBlocked) :
this.scoreOfRivalStyle(line, leftIsBlocked, rightIsBlocked);
//主对角线方向 (rc先减后加)
r1 = i, c1 = j;
while (r1 > 0 && c1 > 0 && this.chessboard[r1 - 1][c1 - 1] == player) {
r1--;
c1--;
}
var leftUpIsBlocked = (r1 == 0 || c1 == 0) || this.chessboard[r1 - 1][c1 - 1] == -player;
r2 = i;
c2 = j;
while (r2 < 14 && c2 < 14 && this.chessboard[r2 + 1][c2 + 1] == player) {
r2++;
c2++;
}
var rightDownIsBlocked = (r2 == 14 || c2 == 14) || this.chessboard[r2 + 1][c2 + 1] == -player;
line = (r1 == r2) ? 1 : (r2 - r1 + 1);
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftUpIsBlocked, rightDownIsBlocked) :
this.scoreOfRivalStyle(line, leftUpIsBlocked, rightDownIsBlocked);
//副对角线方向 (r先加后减, c先减后加)
r1 = i, c1 = j;
while (r1 < 14 && c1 > 0 && this.chessboard[r1 + 1][c1 - 1] == player) {
r1++;
c1--;
}
var leftDownIsBlocked = (r1 == 14 || c1 == 0) || this.chessboard[r1 + 1][c1 - 1] == -player;
r2 = i;
c2 = j;
while (r2 > 0 && c2 < 14 && this.chessboard[r2 - 1][c2 + 1] == player) {
r2--;
c2++;
}
var rightUpIsBlocked = (r2 == 0 || c2 == 14) || this.chessboard[r2 - 1][c2 + 1] == -player;
line = (c1 == c2) ? 1 : (c2 - c1 + 1);
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftDownIsBlocked, rightUpIsBlocked) :
this.scoreOfRivalStyle(line, leftDownIsBlocked, rightUpIsBlocked);
return score;
};
return TestAI_1;
}(GomokuAI));
//# sourceMappingURL=TestAI_1.js.map
\ No newline at end of file
{"version":3,"file":"TestAI_1.js","sourceRoot":"","sources":["../../src/AIs/TestAI_1.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var AI;
(function (AI) {
/** AI 将棋子分为 None, Player, AI 三种 */
var AIChess;
(function (AIChess) {
AIChess[AIChess["Empty"] = 0] = "Empty";
AIChess[AIChess["Player"] = 1] = "Player";
AIChess[AIChess["AI"] = -1] = "AI";
})(AIChess || (AIChess = {}));
/**2号AI */
var TestAI_2 = (function (_super) {
__extends(TestAI_2, _super);
function TestAI_2() {
var _this = _super.call(this) || this;
_this.maxSearchDepth = 2;
_this.chessboard = makeMatrix(15, 15, AIChess.Empty);
_this.profits = makeMatrix(15, 15, -1);
_this.threats = makeMatrix(15, 15, -1);
return _this;
}
TestAI_2.prototype.positionIsValid = function (pos) {
if (0 <= pos.row && pos.row <= 14 && 0 <= pos.col && pos.col <= 14)
return true;
else
return false;
};
TestAI_2.prototype.positionIsEmpty = function (pos) {
return this.getChess(pos) == AIChess.Empty;
};
TestAI_2.prototype.getChess = function (pos) {
return this.chessboard[pos.row][pos.col];
};
TestAI_2.prototype.putChessOn = function (pos, chess) {
this.chessboard[pos.row][pos.col] = chess;
};
TestAI_2.prototype.takeChessFrom = function (pos) {
this.chessboard[pos.row][pos.col] = AIChess.Empty;
};
TestAI_2.prototype.allPossiblePositions = function () {
var postions = [];
for (var r = 0; r < this.chessboard.length; r++) {
for (var c = 0; c < this.chessboard[r].length; c++) {
if (this.chessboard[r][c] == AIChess.Empty) {
postions.push({
row: r,
col: c
});
}
}
}
return postions;
};
TestAI_2.prototype.putFirstChessInMiddle = function () {
this.putChessOn({ row: 7, col: 7 }, AIChess.AI);
};
TestAI_2.prototype.scoreOfEvaluation = function (result) {
if (result.count >= 5 && !result.hasGap)
return AIScore.ooooo;
else if (result.count >= 5 && result.hasGap)
return AIScore.Iooo_oo;
else if (result.leftIsBlocked && result.rightIsBlocked)
return AIScore.WillFail;
if (!result.hasGap) {
switch (result.count) {
case 4: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioooo : AIScore.oooo;
case 3: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Iooo : AIScore.ooo;
case 2: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioo : AIScore.oo;
case 1: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io : AIScore.o;
}
}
else {
switch (result.count) {
case 4: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioo_oo : AIScore.oo_oo;
case 3: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io_oo : AIScore.o_oo;
case 2: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io_o : AIScore.o_o;
}
}
return AIScore.Min;
};
/**
* 评估指定位置和方向的AI或玩家的连子, 连子方向由两个函数决定, 允许中间出现一次间隔
* (应确保指定位置处有棋子且为target)
* @param {ChessPosition} pos 棋子的位置
* @param {AIChess} target AI或玩家 (注: -target == target的对手)
* @param {function(ChessPosition):ChessPosition} dec 位置递减函数
* @param {function(ChessPosition):ChessPosition} inc 位置递增函数
* @return {ContinualLineEvalutaion} 评估结果
*/
TestAI_2.prototype.evaluateContinualLine = function (pos, target, dec, inc) {
//使用dec走到连子的一个边界, 再使用inc走到连子的另一个边界
var hasGap = false;
var leftIsBlocked = false;
//先走到一个边界
while (this.positionIsValid(dec(pos))) {
if (this.positionIsEmpty(dec(pos))) {
if (hasGap)
break;
else
hasGap = true;
}
else if (this.getChess(dec(pos)) == -target) {
leftIsBlocked = true;
break;
}
pos = dec(pos);
}
if (!this.positionIsValid(dec(pos)))
leftIsBlocked = true;
if (this.positionIsEmpty(pos)) {
pos = inc(pos);
leftIsBlocked = false;
}
//再走到另一个边界
hasGap = false;
var count = 1;
var rightIsBlocked = false;
while (this.positionIsValid(inc(pos))) {
if (this.positionIsEmpty(inc(pos))) {
if (hasGap)
break;
else
hasGap = true;
}
else if (this.getChess(inc(pos)) == -target) {
rightIsBlocked = true;
break;
}
pos = inc(pos);
count++;
}
if (!this.positionIsValid(inc(pos)))
rightIsBlocked = true;
if (this.positionIsEmpty(pos)) {
pos = dec(pos);
rightIsBlocked = false;
hasGap = false;
count--;
}
if (hasGap)
count--;
return this.scoreOfEvaluation({
count: count,
hasGap: hasGap,
leftIsBlocked: leftIsBlocked,
rightIsBlocked: rightIsBlocked
});
};
/**
* 计算在 (row, col) target 落子的得分(AI落子即收益分, 玩家落子即威胁分)
* @param {number} row 0~14
* @param {number} col 0~14
* @param {AIChess} target AI 或 Player
*/
TestAI_2.prototype.computeScore = function (pos, target) {
this.putChessOn(pos, target);
var score = 0;
//从上到下
score += this.evaluateContinualLine(pos, target, function (pos) { return { row: pos.row - 1, col: pos.col }; }, function (pos) { return { row: pos.row + 1, col: pos.col }; });
//从左到右
score += this.evaluateContinualLine(pos, target, function (pos) { return { row: pos.row, col: pos.col - 1 }; }, function (pos) { return { row: pos.row, col: pos.col + 1 }; });
//从右上到左下
score += this.evaluateContinualLine(pos, target, function (pos) { return { row: pos.row - 1, col: pos.col - 1 }; }, function (pos) { return { row: pos.row + 1, col: pos.col + 1 }; });
//从左下到右上
score += this.evaluateContinualLine(pos, target, function (pos) { return { row: pos.row + 1, col: pos.col - 1 }; }, function (pos) { return { row: pos.row - 1, col: pos.col + 1 }; });
this.takeChessFrom(pos);
return score;
};
/**计算 AI 所有可能落子的收益 */
TestAI_2.prototype.computeProfits = function () {
for (var r = 0; r < 15; r++) {
for (var c = 0; c < 15; c++) {
if (this.positionIsEmpty({ row: r, col: c })) {
this.profits[r][c] = this.computeScore({ row: r, col: c }, AIChess.AI);
}
else {
this.profits[r][c] = -1;
}
}
}
};
/**获取最大收益点 */
TestAI_2.prototype.getMaxProfitPosition = function () {
var p = {
row: 0,
col: 0
};
for (var r = 0; r < 15; r++) {
for (var c = 0; c < 15; c++) {
if (this.profits[r][c] > this.profits[p.row][p.col]) {
p.row = r;
p.col = c;
}
}
}
return p;
};
/**计算玩家所有可能落子的威胁 */
TestAI_2.prototype.computeThreats = function () {
for (var r = 0; r < 15; r++) {
for (var c = 0; c < 15; c++) {
if (this.positionIsEmpty({ row: r, col: c })) {
this.threats[r][c] = this.computeScore({ row: r, col: c }, AIChess.Player);
}
else {
this.threats[r][c] = -1;
}
}
}
};
/**获取最大威胁点 */
TestAI_2.prototype.getMaxThreatPosition = function () {
var p = {
row: 0,
col: 0
};
for (var r = 0; r < 15; r++) {
for (var c = 0; c < 15; c++) {
if (this.threats[r][c] > this.threats[p.row][p.col]) {
p.row = r;
p.col = c;
}
}
}
return p;
};
/**
* Min-Max 决策找出对大收益点
* 搜索深度取决于 maxSearchDepth
*
* @Todo: minmax 算法无法应用于当前的AI,minmax 算法使用给予状态的整体utility函数,
* 而不是仅当落子时计算四周的连子
*
* @param {AIChess} target 决策对象(AI|Player)
*/
TestAI_2.prototype.minmaxDecision = function (target) {
var _this = this;
var currentDepth = 0;
var maxValue = function (pos) {
currentDepth++;
if (currentDepth == _this.maxSearchDepth) {
currentDepth--;
return _this.computeScore(pos, -target);
}
_this.putChessOn(pos, -target);
var v = -Infinity;
var possiblePositions = _this.allPossiblePositions();
for (var _i = 0, possiblePositions_1 = possiblePositions; _i < possiblePositions_1.length; _i++) {
var pos_1 = possiblePositions_1[_i];
v = Math.max(v, minValue(pos_1));
}
_this.takeChessFrom(pos);
currentDepth--;
return v;
};
var minValue = function (pos) {
currentDepth++;
if (currentDepth == _this.maxSearchDepth) {
currentDepth--;
return _this.computeScore(pos, target);
}
_this.putChessOn(pos, target);
var v = Infinity;
var possiblePositions = _this.allPossiblePositions();
for (var _i = 0, possiblePositions_2 = possiblePositions; _i < possiblePositions_2.length; _i++) {
var pos_2 = possiblePositions_2[_i];
v = Math.min(v, maxValue(pos_2));
}
_this.takeChessFrom(pos);
currentDepth--;
return v;
};
var possiblePositions = this.allPossiblePositions();
var pos = possiblePositions[0];
var value = minValue(pos);
for (var i = 1; i < possiblePositions.length; i++) {
if (minValue(possiblePositions[i]) > value) {
pos = possiblePositions[i];
}
}
return pos;
};
/**
* 分析对手的动作
*/
TestAI_2.prototype.analysAction = function (action) {
this.putChessOn({ row: action.row - 1, col: action.col - 1 }, AIChess.Player);
//判断局棋威胁
this.computeThreats();
//判断下一步收益
this.computeProfits();
};
/**
* 给出下一次动作
*/
TestAI_2.prototype.getNextAction = function () {
var ppos = this.getMaxProfitPosition();
var tpos = this.getMaxThreatPosition();
var pos = (this.threats[tpos.row][tpos.col] > AIScore.Dangerous && this.threats[tpos.row][tpos.col] > this.profits[ppos.row][ppos.col]) ?
tpos : ppos;
if (this.profits[ppos.row][ppos.col] == AIScore.ooooo)
pos = ppos;
this.putChessOn(pos, AIChess.AI);
return {
row: pos.row + 1,
col: pos.col + 1,
player: GomokuPlayer.White,
};
};
return TestAI_2;
}(GomokuAI)); //class TestAI_2
AI.TestAI_2 = TestAI_2;
})(AI || (AI = {})); //namespace AI
//# sourceMappingURL=TestAI_2.js.map
\ No newline at end of file
{"version":3,"file":"TestAI_2.js","sourceRoot":"","sources":["../../src/AIs/TestAI_2.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* 五子棋游戏 (MVC) 的 Model 层
*
* 控制游戏规则,判断胜负
*/
var GomokuGame = (function () {
function GomokuGame(playWithAI) {
if (playWithAI === void 0) { playWithAI = false; }
this.maxRow = 15;
this.maxCol = 15;
this.currentPlayer = GomokuPlayer.White; //白子(AI)先行
this.gameIsOver = false;
this.chessboard = new Chessboard(this.maxRow, this.maxCol);
this.allActions = [];
}
/**
* 当前玩家在坐标上落子,成功落子后返回 true
* (将充分检查以确保安全落子)
* 落子后将变更当前玩家
* @param {number} row 行坐标
* @param {number} col 列坐标
*/
GomokuGame.prototype.putChessOn = function (row, col) {
if (this.gameIsOver)
return false;
if (this.chessboard.validRowAndCol(row, col) && !this.chessboard.hasChess(row, col)) {
this.chessboard.putChess(row, col, chessOfPlayer(this.currentPlayer));
this.lastAction = {
row: row,
col: col,
player: this.currentPlayer
};
this.allActions.push(this.lastAction);
this.checkLastAction();
this.currentPlayer = changePlayer(this.currentPlayer);
return true;
}
return false;
};
/**
* 使用指定的棋局复盘
* 当前棋局将被覆盖
*/
GomokuGame.prototype.replay = function () {
//Todo
};
/**
* 判断最近的一次游戏动作是否使一方获胜
* (以最近的一次落子坐标为基准,分别检查横向、纵向、主对角线、副对角线方向是否存在获胜棋组
* 并保存获胜棋组)
*/
GomokuGame.prototype.checkLastAction = function () {
this.checkRow(this.lastAction.row, this.lastAction.player);
this.checkColumn(this.lastAction.col, this.lastAction.player);
this.checkMainDiagonal(this.lastAction.row, this.lastAction.col, this.lastAction.player);
this.checkSubDiagonal(this.lastAction.row, this.lastAction.col, this.lastAction.player);
};
/**
* 检查玩家是否在指定的行上获胜
* @param {number} row 行坐标
* @param {Player} forPlayer 指定的玩家
*/
GomokuGame.prototype.checkRow = function (row, forPlayer) {
if (this.gameIsOver)
return;
this.winningChesses = [];
for (var col = 1; col <= this.maxCol; col++) {
if (this.chessboard.getChess(row, col) == chessOfPlayer(forPlayer)) {
this.winningChesses.push(this.chessboard.getChess(row, col));
if (this.winningChesses.length == 5) {
this.gameIsOver = true;
return;
}
}
else {
this.winningChesses = [];
}
}
};
/**
* 检查玩家是否在指定的列上获胜
* @param {number} col 列坐标
* @param {Player} forPlayer 玩家
*/
GomokuGame.prototype.checkColumn = function (col, forPlayer) {
if (this.gameIsOver)
return;
for (var row = 1; row <= this.maxRow; row++) {
if (this.chessboard.getChess(row, col) == chessOfPlayer(forPlayer)) {
this.winningChesses.push(this.chessboard.getChess(row, col));
if (this.winningChesses.length == 5) {
this.gameIsOver = true;
return;
}
}
else {
this.winningChesses = [];
}
}
};
/**
* 检查玩家是否在指定点的主对角线上获胜
* @param {number} row 行坐标
* @param {number} col 列坐标
* @param {Player} forPlayer 玩家
*/
GomokuGame.prototype.checkMainDiagonal = function (row, col, forPlayer) {
if (this.gameIsOver)
return;
var fromR, fromC, toR, toC;
if (col >= row) {
fromR = 1;
fromC = col - row + 1;
toR = 15 - col + row;
toC = 15;
}
else {
fromR = row - col + 1;
fromC = 1;
toR = 15;
toC = 15 + col - row;
}
while (fromR <= toR && fromC <= toC) {
if (this.chessboard.getChess(fromR, fromC) == chessOfPlayer(forPlayer)) {
this.winningChesses.push(this.chessboard.getChess(fromR, fromC));
if (this.winningChesses.length == 5) {
this.gameIsOver = true;
return;
}
}
else {
this.winningChesses = [];
}
fromR++;
fromC++;
}
};
/**
* 检查玩家是否在指定点的副对角线上获胜
* @param {number} row 行坐标
* @param {number} col 列坐标
* @param {Player} forPlayer 玩家
*/
GomokuGame.prototype.checkSubDiagonal = function (row, col, forPlayer) {
if (this.gameIsOver)
return;
var fromR, fromC, toR, toC;
if (col + row <= 16) {
fromR = 1;
fromC = row + col - 1;
toR = row + col - 1;
toC = 1;
}
else {
fromR = row + col - 15;
fromC = 15;
toR = 15;
toC = row + col - 15;
}
while (fromR <= toR && fromC >= toC) {
if (this.chessboard.getChess(fromR, fromC) == chessOfPlayer(forPlayer)) {
this.winningChesses.push(this.chessboard.getChess(fromR, fromC));
if (this.winningChesses.length == 5) {
this.gameIsOver = true;
return;
}
}
else {
this.winningChesses = [];
}
fromR++;
fromC--;
}
};
return GomokuGame;
}());
//# sourceMappingURL=GomokuGame.js.map
\ No newline at end of file
{"version":3,"file":"GomokuGame.js","sourceRoot":"","sources":["../src/GomokuGame.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* 五子棋游戏 (MVC) 的 Controller 层
*/
var GomokuViewController = (function () {
function GomokuViewController(playWithAI) {
if (playWithAI === void 0) { playWithAI = false; }
this.playWithAI = false;
this._showChessStep = false;
this.historiesHaveLoaded = false;
//Views
this.gameView = new GomokuView(480, 480, this);
this.menuView = new MenuView(480, 200, this);
this.menuView.statusMessage = "执黑子";
this.dialogView = new DialogView();
//Models
this.gomokuGame = new GomokuGame();
this.gomokuDB = new GomokuDB();
this.loadHistory();
if (playWithAI) {
this.playWithAI = true;
this.AI = new AI.TestAI_2();
//AI先落子
this.AI.putFirstChessInMiddle();
this.gomokuGame.putChessOn(8, 8); //game默认白子开局
this.gameView.putChessOn(8, 8, Chess.White);
this.menuView.chessCount = 1;
}
}
Object.defineProperty(GomokuViewController.prototype, "showChessStep", {
get: function () {
return this._showChessStep;
},
/**
* 修改 showChessStep 值的同时会重绘棋盘
*/
set: function (x) {
this._showChessStep = x;
if (this.showChessStep) {
this.drawChessSteps();
}
else {
this.gameView.redrawChessboard(this.gomokuGame.allActions);
}
},
enumerable: true,
configurable: true
});
/**
* 读取数据库,将历史记录写入对话框视图
*/
GomokuViewController.prototype.loadHistory = function () {
var _this = this;
this.gomokuDB.getAll(function (item) {
//读取并处理一个对象
var date = item.datetime;
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var hour = date.getHours();
var minute = date.getMinutes();
var winner = item.actions[item.actions.length - 1].player == GomokuPlayer.Black
? "玩家" : "AI";
_this.dialogView.addItem(year + "\u5E74" + month + "\u6708" + day + "\u65E5-" + hour + "\u65F6" + minute + "\u5206 " + winner + "\u83B7\u80DC"); //Todo
});
};
/**
* 响应棋盘上的点击
*/
GomokuViewController.prototype.handleClickEvent = function (x, y) {
if (this.gomokuGame.gameIsOver)
return;
//玩家落子
var col = Math.round(x / this.gameView.horizontalLineGap);
var row = Math.round(y / this.gameView.verticalLineGap);
if (this.gomokuGame.currentPlayer != GomokuPlayer.Black) {
return;
} //检查是否该玩家落子(防乱按
if (!this.gomokuGame.putChessOn(row, col)) {
return;
}
this.gameView.putChessOn(this.gomokuGame.lastAction.row, this.gomokuGame.lastAction.col, chessOfPlayer(this.gomokuGame.lastAction.player));
this.menuView.chessCount = this.menuView.chessCount + 1;
//AI落子
if (this.playWithAI && !this.gomokuGame.gameIsOver) {
this.AI.analysAction(this.gomokuGame.lastAction);
var action = this.AI.getNextAction();
this.gomokuGame.putChessOn(action.row, action.col);
this.gameView.putChessOn(action.row, action.col, chessOfPlayer(action.player));
}
this.menuView.chessCount = this.menuView.chessCount + 1;
if (this.gomokuGame.gameIsOver) {
//游戏结束,显示结束信息
var whiteWin = void 0, blackWin = void 0;
if (this.gameView.theme instanceof VividTheme) {
whiteWin = "青子胜";
blackWin = "蓝子胜";
}
else {
whiteWin = "白子胜";
blackWin = "黑子胜";
}
this.menuView.statusMessage = this.gomokuGame.currentPlayer == 1 ? whiteWin : blackWin;
this.gomokuDB.add({
datetime: new Date(),
actions: this.gomokuGame.allActions
});
}
};
/**
* 更改棋盘主题
*/
GomokuViewController.prototype.changeTheme = function (theme) {
this.gameView.theme = theme;
this.gameView.redrawChessboard(this.gomokuGame.allActions);
if (this.showChessStep) {
this.drawChessSteps();
}
if (theme instanceof DefaultTheme) {
this.menuView.statusMessage = "执黑子";
}
else if (theme instanceof VividTheme) {
this.menuView.statusMessage = "执蓝子";
}
};
/**
* 在每个棋子上面显示步数
*/
GomokuViewController.prototype.drawChessSteps = function () {
this.gameView.drawSteps(this.gomokuGame.allActions);
};
/**
* 显示对话框
*/
GomokuViewController.prototype.toggleDialog = function () {
this.dialogView.toggle();
};
return GomokuViewController;
}());
//# sourceMappingURL=GomokuViewController.js.map
\ No newline at end of file
{"version":3,"file":"GomokuViewController.js","sourceRoot":"","sources":["../src/GomokuViewController.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* 棋盘上的棋子:黑子、白子、空
*/
var Chess;
(function (Chess) {
Chess[Chess["None"] = 0] = "None";
Chess[Chess["Black"] = 1] = "Black";
Chess[Chess["White"] = 2] = "White"; //should equal Player.White
//Todo: keep consistency between Player and Chessman
})(Chess || (Chess = {}));
/**
* 返回玩家所持有的棋子
* @param {Player} player 玩家
* @return {Chess} 玩家的棋子
*/
function chessOfPlayer(player) {
return Chess[GomokuPlayer[player]];
}
/**
* 返回对手所持有的棋子
* @param {Player} player 玩家
* @return {Chess} 对手的棋子
*/
function chessOfRival(rival) {
return Chess[GomokuPlayer[rival]];
}
//# sourceMappingURL=Chess.js.map
\ No newline at end of file
{"version":3,"file":"Chess.js","sourceRoot":"","sources":["../../src/Models/Chess.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,IAAK,KAKJ;AALD,WAAK,KAAK;IACN,iCAAQ,CAAA;IACR,mCAAS,CAAA;IACT,mCAAS,CAAA,CAAE,2BAA2B;IACtC,oDAAoD;AACxD,CAAC,EALI,KAAK,KAAL,KAAK,QAKT;AAED;;;;GAIG;AACH,uBAAuB,MAAoB;IACvC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;AACtC,CAAC;AAED;;;;GAIG;AACH,sBAAsB,KAAmB;IACrC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AACrC,CAAC"}
\ No newline at end of file
/**
* 包含棋子的棋盘
*/
var Chessboard = (function () {
function Chessboard(numberOfRows, numberOfColumns) {
if (numberOfRows === void 0) { numberOfRows = 15; }
if (numberOfColumns === void 0) { numberOfColumns = 15; }
this.chessboard = [];
this.numberOfRows = numberOfRows;
this.numberOfColumns = numberOfColumns;
for (var i = 0; i < numberOfRows; i++) {
var row = [];
for (var j = 0; j < numberOfColumns; j++) {
row.push(Chess.None);
}
this.chessboard.push(row);
}
}
/**
* 判断坐标是否有棋子(可以指定棋子类型)
*
* 坐标越界则返回 undefined
* @param {Chessman} givenChess 指定棋子的类型
*/
Chessboard.prototype.hasChess = function (row, col, givenChess) {
if (givenChess) {
return this.validRowAndCol(row, col) ? this.chessboard[row - 1][col - 1] != givenChess : undefined;
}
else {
return this.validRowAndCol(row, col) ? this.chessboard[row - 1][col - 1] != Chess.None : undefined;
}
};
Chessboard.prototype.getChess = function (row, col) {
return this.validRowAndCol(row, col) ? this.chessboard[row - 1][col - 1] : undefined;
};
Chessboard.prototype.putChess = function (row, col, chess) {
if (this.validRowAndCol(row, col)) {
this.chessboard[row - 1][col - 1] = chess;
}
};
Chessboard.prototype.validRowAndCol = function (row, col) {
return 1 <= row && row <= this.numberOfRows
&& 1 <= col && col <= this.numberOfColumns ?
true : false;
};
return Chessboard;
}());
//# sourceMappingURL=Chessboard.js.map
\ No newline at end of file
{"version":3,"file":"Chessboard.js","sourceRoot":"","sources":["../../src/Models/Chessboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;IAQI,oBAAY,YAAiB,EAAE,eAAoB;QAAvC,6BAAA,EAAA,iBAAiB;QAAE,gCAAA,EAAA,oBAAoB;QAC/C,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;QACpB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA;QAChC,IAAI,CAAC,eAAe,GAAG,eAAe,CAAA;QACtC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,GAAY,EAAE,CAAA;YACrB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACxB,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC7B,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,6BAAQ,GAAR,UAAS,GAAW,EAAE,GAAW,EAAE,UAAkB;QACjD,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,UAAU,GAAG,SAAS,CAAA;QACtG,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,SAAS,CAAA;QACtG,CAAC;IACL,CAAC;IAED,6BAAQ,GAAR,UAAS,GAAW,EAAE,GAAW;QAC7B,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,SAAS,CAAA;IACxF,CAAC;IAED,6BAAQ,GAAR,UAAS,GAAW,EAAE,GAAW,EAAE,KAAY;QAC3C,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,CAAA;QAC7C,CAAC;IACL,CAAC;IAED,mCAAc,GAAd,UAAe,GAAW,EAAE,GAAW;QACnC,MAAM,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY;eACpC,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,eAAe;YACzC,IAAI,GAAG,KAAK,CAAA;IACrB,CAAC;IACL,iBAAC;AAAD,CAAC,AAlDD,IAkDC"}
\ No newline at end of file
/**
* 棋盘上的棋子:黑子、白子、空
*/
var Chessman;
(function (Chessman) {
Chessman[Chessman["None"] = 0] = "None";
Chessman[Chessman["Black"] = 1] = "Black";
Chessman[Chessman["White"] = 2] = "White"; //should equal Player.White
//Todo: keep consistency between Player and Chessman
})(Chessman || (Chessman = {}));
/**
* 返回玩家所持有的棋子
* @param {Player} player 玩家
* @return {Chess} 玩家的棋子
*/
function chessOfPlayer(player) {
return Chessman[GomokuPlayer[player]];
}
/**
* 返回对手所持有的棋子
* @param {Player} player 玩家
* @return {Chess} 对手的棋子
*/
function chessOfRival(rival) {
return Chessman[GomokuPlayer[rival]];
}
//# sourceMappingURL=Chessman.js.map
\ No newline at end of file
{"version":3,"file":"Chessman.js","sourceRoot":"","sources":["../../src/Models/Chessman.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,IAAK,QAKJ;AALD,WAAK,QAAQ;IACT,uCAAQ,CAAA;IACR,yCAAS,CAAA;IACT,yCAAS,CAAA,CAAE,2BAA2B;IACtC,oDAAoD;AACxD,CAAC,EALI,QAAQ,KAAR,QAAQ,QAKZ;AAED;;;;GAIG;AACH,uBAAuB,MAAoB;IACvC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;AACzC,CAAC;AAED;;;;GAIG;AACH,sBAAsB,KAAmB;IACrC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AACxC,CAAC"}
\ No newline at end of file
/**
* 以 IndexedDB 为基础所实现的五子棋数据库模型
*
* 用于纪录玩家的对弈历史
*/
var GomokuDB = (function () {
/**
* 打开或创建 IndexedDB 数据库
*/
function GomokuDB() {
var _this = this;
/**
* 当数据库尚未准备完毕时,将请求数据库的操作做成闭包放入 onReady。
* 当 dbIsReady 被设置为 true 时,将自动执行这些操作
*/
this.onReady = [];
this._dbIsReady = false;
this.onReady = [];
this.dbOpenRequest = window.indexedDB.open(GomokuDB.DBName, GomokuDB.DBVersion);
this.dbOpenRequest.onsuccess = function (event) {
_this.db = _this.dbOpenRequest.result;
_this.dbIsReady = true;
console.log("GomokuDB Ready.");
};
this.dbOpenRequest.onerror = function (event) {
alert("Database error: " + event.message);
};
this.dbOpenRequest.onupgradeneeded = function (event) {
var db = event.target.result;
if (!db.objectStoreNames.contains(GomokuDB.HistoryStoreName)) {
db.createObjectStore(GomokuDB.HistoryStoreName, { keyPath: GomokuDB.HistoryKeyPath });
}
console.log("DB version changed from " + event.oldVersion + " to " + event.newVersion);
};
}
Object.defineProperty(GomokuDB.prototype, "dbIsReady", {
get: function () {
return this._dbIsReady;
},
set: function (value) {
this._dbIsReady = value;
if (this.dbIsReady) {
//Todo: do something
for (var _i = 0, _a = this.onReady; _i < _a.length; _i++) {
var func = _a[_i];
func();
}
this.onReady = [];
}
},
enumerable: true,
configurable: true
});
/**
* 添加新的纪录
* @param {GomokuHistory} history 新的历史记录条目
*/
GomokuDB.prototype.add = function (history) {
var _this = this;
if (!this.dbIsReady) {
this.onReady.push(function () {
_this.add(history);
});
return;
}
var transaction = this.db.transaction(GomokuDB.HistoryStoreName, "readwrite");
var store = transaction.objectStore(GomokuDB.HistoryStoreName);
store.add(history);
};
/**
* 获取所有的历史记录
*/
GomokuDB.prototype.getAll = function (callback) {
var _this = this;
if (!this.dbIsReady) {
this.onReady.push(function () {
_this.getAll(callback);
});
return;
}
var transaction = this.db.transaction(GomokuDB.HistoryStoreName);
var store = transaction.objectStore(GomokuDB.HistoryStoreName);
// return []
var req = store.openCursor();
req.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
callback(cursor.value);
cursor.continue();
}
};
};
return GomokuDB;
}());
GomokuDB.DBVersion = 2;
GomokuDB.DBName = "gomokudb";
GomokuDB.HistoryStoreName = "history";
GomokuDB.HistoryKeyPath = "datetime";
//# sourceMappingURL=GomokuDB.js.map
\ No newline at end of file
{"version":3,"file":"GomokuDB.js","sourceRoot":"","sources":["../../src/Models/GomokuDB.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* 玩家:黑、白
*/
var GomokuPlayer;
(function (GomokuPlayer) {
GomokuPlayer[GomokuPlayer["Black"] = 1] = "Black";
GomokuPlayer[GomokuPlayer["White"] = 2] = "White";
})(GomokuPlayer || (GomokuPlayer = {}));
/**
* 改变当前玩家, 返回新玩家
* @param {Player} player 当前玩家
* @return {Player} 新玩家
*/
function changePlayer(player) {
if (player == GomokuPlayer.Black) {
return GomokuPlayer.White;
}
else {
return GomokuPlayer.Black;
}
}
//# sourceMappingURL=Player.js.map
\ No newline at end of file
{"version":3,"file":"Player.js","sourceRoot":"","sources":["../../src/Models/Player.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,IAAK,YAGJ;AAHD,WAAK,YAAY;IACb,iDAAS,CAAA;IACT,iDAAS,CAAA;AACb,CAAC,EAHI,YAAY,KAAZ,YAAY,QAGhB;AAED;;;;GAIG;AACH,sBAAsB,MAAoB;IACtC,EAAE,CAAC,CAAC,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,YAAY,CAAC,KAAK,CAAA;IAC7B,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,YAAY,CAAC,KAAK,CAAA;IAC7B,CAAC;AACL,CAAC"}
\ No newline at end of file
var default_1 = (function () {
function default_1() {
}
return default_1;
}());
//# sourceMappingURL=ButtonWithText.js.map
\ No newline at end of file
{"version":3,"file":"ButtonWithText.js","sourceRoot":"","sources":["../../src/Shapes/ButtonWithText.ts"],"names":[],"mappings":"AAAA;IAAA;IAAM,CAAC,AAAF;IAAC,gBAAC;AAAD,CAAC,AAAF,AAAL,IAAK"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 棋子图形:
* 一个圆
*/
var ChessShape = (function (_super) {
__extends(ChessShape, _super);
function ChessShape(style, centerX, centerY) {
var _this = _super.call(this, centerX, centerY, style.radius) || this;
_this.borderWidth = style.borderWidth;
_this.borderColor = style.borderColor;
_this.fill = true;
_this.fillColor = style.fillColor;
return _this;
}
ChessShape.prototype.drawOn = function (ctx) {
_super.prototype.drawOn.call(this, ctx);
};
return ChessShape;
}(Circle));
//# sourceMappingURL=ChessShape.js.map
\ No newline at end of file
{"version":3,"file":"ChessShape.js","sourceRoot":"","sources":["../../src/Shapes/ChessShape.ts"],"names":[],"mappings":";;;;;AAUA;;;GAGG;AACH;IAAyB,8BAAM;IAC3B,oBAAY,KAAoB,EAAE,OAAe,EAAE,OAAe;QAAlE,YACI,kBAAM,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,SAKxC;QAJG,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,KAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;;IACpC,CAAC;IAED,2BAAM,GAAN,UAAO,GAA6B;QAChC,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IACL,iBAAC;AAAD,CAAC,AAZD,CAAyB,MAAM,GAY9B"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 棋盘图形:(一个方形)
* 标准的 15x15 的五子棋棋盘
*
* 棋盘样式由一个 ChessboardStyle 对象指定
*/
var ChessboardShape = (function (_super) {
__extends(ChessboardShape, _super);
function ChessboardShape(style, width, height) {
var _this =
//边框
_super.call(this, style.originX, style.originY, width, height) || this;
_this.numberOfHorizontalLines = 15;
_this.numberOfVerticalLines = 15;
_this.borderWidth = style.borderWidth;
_this.borderColor = style.borderColor;
_this.fillColor = style.backgroudColor;
//线
_this.horizontalLines = [];
_this.verticalLines = [];
var hOffSet = (_this.width / (_this.numberOfHorizontalLines + 1));
for (var i = 0; i < _this.numberOfHorizontalLines; i++) {
var Y = _this.originY + (i + 1) * hOffSet;
var hline = new Line(_this.originX + hOffSet, Y, _this.endX - hOffSet, Y);
hline.lineWidth = style.lineWidth;
hline.strokeColor = style.lineColor;
_this.horizontalLines.push(hline);
}
var vOffSet = (_this.height / (_this.numberOfVerticalLines + 1));
for (var j = 0; j < _this.numberOfVerticalLines; j++) {
var X = _this.originX + (j + 1) * vOffSet;
var vline = new Line(X, _this.originY + vOffSet, X, _this.endY - vOffSet);
vline.lineWidth = style.lineWidth;
vline.strokeColor = style.lineColor;
_this.verticalLines.push(vline);
}
return _this;
}
ChessboardShape.prototype.drawOn = function (ctx) {
ctx.save();
this.fill = true;
_super.prototype.drawOn.call(this, ctx);
for (var i = 0; i < this.numberOfHorizontalLines; i++) {
this.horizontalLines[i].drawOn(ctx);
}
for (var j = 0; j < this.numberOfVerticalLines; j++) {
this.verticalLines[j].drawOn(ctx);
}
ctx.restore();
};
return ChessboardShape;
}(Rectangle));
//# sourceMappingURL=ChessboardShape.js.map
\ No newline at end of file
{"version":3,"file":"ChessboardShape.js","sourceRoot":"","sources":["../../src/Shapes/ChessboardShape.ts"],"names":[],"mappings":";;;;;AAYA;;;;;GAKG;AACH;IAA8B,mCAAS;IAMnC,yBAAY,KAAsB,EAAE,KAAa,EAAE,MAAc;QAAjE;QACI,IAAI;QACJ,kBAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,SAuBrD;QA9BQ,6BAAuB,GAAG,EAAE,CAAA;QAC5B,2BAAqB,GAAG,EAAE,CAAA;QAO/B,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,SAAS,GAAG,KAAK,CAAC,cAAc,CAAA;QACrC,GAAG;QACH,KAAI,CAAC,eAAe,GAAG,EAAE,CAAA;QACzB,KAAI,CAAC,aAAa,GAAG,EAAE,CAAA;QACvB,IAAI,OAAO,GAAG,CAAC,KAAI,CAAC,KAAK,GAAG,CAAC,KAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC,CAAC,CAAA;QAC/D,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,uBAAuB,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,GAAG,KAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAA;YACxC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,KAAI,CAAC,OAAO,GAAG,OAAO,EAAE,CAAC,EAAE,KAAI,CAAC,IAAI,GAAG,OAAO,EAAG,CAAC,CAAC,CAAA;YACxE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;YACjC,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,CAAA;YACnC,KAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpC,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,KAAI,CAAC,MAAM,GAAG,CAAC,KAAI,CAAC,qBAAqB,GAAG,CAAC,CAAC,CAAC,CAAA;QAC9D,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,KAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAA;YACxC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,KAAI,CAAC,OAAO,GAAG,OAAO,EAAE,CAAC,EAAG,KAAI,CAAC,IAAI,GAAG,OAAO,CAAC,CAAA;YACxE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;YACjC,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,CAAA;YACnC,KAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,CAAC;;IACL,CAAC;IAED,gCAAM,GAAN,UAAO,GAA6B;QAChC,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;QACjB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACvC,CAAC;QACD,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACrC,CAAC;QACD,GAAG,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;IACL,sBAAC;AAAD,CAAC,AA7CD,CAA8B,SAAS,GA6CtC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 棋子图形:
* 一个圆
*/
var ChessmanShape = (function (_super) {
__extends(ChessmanShape, _super);
function ChessmanShape(style, centerX, centerY) {
var _this = _super.call(this, centerX, centerY, style.radius) || this;
_this.borderWidth = style.borderWidth;
_this.borderColor = style.borderColor;
_this.fill = true;
_this.fillColor = style.fillColor;
return _this;
}
ChessmanShape.prototype.drawOn = function (ctx) {
_super.prototype.drawOn.call(this, ctx);
};
return ChessmanShape;
}(Circle));
//# sourceMappingURL=ChessmanShape.js.map
\ No newline at end of file
{"version":3,"file":"ChessmanShape.js","sourceRoot":"","sources":["../../src/Shapes/ChessmanShape.ts"],"names":[],"mappings":";;;;;AAUA;;;GAGG;AACH;IAA4B,iCAAM;IAC9B,uBAAY,KAAoB,EAAE,OAAe,EAAE,OAAe;QAAlE,YACI,kBAAM,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,SAKxC;QAJG,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;QACpC,KAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,KAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;;IACpC,CAAC;IAED,8BAAM,GAAN,UAAO,GAA6B;QAChC,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IACL,oBAAC;AAAD,CAAC,AAZD,CAA4B,MAAM,GAYjC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 圆:
* 一个圆由中心点(centerX, centerY)和半径(radius)所确定
*
* 样式:
* borderWidth、borderColor
*/
var Circle = (function (_super) {
__extends(Circle, _super);
function Circle(centerX, centerY, radius, arc) {
var _this = _super.call(this, centerX, centerY) || this;
_this.fill = false;
_this.radius = radius;
if (arc) {
_this.arc = arc;
}
return _this;
}
Object.defineProperty(Circle.prototype, "centerX", {
get: function () {
return this.originX;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Circle.prototype, "centerY", {
get: function () {
return this.originY;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Circle.prototype, "borderColor", {
get: function () {
return this.strokeColor;
},
set: function (color) {
this.strokeColor = color;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Circle.prototype, "borderWidth", {
get: function () {
return this.lineWidth;
},
set: function (width) {
this.lineWidth = width;
},
enumerable: true,
configurable: true
});
Circle.prototype.drawOn = function (ctx) {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = this.strokeColor;
ctx.lineWidth = this.lineWidth;
if (this.arc) {
ctx.arc(this.centerX, this.centerY, this.radius, this.arc.radian1, this.arc.radian2);
}
else {
ctx.arc(this.centerX, this.centerY, this.radius, 0, 2 * Math.PI);
}
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fill();
}
ctx.stroke();
ctx.restore();
};
return Circle;
}(Shape));
//# sourceMappingURL=Circle.js.map
\ No newline at end of file
{"version":3,"file":"Circle.js","sourceRoot":"","sources":["../../src/Shapes/Circle.ts"],"names":[],"mappings":";;;;;AAKA;;;;;;GAMG;AACH;IAAqB,0BAAK;IAsBtB,gBAAY,OAAe,EAAE,OAAe,EAAE,MAAc,EAAE,GAAS;QAAvE,YACI,kBAAM,OAAO,EAAE,OAAO,CAAC,SAK1B;QA1BD,UAAI,GAAY,KAAK,CAAA;QAsBjB,KAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACN,KAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QAClB,CAAC;;IACL,CAAC;IAxBD,sBAAI,2BAAO;aAAX;YACI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAA;QACvB,CAAC;;;OAAA;IACD,sBAAI,2BAAO;aAAX;YACI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAA;QACvB,CAAC;;;OAAA;IACD,sBAAI,+BAAW;aAAf;YACI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAA;QAC3B,CAAC;aACD,UAAgB,KAAa;YACzB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QAC5B,CAAC;;;OAHA;IAID,sBAAI,+BAAW;aAAf;YACI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAA;QACzB,CAAC;aACD,UAAgB,KAAa;YACzB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;QAC1B,CAAC;;;OAHA;IAYD,uBAAM,GAAN,UAAO,GAA6B;QAChC,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QAClC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC9B,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YACX,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACxF,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACZ,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;YAC9B,GAAG,CAAC,IAAI,EAAE,CAAA;QACd,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,CAAA;QACZ,GAAG,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;IACL,aAAC;AAAD,CAAC,AA/CD,CAAqB,KAAK,GA+CzB"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 线:
* 一条线由起始坐标(fromX, fromY)和目标坐标(toX, toY)所确定
*
* 样式:
* lineWidth、lineColor
*/
var Line = (function (_super) {
__extends(Line, _super);
function Line(fromX, fromY, toX, toY) {
var _this = _super.call(this, fromX, fromY) || this;
_this.toX = toX;
_this.toY = toY;
return _this;
}
Object.defineProperty(Line.prototype, "fromX", {
get: function () {
return this.originX;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Line.prototype, "fromY", {
get: function () {
return this.originY;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Line.prototype, "lineColor", {
get: function () {
return this.strokeColor;
},
set: function (color) {
this.strokeColor = color;
},
enumerable: true,
configurable: true
});
Line.prototype.drawOn = function (ctx) {
ctx.save();
ctx.beginPath();
ctx.moveTo(this.fromX, this.fromY);
ctx.lineTo(this.toX, this.toY);
ctx.strokeStyle = this.lineColor;
ctx.lineWidth = this.lineWidth;
ctx.stroke();
ctx.restore();
};
return Line;
}(Shape));
//# sourceMappingURL=Line.js.map
\ No newline at end of file
{"version":3,"file":"Line.js","sourceRoot":"","sources":["../../src/Shapes/Line.ts"],"names":[],"mappings":";;;;;AAAA;;;;;;GAMG;AACH;IAAmB,wBAAK;IAgBpB,cAAY,KAAa,EAAE,KAAa,EAAE,GAAW,EAAE,GAAW;QAAlE,YACI,kBAAM,KAAK,EAAE,KAAK,CAAC,SAGtB;QAFG,KAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,KAAI,CAAC,GAAG,GAAG,GAAG,CAAA;;IAClB,CAAC;IAjBD,sBAAI,uBAAK;aAAT;YACI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAA;QACvB,CAAC;;;OAAA;IACD,sBAAI,uBAAK;aAAT;YACI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAA;QACvB,CAAC;;;OAAA;IACD,sBAAI,2BAAS;aAAb;YACI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAA;QAC3B,CAAC;aACD,UAAc,KAAa;YACvB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QAC5B,CAAC;;;OAHA;IAWD,qBAAM,GAAN,UAAO,GAA6B;QAChC,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;QAC9B,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,SAAS,CAAA;QAChC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC9B,GAAG,CAAC,MAAM,EAAE,CAAA;QACZ,GAAG,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;IACL,WAAC;AAAD,CAAC,AAhCD,CAAmB,KAAK,GAgCvB"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 长方形:
* 一个长方形由起始坐标(originX, originY)和宽(width)高(height)所确定
*
* 样式:
* borderWidth、borderColor
*/
var Rectangle = (function (_super) {
__extends(Rectangle, _super);
function Rectangle(originX, originY, width, height) {
var _this = _super.call(this, originX, originY) || this;
_this.fill = false;
_this.width = width;
_this.height = height;
return _this;
}
Object.defineProperty(Rectangle.prototype, "borderColor", {
get: function () {
return this.strokeColor;
},
set: function (color) {
this.strokeColor = color;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "borderWidth", {
get: function () {
return this.lineWidth;
},
set: function (width) {
this.lineWidth = width;
},
enumerable: true,
configurable: true
});
Rectangle.prototype.drawOn = function (ctx) {
ctx.save();
ctx.strokeStyle = this.strokeColor;
ctx.lineWidth = this.lineWidth;
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fillRect(this.originX, this.originY, this.width, this.height);
}
ctx.strokeRect(this.originX, this.originY, this.width, this.height);
ctx.restore();
};
Object.defineProperty(Rectangle.prototype, "minX", {
get: function () {
return Math.min(this.originX, this.originX + this.width);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "minY", {
get: function () {
return Math.min(this.originY, this.originY + this.height);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "maxX", {
get: function () {
return Math.max(this.originX, this.originX + this.width);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "maxY", {
get: function () {
return Math.max(this.originY, this.originY + this.height);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "midX", {
get: function () {
return ((this.originX + this.width) / 2);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "midY", {
get: function () {
return ((this.originY + this.height) / 2);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "endX", {
get: function () {
return this.originX + this.width;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "endY", {
get: function () {
return this.originY + this.height;
},
enumerable: true,
configurable: true
});
return Rectangle;
}(Shape));
//# sourceMappingURL=Rectangle.js.map
\ No newline at end of file
{"version":3,"file":"Rectangle.js","sourceRoot":"","sources":["../../src/Shapes/Rectangle.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* 所有用于在 Canvas 绘制的图形继承自该类
*/
var Shape = (function () {
function Shape(originX, originY) {
this.originX = originX;
this.originY = originY;
this.lineWidth = Shape.DefaultLineWidth;
this.strokeColor = Shape.DefaultLineColor;
this.fillColor = Shape.DefualtFillColor;
}
return Shape;
}());
Shape.DefaultLineWidth = 1;
Shape.DefaultLineColor = "black";
Shape.DefualtFillColor = "white";
//# sourceMappingURL=Shape.js.map
\ No newline at end of file
{"version":3,"file":"Shape.js","sourceRoot":"","sources":["../../src/Shapes/Shape.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;IAYI,eAAY,OAAe,EAAE,OAAe;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,gBAAgB,CAAA;QACvC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAA;QACzC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,gBAAgB,CAAA;IAC3C,CAAC;IAML,YAAC;AAAD,CAAC,AAxBD;AACW,sBAAgB,GAAG,CAAC,CAAA;AACpB,sBAAgB,GAAG,OAAO,CAAA;AAC1B,sBAAgB,GAAG,OAAO,CAAA"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 中间有数字的圆形
*/
var TextCircle = (function (_super) {
__extends(TextCircle, _super);
function TextCircle() {
return _super !== null && _super.apply(this, arguments) || this;
}
return TextCircle;
}(Circle));
//# sourceMappingURL=TextButton.js.map
\ No newline at end of file
{"version":3,"file":"TextButton.js","sourceRoot":"","sources":["../../src/Shapes/TextButton.ts"],"names":[],"mappings":";;;;;AAAA;;GAEG;AACH;IAAyB,8BAAM;IAA/B;;IAEA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAFD,CAAyB,MAAM,GAE9B"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 中间有字的圆形
* (仅容纳一个字符)
*/
var TextCircle = (function (_super) {
__extends(TextCircle, _super);
function TextCircle(centerX, centerY, radius, x) {
var _this = _super.call(this, centerX, centerY, radius) || this;
_this.yOffset = radius / 2.5;
_this.number = x;
return _this;
}
Object.defineProperty(TextCircle.prototype, "number", {
set: function (x) {
this.text = new TextShape("" + x, this.centerX, this.centerY + this.yOffset, true);
this.text.fillColor = "black";
this.text.strokeColor = "black";
},
enumerable: true,
configurable: true
});
TextCircle.prototype.drawOn = function (ctx) {
_super.prototype.drawOn.call(this, ctx);
this.text.drawOn(ctx);
};
return TextCircle;
}(Circle));
//# sourceMappingURL=TextCircle.js.map
\ No newline at end of file
{"version":3,"file":"TextCircle.js","sourceRoot":"","sources":["../../src/Shapes/TextCircle.ts"],"names":[],"mappings":";;;;;AAAA;;;GAGG;AACH;IAAyB,8BAAM;IAW3B,oBAAY,OAAe,EAAE,OAAe,EAAE,MAAc,EAAE,CAAS;QAAvE,YACI,kBAAM,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,SAGlC;QAFG,KAAI,CAAC,OAAO,GAAG,MAAM,GAAG,GAAG,CAAA;QAC3B,KAAI,CAAC,MAAM,GAAG,CAAC,CAAA;;IACnB,CAAC;IAVD,sBAAI,8BAAM;aAAV,UAAW,CAAS;YAChB,IAAI,CAAC,IAAI,GAAG,IAAI,SAAS,CAAC,KAAG,CAAG,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;YAClF,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAA;YAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAA;QACnC,CAAC;;;OAAA;IAQD,2BAAM,GAAN,UAAO,GAA6B;QAChC,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IACL,iBAAC;AAAD,CAAC,AArBD,CAAyB,MAAM,GAqB9B"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 字体形状
*/
var TextShape = (function (_super) {
__extends(TextShape, _super);
function TextShape(content, orginX, originY, fill) {
if (fill === void 0) { fill = false; }
var _this = _super.call(this, orginX, originY) || this;
_this.font = "25px sans-serif";
_this.maxWidth = 300;
_this.content = content;
_this.fill = fill;
_this.strokeColor = "grey";
_this.fillColor = "grey";
return _this;
}
TextShape.prototype.drawOn = function (ctx) {
ctx.save();
ctx.textAlign = "center";
ctx.font = this.font;
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fillText(this.content, this.originX, this.originY, this.maxWidth);
}
ctx.strokeStyle = this.strokeColor;
ctx.strokeText(this.content, this.originX, this.originY, this.maxWidth);
ctx.restore();
};
return TextShape;
}(Shape));
//# sourceMappingURL=TextShape.js.map
\ No newline at end of file
{"version":3,"file":"TextShape.js","sourceRoot":"","sources":["../../src/Shapes/TextShape.ts"],"names":[],"mappings":";;;;;AAAA;;GAEG;AACH;IAAwB,6BAAK;IAKzB,mBAAY,OAAe,EAAE,MAAc,EAAE,OAAe,EAAE,IAAY;QAAZ,qBAAA,EAAA,YAAY;QAA1E,YACI,kBAAM,MAAM,EAAE,OAAO,CAAC,SAKzB;QARD,UAAI,GAAW,iBAAiB,CAAA;QAChC,cAAQ,GAAW,GAAG,CAAA;QAGlB,KAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,KAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,KAAI,CAAC,WAAW,GAAG,MAAM,CAAA;QACzB,KAAI,CAAC,SAAS,GAAG,MAAM,CAAA;;IAC3B,CAAC;IAED,0BAAM,GAAN,UAAO,GAA6B;QAChC,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAA;QACxB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACpB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACZ,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;YAC9B,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QACzE,CAAC;QACD,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QAClC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QACvE,GAAG,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;IACL,gBAAC;AAAD,CAAC,AAzBD,CAAwB,KAAK,GAyB5B"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 由两个半圆拼成的圆形
*/
var TwoHalfCircle = (function (_super) {
__extends(TwoHalfCircle, _super);
function TwoHalfCircle(centerX, centerY, radius, leftColor, rightColor) {
var _this = _super.call(this, centerX, centerY, radius) || this;
_this.leftHalfCircle =
new Circle(_this.centerX, _this.centerY, _this.radius, {
radian1: Math.PI / 4 * 3,
radian2: Math.PI / 4 * 7
});
_this.rightHalfCircle =
new Circle(_this.centerX, _this.centerY, _this.radius, {
radian1: Math.PI / 4 * 7,
radian2: Math.PI / 4 * 3,
});
_this.leftHalfCircle.lineWidth = 0.1;
_this.leftHalfCircle.fill = true;
_this.leftHalfCircle.fillColor = leftColor;
_this.rightHalfCircle.lineWidth = 0.1;
_this.rightHalfCircle.fill = true;
_this.rightHalfCircle.fillColor = rightColor;
return _this;
}
TwoHalfCircle.prototype.drawOn = function (ctx) {
_super.prototype.drawOn.call(this, ctx);
this.leftHalfCircle.drawOn(ctx);
this.rightHalfCircle.drawOn(ctx);
};
return TwoHalfCircle;
}(Circle));
//# sourceMappingURL=TwoHalfButton.js.map
\ No newline at end of file
{"version":3,"file":"TwoHalfButton.js","sourceRoot":"","sources":["../../src/Shapes/TwoHalfButton.ts"],"names":[],"mappings":";;;;;AAAA;;GAEG;AACH;IAA4B,iCAAM;IAI9B,uBAAY,OAAe,EAAE,OAAe,EAAE,MAAc,EAChD,SAAiB,EAAE,UAAkB;QADjD,YAEI,kBAAM,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,SAiBlC;QAhBG,KAAI,CAAC,cAAc;YACf,IAAI,MAAM,CAAC,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,MAAM,EAAE;gBAChD,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;gBACxB,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;aAC3B,CAAC,CAAA;QACN,KAAI,CAAC,eAAe;YAChB,IAAI,MAAM,CAAC,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,MAAM,EAAE;gBAChD,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;gBACxB,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;aAC3B,CAAC,CAAA;QACN,KAAI,CAAC,cAAc,CAAC,SAAS,GAAG,GAAG,CAAA;QACnC,KAAI,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAA;QAC/B,KAAI,CAAC,cAAc,CAAC,SAAS,GAAG,SAAS,CAAA;QACzC,KAAI,CAAC,eAAe,CAAC,SAAS,GAAG,GAAG,CAAA;QACpC,KAAI,CAAC,eAAe,CAAC,IAAI,GAAG,IAAI,CAAA;QAChC,KAAI,CAAC,eAAe,CAAC,SAAS,GAAG,UAAU,CAAA;;IAC/C,CAAC;IAED,8BAAM,GAAN,UAAO,GAA6B;QAChC,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IACL,oBAAC;AAAD,CAAC,AA9BD,CAA4B,MAAM,GA8BjC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 由两个半圆拼成的圆形
*/
var TwoHalfCircle = (function (_super) {
__extends(TwoHalfCircle, _super);
function TwoHalfCircle(centerX, centerY, radius, leftColor, rightColor) {
var _this = _super.call(this, centerX, centerY, radius) || this;
_this.leftHalfCircle =
new Circle(_this.centerX, _this.centerY, _this.radius, {
radian1: Math.PI / 4 * 3,
radian2: Math.PI / 4 * 7
});
_this.rightHalfCircle =
new Circle(_this.centerX, _this.centerY, _this.radius, {
radian1: Math.PI / 4 * 7,
radian2: Math.PI / 4 * 3,
});
_this.leftHalfCircle.lineWidth = 0.1;
_this.leftHalfCircle.fill = true;
_this.leftHalfCircle.fillColor = leftColor;
_this.rightHalfCircle.lineWidth = 0.1;
_this.rightHalfCircle.fill = true;
_this.rightHalfCircle.fillColor = rightColor;
return _this;
}
TwoHalfCircle.prototype.drawOn = function (ctx) {
_super.prototype.drawOn.call(this, ctx);
this.leftHalfCircle.drawOn(ctx);
this.rightHalfCircle.drawOn(ctx);
};
return TwoHalfCircle;
}(Circle));
//# sourceMappingURL=TwoHalfCircle.js.map
\ No newline at end of file
{"version":3,"file":"TwoHalfCircle.js","sourceRoot":"","sources":["../../src/Shapes/TwoHalfCircle.ts"],"names":[],"mappings":";;;;;AAAA;;GAEG;AACH;IAA4B,iCAAM;IAI9B,uBAAY,OAAe,EAAE,OAAe,EAAE,MAAc,EAChD,SAAiB,EAAE,UAAkB;QADjD,YAEI,kBAAM,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,SAiBlC;QAhBG,KAAI,CAAC,cAAc;YACf,IAAI,MAAM,CAAC,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,MAAM,EAAE;gBAChD,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;gBACxB,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;aAC3B,CAAC,CAAA;QACN,KAAI,CAAC,eAAe;YAChB,IAAI,MAAM,CAAC,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,OAAO,EAAE,KAAI,CAAC,MAAM,EAAE;gBAChD,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;gBACxB,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;aAC3B,CAAC,CAAA;QACN,KAAI,CAAC,cAAc,CAAC,SAAS,GAAG,GAAG,CAAA;QACnC,KAAI,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAA;QAC/B,KAAI,CAAC,cAAc,CAAC,SAAS,GAAG,SAAS,CAAA;QACzC,KAAI,CAAC,eAAe,CAAC,SAAS,GAAG,GAAG,CAAA;QACpC,KAAI,CAAC,eAAe,CAAC,IAAI,GAAG,IAAI,CAAA;QAChC,KAAI,CAAC,eAAe,CAAC,SAAS,GAAG,UAAU,CAAA;;IAC/C,CAAC;IAED,8BAAM,GAAN,UAAO,GAA6B;QAChC,iBAAM,MAAM,YAAC,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IACL,oBAAC;AAAD,CAAC,AA9BD,CAA4B,MAAM,GA8BjC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var DefaultTheme = (function (_super) {
__extends(DefaultTheme, _super);
function DefaultTheme() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.chessboardStyle = {
originX: 0,
originY: 0,
lineWidth: 1,
lineColor: "black",
borderWidth: 0.5,
borderColor: "black",
backgroudColor: "white"
};
_this.blackChessStyle = {
radius: 13,
borderWidth: 1,
borderColor: "rgb(210,210,210)",
fillColor: "black"
};
_this.whiteChessStyle = {
radius: 13,
borderWidth: 1,
borderColor: "black",
fillColor: "white"
};
return _this;
}
return DefaultTheme;
}(Theme));
//# sourceMappingURL=DefaultTheme.js.map
\ No newline at end of file
{"version":3,"file":"DefaultTheme.js","sourceRoot":"","sources":["../../src/Themes/DefaultTheme.ts"],"names":[],"mappings":";;;;;AAAA;IAA2B,gCAAK;IAAhC;QAAA,qEAyBC;QAvBY,qBAAe,GAAoB;YACxC,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,OAAO;YAClB,WAAW,EAAE,GAAG;YAChB,WAAW,EAAE,OAAO;YACpB,cAAc,EAAE,OAAO;SAC1B,CAAA;QAEQ,qBAAe,GAAkB;YACtC,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,kBAAkB;YAC/B,SAAS,EAAE,OAAO;SACrB,CAAA;QAEQ,qBAAe,GAAkB;YACtC,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,OAAO;YACpB,SAAS,EAAE,OAAO;SACrB,CAAA;;IACL,CAAC;IAAD,mBAAC;AAAD,CAAC,AAzBD,CAA2B,KAAK,GAyB/B"}
\ No newline at end of file
var Theme = (function () {
function Theme() {
}
return Theme;
}());
//# sourceMappingURL=Theme.js.map
\ No newline at end of file
{"version":3,"file":"Theme.js","sourceRoot":"","sources":["../../src/Themes/Theme.ts"],"names":[],"mappings":"AAAA;IAAA;IAIA,CAAC;IAAD,YAAC;AAAD,CAAC,AAJD,IAIC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var VividTheme = (function (_super) {
__extends(VividTheme, _super);
function VividTheme() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.chessboardStyle = {
originX: 0,
originY: 0,
lineWidth: 1,
lineColor: "black",
borderWidth: 0.5,
borderColor: "black",
backgroudColor: "white"
};
_this.blackChessStyle = {
radius: 13,
borderWidth: 0.5,
borderColor: "grey",
fillColor: "rgb(30,157,255)"
};
_this.whiteChessStyle = {
radius: 13,
borderWidth: 0.5,
borderColor: "grey",
fillColor: "rgb(225,233,243)"
};
return _this;
}
return VividTheme;
}(Theme));
//# sourceMappingURL=VividTheme.js.map
\ No newline at end of file
{"version":3,"file":"VividTheme.js","sourceRoot":"","sources":["../../src/Themes/VividTheme.ts"],"names":[],"mappings":";;;;;AAAA;IAAyB,8BAAK;IAA9B;QAAA,qEAwBC;QAvBY,qBAAe,GAAoB;YACxC,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,OAAO;YAClB,WAAW,EAAE,GAAG;YAChB,WAAW,EAAE,OAAO;YACpB,cAAc,EAAE,OAAO;SAC1B,CAAA;QAEQ,qBAAe,GAAkB;YACtC,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,GAAG;YAChB,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,iBAAiB;SAC/B,CAAA;QAEQ,qBAAe,GAAkB;YACtC,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,GAAG;YAChB,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,kBAAkB;SAChC,CAAA;;IACL,CAAC;IAAD,iBAAC;AAAD,CAAC,AAxBD,CAAyB,KAAK,GAwB7B"}
\ No newline at end of file
/**
* 集成 Canvas 元素的视图类
*/
var AbstractCanvasView = (function () {
function AbstractCanvasView(width, height, id) {
this.canvas = document.getElementById(id);
this.context = this.canvas.getContext("2d");
this.canvas.width = width;
this.canvas.height = height;
}
AbstractCanvasView.prototype.addEventListener = function (event, callback) {
this.canvas.addEventListener(event, callback);
};
Object.defineProperty(AbstractCanvasView.prototype, "midX", {
get: function () {
return this.canvas.width / 2;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractCanvasView.prototype, "midY", {
get: function () {
return this.canvas.height / 2;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractCanvasView.prototype, "bound", {
/**
* 画布的边界对象
*/
get: function () {
return {
width: this.canvas.width,
height: this.canvas.height
};
},
enumerable: true,
configurable: true
});
return AbstractCanvasView;
}());
//# sourceMappingURL=CanvasView.js.map
\ No newline at end of file
{"version":3,"file":"CanvasView.js","sourceRoot":"","sources":["../../src/Views/CanvasView.ts"],"names":[],"mappings":"AAcA;;GAEG;AACH;IAcI,4BAAY,KAAa,EAAE,MAAc,EAAE,EAAU;QACjD,IAAI,CAAC,MAAM,GAAsB,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,OAAO,GAA6B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACrE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;QACzB,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;IAC/B,CAAC;IATD,6CAAgB,GAAhB,UAAiB,KAAa,EAAE,QAA4B;QACxD,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACjD,CAAC;IASD,sBAAc,oCAAI;aAAlB;YACI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAA;QAChC,CAAC;;;OAAA;IACD,sBAAc,oCAAI;aAAlB;YACI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;QACjC,CAAC;;;OAAA;IAKD,sBAAI,qCAAK;QAHT;;WAEG;aACH;YACI,MAAM,CAAC;gBACH,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBACxB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;aAC7B,CAAA;QACL,CAAC;;;OAAA;IAEL,yBAAC;AAAD,CAAC,AAtCD,IAsCC"}
\ No newline at end of file
/**
* 包装了一个 Bootstrap 模态对话框的视图
* 该对话框专用于显示历史记录与实现用户点击复盘
*/
var DialogView = (function () {
function DialogView() {
this.DialogID = "modal";
this.HeaderID = "modal-header";
this.BodyID = "modal-body";
this.ListID = "history-list";
this.FooterID = "modal-footer";
this.dialog = document.getElementById(this.DialogID);
this.header = document.getElementById(this.HeaderID);
this.body = document.getElementById(this.BodyID);
this.list = document.getElementById(this.ListID);
this.footer = document.getElementById(this.FooterID);
}
/**
* 显示对话框
*/
DialogView.prototype.show = function () {
$("#" + this.DialogID)["modal"]("show");
};
/**
* 隐藏对话框
*/
DialogView.prototype.hide = function () {
$("#" + this.DialogID)["modal"]("hide");
};
DialogView.prototype.toggle = function () {
$("#" + this.DialogID)["modal"]("toggle");
};
DialogView.prototype.addItem = function (content) {
var newNode = document.createElement("li");
newNode.classList.add("list-group-item");
newNode.textContent = content;
this.list.appendChild(newNode);
};
return DialogView;
}());
//# sourceMappingURL=DialogView.js.map
\ No newline at end of file
{"version":3,"file":"DialogView.js","sourceRoot":"","sources":["../../src/Views/DialogView.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAqCI;QApCiB,aAAQ,GAAG,OAAO,CAAA;QAClB,aAAQ,GAAG,cAAc,CAAA;QACzB,WAAM,GAAG,YAAY,CAAA;QACrB,WAAM,GAAG,cAAc,CAAA;QACvB,aAAQ,GAAG,cAAc,CAAA;QAiCtC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChD,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChD,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACxD,CAAC;IA/BD;;OAEG;IACI,yBAAI,GAAX;QACI,CAAC,CAAC,MAAI,IAAI,CAAC,QAAU,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IAC3C,CAAC;IAED;;OAEG;IACI,yBAAI,GAAX;QACI,CAAC,CAAC,MAAI,IAAI,CAAC,QAAU,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IAC3C,CAAC;IAEM,2BAAM,GAAb;QACI,CAAC,CAAC,MAAI,IAAI,CAAC,QAAU,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC7C,CAAC;IAEM,4BAAO,GAAd,UAAe,OAAe;QAC1B,IAAI,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QAC1C,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;QACxC,OAAO,CAAC,WAAW,GAAG,OAAO,CAAA;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC;IASL,iBAAC;AAAD,CAAC,AA5CD,IA4CC"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* 五子棋游戏 (MVC) 的 View 层
*/
var GomokuView = (function (_super) {
__extends(GomokuView, _super);
function GomokuView(width, height, viewController) {
var _this = _super.call(this, width, height, "game") || this;
_this.theme = new DefaultTheme();
_this.stepNumberFont = "15px menlo";
_this.viewController = viewController;
_this.drawChessboard();
_this.registerEvents();
return _this;
}
Object.defineProperty(GomokuView.prototype, "horizontalLineGap", {
get: function () {
return this.bound.height / 16;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GomokuView.prototype, "verticalLineGap", {
get: function () {
return this.bound.width / 16;
},
enumerable: true,
configurable: true
});
/**
* 在第i行第j列放置一个棋子 (无越界检查)
* @param {number} row 第i行(1 ~ 15)
* @param {number} col 第j列(1 ~ 15)
*/
GomokuView.prototype.putChessOn = function (row, col, chess) {
if (chess == Chess.None)
return;
var coord = this.getChessPosition(row, col);
var style = chess == Chess.Black ?
this.theme.blackChessStyle :
this.theme.whiteChessStyle;
new ChessShape({
radius: style.radius,
borderColor: style.borderColor,
borderWidth: style.borderWidth,
fillColor: style.fillColor
}, coord.x, coord.y).drawOn(this.context);
};
/**
* 重绘棋盘, 并保持棋局不变
*/
GomokuView.prototype.redrawChessboard = function (actions) {
this.drawChessboard();
for (var i = 0; i < actions.length; i++) {
this.putChessOn(actions[i].row, actions[i].col, chessOfPlayer(actions[i].player));
}
};
/**
* 在棋盘上绘制棋局的步数,把代表了步数的数字画在棋子上
* 数字的颜色取自当前主题
*/
GomokuView.prototype.drawSteps = function (steps) {
for (var i = 0; i < steps.length; i++) {
var num = "" + (i + 1);
var pos = this.getChessPosition(steps[i].row, steps[i].col);
var player = steps[i].player;
var yOffSet = this.horizontalLineGap / 5;
var stepNum = new TextShape(num, pos.x, pos.y + yOffSet, true);
stepNum.fillColor = (player == GomokuPlayer.White) ?
this.theme.blackChessStyle.fillColor :
this.theme.whiteChessStyle.fillColor;
stepNum.strokeColor = stepNum.fillColor;
stepNum.font = this.stepNumberFont;
stepNum.drawOn(this.context);
}
};
/**
* 获取第i行第j列的棋子的坐标 (无越界检查)
* @param {number} row 第i行(1 ~ 15)
* @param {number} col 第j列(1 ~ 15)
*/
GomokuView.prototype.getChessPosition = function (row, col) {
return {
x: this.theme.chessboardStyle.originY + col * (this.bound.height / 16),
y: this.theme.chessboardStyle.originX + row * (this.bound.width / 16)
};
};
/**
* 绘制棋盘
*/
GomokuView.prototype.drawChessboard = function () {
this.context.clearRect(0, 0, this.bound.width, this.bound.height);
new ChessboardShape(this.theme.chessboardStyle, this.bound.width, this.bound.height).drawOn(this.context);
};
/**
* 注册Canvas事件, 设置事件处理函数 (将事件交由Controller处理)
*
* 警告: 不能直接将控制器的方法作为闭包传入回调
* 这将导致控制器方法中的this指针指向canvas对象而不是控制器对象
*/
GomokuView.prototype.registerEvents = function () {
var _this = this;
this.addEventListener("click", function (event) {
_this.viewController.handleClickEvent(event.offsetX, event.offsetY);
});
};
return GomokuView;
}(AbstractCanvasView));
//# sourceMappingURL=GomokuView.js.map
\ No newline at end of file
{"version":3,"file":"GomokuView.js","sourceRoot":"","sources":["../../src/Views/GomokuView.ts"],"names":[],"mappings":";;;;;AAAA;;GAEG;AACH;IAAyB,8BAAkB;IAgBvC,oBAAY,KAAa,EAAE,MAAc,EAAE,cAAoC;QAA/E,YACI,kBAAM,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,SAI/B;QApBD,WAAK,GAAU,IAAI,YAAY,EAAE,CAAA;QACjC,oBAAc,GAAW,YAAY,CAAA;QAgBjC,KAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,KAAI,CAAC,cAAc,EAAE,CAAA;QACrB,KAAI,CAAC,cAAc,EAAE,CAAA;;IACzB,CAAC;IAjBD,sBAAI,yCAAiB;aAArB;YACI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAA;QACjC,CAAC;;;OAAA;IACD,sBAAI,uCAAe;aAAnB;YACI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAA;QAChC,CAAC;;;OAAA;IAcD;;;;OAIG;IACI,+BAAU,GAAjB,UAAkB,GAAW,EAAE,GAAW,EAAE,KAAY;QACpD,EAAE,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;YAAC,MAAM,CAAA;QAC/B,IAAI,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAC3C,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC,KAAK;YACpB,IAAI,CAAC,KAAK,CAAC,eAAe;YAC1B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAA;QACtC,IAAI,UAAU,CAAC;YACX,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,SAAS,EAAE,KAAK,CAAC,SAAS;SAC7B,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7C,CAAC;IAED;;OAEG;IACI,qCAAgB,GAAvB,UAAwB,OAAuB;QAC3C,IAAI,CAAC,cAAc,EAAE,CAAA;QACrB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACrF,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,8BAAS,GAAhB,UAAiB,KAAqB;QAClC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,GAAG,MAAG,CAAC,GAAG,CAAC,CAAE,CAAA;YACpB,IAAI,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAC3D,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;YAC5B,IAAI,OAAO,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAA;YACxC,IAAI,OAAO,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAA;YAC9D,OAAO,CAAC,SAAS,GAAG,CAAC,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC;gBAC9C,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,SAAS;gBACpC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,SAAS,CAAA;YACxC,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,SAAS,CAAA;YACvC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,CAAA;YAClC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAChC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,qCAAgB,GAAxB,UAAyB,GAAW,EAAE,GAAW;QAC7C,MAAM,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;YACtE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;SACxE,CAAA;IACL,CAAC;IAED;;OAEG;IACK,mCAAc,GAAtB;QACI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACjE,IAAI,eAAe,CACf,IAAI,CAAC,KAAK,CAAC,eAAe,EAC1B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CACtC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAED;;;;;OAKG;IACK,mCAAc,GAAtB;QAAA,iBAIC;QAHG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,KAAiB;YAC7C,KAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QACtE,CAAC,CAAC,CAAA;IACN,CAAC;IACL,iBAAC;AAAD,CAAC,AA1GD,CAAyB,kBAAkB,GA0G1C"}
\ No newline at end of file
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var MenuView = (function (_super) {
__extends(MenuView, _super);
function MenuView(width, height, viewController) {
var _this = _super.call(this, width, height, MenuView.MenuCanvasID) || this;
_this._chessCount = 0;
_this.viewController = viewController;
_this.buttonBoderWidth = 0.5;
_this.button1Alpha = MenuView.untouchedButtonAlpha;
_this.button2Alpha = MenuView.untouchedButtonAlpha;
_this.drawButtons();
_this._statusMessage = "";
_this.drawStatusBar();
_this.registerEvents();
return _this;
}
Object.defineProperty(MenuView.prototype, "statusMessage", {
get: function () {
return this._statusMessage;
},
set: function (s) {
this._statusMessage = s;
this.drawStatusBar();
},
enumerable: true,
configurable: true
});
Object.defineProperty(MenuView.prototype, "chessCount", {
get: function () {
return this._chessCount;
},
set: function (x) {
this._chessCount = x;
this.button3.number = this.chessCount;
this.redrawButton3();
},
enumerable: true,
configurable: true
});
/**
* 根据当前设定, 重绘 Menu 视图
*/
MenuView.prototype.redrawAll = function () {
this.drawButtons();
this.drawStatusBar();
};
/**
* (游戏开始时)初始化并绘制所有按钮
*/
MenuView.prototype.drawButtons = function () {
this.context.clearRect(0, 0, this.bound.width, this.bound.height / 2);
if (!this.buttonScale) {
this.buttonScale = 0.45;
}
this.buttonGap = this.bound.width / 4;
var centerX1 = this.buttonGap / 2;
var centerY = this.bound.height / 4;
var radius = Math.min(this.buttonGap / 2, this.bound.height / 4) * this.buttonScale;
this.button1 = new TwoHalfCircle(centerX1, centerY, radius, "white", "black");
this.button2 = new TwoHalfCircle(centerX1 + this.buttonGap, centerY, radius, "rgb(225,233,243)", "rgb(30,157,255)");
this.button3 = new TextCircle(centerX1 + this.buttonGap * 2, centerY, radius, 3);
this.button4 = new Circle(centerX1 + this.buttonGap * 3, centerY, radius);
this.button4.fill = true;
this.button4.fillColor = "grey";
this.button1.borderWidth = this.buttonBoderWidth;
this.button2.borderWidth = this.buttonBoderWidth;
this.button3.borderWidth = this.buttonBoderWidth;
this.button4.borderWidth = this.buttonBoderWidth;
this.context.save();
this.context.globalAlpha = MenuView.untouchedButtonAlpha;
this.button1.drawOn(this.context);
this.button2.drawOn(this.context);
this.button3.drawOn(this.context);
this.button4.drawOn(this.context);
this.context.restore();
};
MenuView.prototype.redrawButton1 = function () {
this.context.clearRect(0, 0, this.buttonGap, this.bound.height / 2);
this.context.save();
this.context.globalAlpha = this.button1Alpha;
this.button1.drawOn(this.context);
this.context.restore();
};
MenuView.prototype.redrawButton2 = function () {
this.context.clearRect(this.buttonGap, 0, this.buttonGap, this.bound.height / 2);
this.context.save();
this.context.globalAlpha = this.button2Alpha;
this.button2.drawOn(this.context);
this.context.restore();
};
MenuView.prototype.redrawButton3 = function () {
this.context.clearRect(this.buttonGap * 2, 0, this.buttonGap, this.bound.height / 2);
this.context.save();
this.context.globalAlpha = this.button3Alpha;
this.button3.drawOn(this.context);
this.context.restore();
};
MenuView.prototype.redrawButton4 = function () {
this.context.clearRect(this.buttonGap * 3, 0, this.buttonGap, this.bound.height / 2);
this.context.save();
this.context.globalAlpha = this.button4Alpha;
this.button4.drawOn(this.context);
this.context.restore();
};
/**
* 在状态栏绘制状态信息
*/
MenuView.prototype.drawStatusBar = function () {
this.context.clearRect(0, this.bound.height / 2, this.bound.width, this.bound.height / 2);
new TextShape(this._statusMessage, this.bound.width / 2, this.bound.height / 3 * 2, true)
.drawOn(this.context);
};
MenuView.prototype.registerEvents = function () {
var _this = this;
/**
* 点击菜单栏的按钮:交由控制器处理
*/
this.addEventListener("click", function (event) {
if (Math.pow(event.offsetX - _this.button1.centerX, 2) + Math.pow(event.offsetY - _this.button1.centerY, 2) < Math.pow(_this.button1.radius, 2)) {
_this.viewController.changeTheme(new DefaultTheme());
}
if (Math.pow(event.offsetX - _this.button2.centerX, 2) + Math.pow(event.offsetY - _this.button2.centerY, 2) < Math.pow(_this.button2.radius, 2)) {
_this.viewController.changeTheme(new VividTheme());
}
if (Math.pow(event.offsetX - _this.button3.centerX, 2) + Math.pow(event.offsetY - _this.button3.centerY, 2) < Math.pow(_this.button3.radius, 2)) {
if (_this.viewController.showChessStep) {
_this.viewController.showChessStep = false;
}
else {
_this.viewController.showChessStep = true;
}
}
if (Math.pow(event.offsetX - _this.button4.centerX, 2) + Math.pow(event.offsetY - _this.button4.centerY, 2) < Math.pow(_this.button4.radius, 2)) {
_this.viewController.toggleDialog();
}
});
/**
* 将鼠标移动到菜单栏按钮时改变透明度:由视图自行处理
* Todo: 每次鼠标移动都重绘是不合理的,应该设置一个额外变量 isInButton,使其仅在进按钮和出按钮时重绘
*/
this.addEventListener("mousemove", function (event) {
if (Math.pow(event.offsetX - _this.button1.centerX, 2) + Math.pow(event.offsetY - _this.button1.centerY, 2) < Math.pow(_this.button1.radius, 2)) {
_this.button1Alpha = MenuView.touchedButtonAlpha;
_this.redrawButton1();
}
else {
_this.button1Alpha = MenuView.untouchedButtonAlpha;
_this.redrawButton1();
}
if (Math.pow(event.offsetX - _this.button2.centerX, 2) + Math.pow(event.offsetY - _this.button2.centerY, 2) < Math.pow(_this.button2.radius, 2)) {
_this.button2Alpha = MenuView.touchedButtonAlpha;
_this.redrawButton2();
}
else {
_this.button2Alpha = MenuView.untouchedButtonAlpha;
_this.redrawButton2();
}
if (Math.pow(event.offsetX - _this.button3.centerX, 2) + Math.pow(event.offsetY - _this.button3.centerY, 2) < Math.pow(_this.button3.radius, 2)) {
_this.button3Alpha = MenuView.touchedButtonAlpha;
_this.redrawButton3();
}
else {
_this.button3Alpha = MenuView.untouchedButtonAlpha;
_this.redrawButton3();
}
if (Math.pow(event.offsetX - _this.button4.centerX, 2) + Math.pow(event.offsetY - _this.button4.centerY, 2) < Math.pow(_this.button4.radius, 2)) {
_this.button4Alpha = MenuView.touchedButtonAlpha;
_this.redrawButton4();
}
else {
_this.button4Alpha = MenuView.untouchedButtonAlpha;
_this.redrawButton4();
}
});
};
return MenuView;
}(AbstractCanvasView));
MenuView.MenuCanvasID = "menu";
MenuView.untouchedButtonAlpha = 0.5;
MenuView.touchedButtonAlpha = 1;
//# sourceMappingURL=MenuView.js.map
\ No newline at end of file
{"version":3,"file":"MenuView.js","sourceRoot":"","sources":["../../src/Views/MenuView.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
此差异已折叠。
{
"name": "2048",
"version": "1.0.0",
"description": "A small clone of [1024](https://play.google.com/store/apps/details?id=com.veewo.a1024), based on [Saming's 2048](http://saming.fr/p/2048/) (also a clone).",
"main": "index.js",
"name": "Gomoku",
"version": "0.9.0",
"description": "go-moku game",
"main": "index.html",
"scripts": {
"dev": "live-server"
"test": "echo \"Error: no test specified\" && exit 1",
"build": "./node_modules/.bin/live-server --port=5500"
},
"repository": {
"type": "git",
"url": "https://gitcode.net/cloud-ide/2048.git"
},
"author": "Aresn",
"keywords": [
"gomoku",
"game"
],
"author": "DongdongWang",
"license": "MIT",
"devDependencies": {
"@types/jquery": "^2.0.40",
"typescript": "^2.1.5"
},
"dependencies": {
"bootstrap": "^3.3.7",
"jquery": "^3.1.1",
"live-server": "^1.2.2"
}
}
......@@ -2,9 +2,9 @@
autoOpen: false # 打开工作空间时是否自动开启所有应用的预览
apps:
- port: 5500 # 应用的端口
run: npm i && npm run dev # 应用的启动命
run: npm i --registry=https://registry.npm.taobao.org && npm run build # 应用的启动命
command: # 使用此命令启动服务,且不执行run
root: ./ # 应用的启动目录
name: 2048 # 应用名称
name: t # 应用名称
description: 我的第一个 App。 # 应用描述
autoOpen: true # 打开工作空间时是否自动开启预览(优先级高于根级 autoOpen
/**
* 棋型收益估分(不可变)
*/
class AIScore {
/**立即获胜 */
static readonly WillWin = 1000
/**无法获胜(一定无法达成5连) */
static readonly WillFail = 0
static readonly Min = 0
static readonly Dangerous = 60
static readonly ooooo = 1000
static readonly oooo = 100
static readonly ooo = 40
static readonly Ioooo = 40
static readonly Iooo = 5
static readonly oo = 5
static readonly Ioo = 1
static readonly o = 0
static readonly Io = 0
static readonly ooo_oo = AIScore.ooo - 1
static readonly Iooo_oo = AIScore.Ioooo - 1
static readonly oo_oo = AIScore.ooo_oo
static readonly Ioo_oo = AIScore.Iooo_oo
static readonly o_oo = AIScore.ooo_oo
static readonly Io_oo = AIScore.Io + AIScore.oo
static readonly o_o = AIScore.o + AIScore.o
static readonly Io_o = AIScore.Io + AIScore.o
}
/**
* 棋型威胁估分(不可变)
*/
class AIRivalScore {
static readonly ooooo = 50
static readonly oooo = 50
static readonly ooo = 10
static readonly Ioooo = 10
static readonly Iooo = 3
static readonly oo = 3
static readonly Ioo = 1
static readonly o = 0
}
\ No newline at end of file
/**
* 五子棋人工智能棋手抽象类
* (在控制器中使用继承该类的子类)
*/
abstract class GomokuAI {
/**
* 规定 AI 执白子
*/
protected readonly player = GomokuPlayer.White
/**
* 分析对手的动作
*/
abstract analysAction(action: GomokuAction)
/**
* 给出下一次动作
*/
abstract getNextAction(): GomokuAction
}
\ No newline at end of file
function makeMatrix<T>(r: number, c: number, value: T): T[][] {
let matrix = new Array<T[]>(r)
for (let i = 0; i < r; i++)
matrix[i] = new Array<T>(c)
for (let i = 0; i < r; i++)
for (let j = 0; j < c; j++)
matrix[i][j] = value
return matrix
}
\ No newline at end of file
namespace AI {
/**状态类 */
export abstract class State {}
/**动作类(动作使一个状态转变为另一个状态) */
export abstract class Action {}
/**玩家类 */
export abstract class Player {}
/**游戏类(继承该类以描述一个游戏,使其能够利用minmax决策树) */
export abstract class Game {
abstract actions(state: State): Action[]
abstract result(state: State, action: Action): State
abstract utility(state: State, player: Player): number
abstract isTerminal(state: State): boolean
abstract toMove(state: State): Player
}
/**
* 对游戏和当前状态进行 minmax 决策
*/
export function minmaxDecision(state: State, game: Game) {
let player = game.toMove(state)
return maxValue(state)
function maxValue(state: State): number {
if (game.isTerminal(state)) {
return game.utility(state, player)
}
let value = -Infinity
let possibleActions = game.actions(state)
for (let action of possibleActions) {
value = Math.max(value, minValue(game.result(state, action)))
}
return value
}
function minValue(state: State): number {
if (game.isTerminal(state)) {
return game.utility(state, player)
}
let value = Infinity
let possibleActions = game.actions(state)
for (let action of possibleActions) {
value = Math.min(value, maxValue(game.result(state, action)))
}
return value
}
}
}//namespace AI
\ No newline at end of file
/**
* 测试AI_1:采用简单估分的方式进行决策
*/
class TestAI_1 extends GomokuAI {
next: GomokuAction
/**
* AI 自行维护一个棋盘
* 1: 己方棋子
* 0: 无棋子
* -1: 敌方棋子
*/
private chessboard: number[][]
private scores: number[][]
constructor() {
super()
this.chessboard = makeMatrix(15, 15, 0)
}
/**
* AI 先在中间落子
*/
putFirstChessInMiddle() {
this.chessboard[7][7] = 1
}
analysAction(action: GomokuAction) {
this.chessboard[action.row - 1][action.col - 1] = -1
//先防
//计算敌方下一步最高收益的落子
let rivalScores = makeMatrix(15, 15, -1)
for (let i = 0; i < 15; i++)
for (let j = 0; j < 15; j++)
if (this.chessboard[i][j] == 0) {
this.chessboard[i][j] = -1 //尝试落子
rivalScores[i][j] = this.computeScore(i, j, -1) //计算敌方收益
this.chessboard[i][j] = 0 //收回尝试
}
let rI = 0, rJ = 0
for (let i = 0; i < 15; i++)
for (let j = 0; j < 15; j++)
if (rivalScores[i][j] > rivalScores[rI][rJ]) {
rI = i
rJ = j
}
// 后攻
// 遍历每一个位置, 评估分数
this.scores = makeMatrix(15, 15, -1)
for (let i = 0; i < 15; i++)
for (let j = 0; j < 15; j++)
if (this.chessboard[i][j] == 0) {
this.chessboard[i][j] = 1 //尝试落子
this.scores[i][j] = this.computeScore(i, j, 1) //计算己方收益
this.chessboard[i][j] = 0 //收回尝试
}
// 选出进攻分数最高的位置
let I = 0, J = 0
for (let i = 0; i < 15; i++)
for (let j = 0; j < 15; j++)
if (this.scores[i][j] > this.scores[I][J]) {
I = i
J = j
}
if (this.scores[I][J] == 100) {
this.chessboard[I][J] = 1
//直接获胜
this.next = {
row: I + 1,
col: J + 1,
player: this.player
}
console.log(`Attack: (${this.next.row}, ${this.next.col}) s:${this.scores[I][J]}`);
} else if (rivalScores[rI][rJ] >= 20) {
//若出现危险棋局, 选择防守策略
this.chessboard[rI][rJ] = 1
this.next = {
row: rI + 1,
col: rJ + 1,
player: this.player
}
console.log(`Defend: (${this.next.row}, ${this.next.col}) s:${rivalScores[rI][rJ]}`);
} else {
//进攻
this.chessboard[I][J] = 1
this.next = {
row: I + 1,
col: J + 1,
player: this.player
}
console.log(`Attack: (${this.next.row}, ${this.next.col}) s:${this.scores[I][J]}`);
}
}
getNextAction() {
return this.next
}
/**
* 根据棋型给出分数
*
* 一个棋型由其中连子的个数和前后是否堵截来确定
*/
private scoreOfStyle(line: number, block1: boolean, block2: boolean) {
if (line == 5) return AIScore.ooooo
if (block1 && block2) return 0
switch (line) {
case 4: return (block1 || block2) ? AIScore.Ioooo : AIScore.oooo
case 3: return (block1 || block2) ? AIScore.Iooo : AIScore.ooo
case 2: return (block1 || block2) ? AIScore.Ioo : AIScore.oo
case 1: return 0
}
}
/**
* 根据棋敌方型给出威胁分数
*
* 一个棋型由其中连子的个数和前后是否堵截来确定
*/
private scoreOfRivalStyle(line: number, block1: boolean, block2: boolean) {
if (line == 5) return AIRivalScore.ooooo
if (block1 && block2) return 0
switch (line) {
case 4: return (block1 || block2) ? AIRivalScore.Ioooo : AIRivalScore.oooo
case 3: return (block1 || block2) ? AIRivalScore.Iooo : AIRivalScore.ooo
case 2: return (block1 || block2) ? AIRivalScore.Ioo : AIRivalScore.oo
case 1: return 0
}
}
/**
* 假设在(i, j)处落子, 计算落子后获得的分数 scores[i][j]
* @param {number} player 1 计算己方的收益, -1 计算敌方收益
*/
private computeScore(i: number, j: number, player: number) {
let score = 0
//上、下 (r先减后加, c不变)
let r1 = i, c = j
while (r1 > 0 && this.chessboard[r1 - 1][c] == player) r1--
let upIsBlocked = (r1 == 0) || this.chessboard[r1 - 1][c] == -player
let r2 = i
while (r2 < 14 && this.chessboard[r2 + 1][c] == player) r2++
let downIsBlocked = (r2 == 14) || this.chessboard[r2 + 1][c] == -player
let line = (r1 == r2) ? 1 : (r2 - r1 + 1)
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, upIsBlocked, downIsBlocked) :
this.scoreOfRivalStyle(line, upIsBlocked, downIsBlocked)
//左、右 (r不变, c先减后加)
let r = i, c1 = j
while (c1 > 0 && this.chessboard[r][c1 - 1] == player) c1--
let leftIsBlocked = (c1 == 0) || this.chessboard[r][c1 - 1] == -player
let c2 = j
while (c2 < 14 && this.chessboard[r][c2 + 1] == player) c2++
let rightIsBlocked = (c2 == 14) || this.chessboard[r][c2 + 1] == -player
line = (c1 == c2) ? 1 : (c2 - c1 + 1)
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftIsBlocked, rightIsBlocked) :
this.scoreOfRivalStyle(line, leftIsBlocked, rightIsBlocked)
//主对角线方向 (rc先减后加)
r1 = i, c1 = j
while (r1 > 0 && c1 > 0 && this.chessboard[r1 - 1][c1 - 1] == player) {r1--; c1--}
let leftUpIsBlocked = (r1 == 0 || c1 == 0) || this.chessboard[r1 - 1][c1 - 1] == -player
r2 = i
c2 = j
while (r2 < 14 && c2 < 14 && this.chessboard[r2 + 1][c2 + 1] == player) {r2++; c2++}
let rightDownIsBlocked = (r2 == 14 || c2 == 14) || this.chessboard[r2 + 1][c2 + 1] == -player
line = (r1 == r2) ? 1 : (r2 - r1 + 1)
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftUpIsBlocked, rightDownIsBlocked) :
this.scoreOfRivalStyle(line, leftUpIsBlocked, rightDownIsBlocked)
//副对角线方向 (r先加后减, c先减后加)
r1 = i, c1 = j
while (r1 < 14 && c1 > 0 && this.chessboard[r1 + 1][c1 - 1] == player) {r1++; c1--}
let leftDownIsBlocked = (r1 == 14 || c1 == 0) || this.chessboard[r1 + 1][c1 - 1] == -player
r2 = i
c2 = j
while (r2 > 0 && c2 < 14 && this.chessboard[r2 - 1][c2 + 1] == player) {r2--; c2++}
let rightUpIsBlocked = (r2 == 0 || c2 == 14) || this.chessboard[r2 - 1][c2 + 1] == -player
line = (c1 == c2) ? 1 : (c2 - c1 + 1)
// 判断棋型
score += (player == 1) ?
this.scoreOfStyle(line, leftDownIsBlocked, rightUpIsBlocked) :
this.scoreOfRivalStyle(line, leftDownIsBlocked, rightUpIsBlocked)
return score
}
}
\ No newline at end of file
namespace AI {
/** AI 将棋子分为 None, Player, AI 三种 */
enum AIChess {
Empty = 0,
Player = 1,
AI = -1
}
/** 棋子在棋盘中的位置(row, col) (Zero Based) */
interface ChessPosition {
row: number
col: number
}
/** 连子的评估结果(连子的个数,是否间断,两端是否堵截) */
interface ContinualLineEvalutaion {
/**连子的个数(不含空格) */
count: number
hasGap: boolean
leftIsBlocked: boolean
rightIsBlocked: boolean
}
/**2号AI */
export class TestAI_2 extends GomokuAI {
private maxSearchDepth = 2
/**
* AI 自行维护一个棋盘 (0~14X0~14)
* 注: 使用 ChessPosition 将二维数组的的操作包装起来,避免在逻辑中出现[][]的操作
*/
private chessboard: AIChess[][]
private positionIsValid(pos: ChessPosition) {
if (0 <= pos.row && pos.row <= 14 && 0 <= pos.col && pos.col <= 14)
return true
else
return false
}
private positionIsEmpty(pos: ChessPosition) {
return this.getChess(pos) == AIChess.Empty
}
private getChess(pos: ChessPosition) {
return this.chessboard[pos.row][pos.col]
}
private putChessOn(pos: ChessPosition, chess: AIChess) {
this.chessboard[pos.row][pos.col] = chess
}
private takeChessFrom(pos: ChessPosition) {
this.chessboard[pos.row][pos.col] = AIChess.Empty
}
private allPossiblePositions(): ChessPosition[] {
let postions: ChessPosition[] = []
for (let r = 0; r < this.chessboard.length; r++) {
for (let c = 0; c < this.chessboard[r].length; c++) {
if (this.chessboard[r][c] == AIChess.Empty) {
postions.push({
row: r,
col: c
})
}
}
}
return postions
}
private profits: number[][]
private threats: number[][]
constructor() {
super()
this.chessboard = makeMatrix(15, 15, AIChess.Empty)
this.profits = makeMatrix(15, 15, -1)
this.threats = makeMatrix(15, 15, -1)
}
public putFirstChessInMiddle() {
this.putChessOn({row: 7, col: 7}, AIChess.AI)
}
private scoreOfEvaluation(result: ContinualLineEvalutaion):number {
if (result.count >= 5 && !result.hasGap) return AIScore.ooooo
else if (result.count >= 5 && result.hasGap) return AIScore.Iooo_oo
else if (result.leftIsBlocked && result.rightIsBlocked) return AIScore.WillFail
if (!result.hasGap) {
switch (result.count) {
case 4: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioooo : AIScore.oooo
case 3: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Iooo : AIScore.ooo
case 2: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioo : AIScore.oo
case 1: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io : AIScore.o
}
} else {
switch (result.count) {
case 4: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Ioo_oo : AIScore.oo_oo
case 3: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io_oo : AIScore.o_oo
case 2: return (result.leftIsBlocked || result.rightIsBlocked) ? AIScore.Io_o : AIScore.o_o
}
}
return AIScore.Min
}
/**
* 评估指定位置和方向的AI或玩家的连子, 连子方向由两个函数决定, 允许中间出现一次间隔
* (应确保指定位置处有棋子且为target)
* @param {ChessPosition} pos 棋子的位置
* @param {AIChess} target AI或玩家 (注: -target == target的对手)
* @param {function(ChessPosition):ChessPosition} dec 位置递减函数
* @param {function(ChessPosition):ChessPosition} inc 位置递增函数
* @return {ContinualLineEvalutaion} 评估结果
*/
private evaluateContinualLine (
pos: ChessPosition, target: AIChess.AI | AIChess.Player,
dec: (pos: ChessPosition) => ChessPosition,
inc: (pos: ChessPosition) => ChessPosition): number {
//使用dec走到连子的一个边界, 再使用inc走到连子的另一个边界
let hasGap = false
let leftIsBlocked = false
//先走到一个边界
while (this.positionIsValid(dec(pos))) {
if (this.positionIsEmpty(dec(pos))) {
if (hasGap) break
else hasGap = true
} else if (this.getChess(dec(pos)) == -target) {
leftIsBlocked = true
break
}
pos = dec(pos)
}
if (!this.positionIsValid(dec(pos))) leftIsBlocked = true
if (this.positionIsEmpty(pos)) {
pos = inc(pos)
leftIsBlocked = false
}
//再走到另一个边界
hasGap = false
let count = 1
let rightIsBlocked = false
while (this.positionIsValid(inc(pos))) {
if (this.positionIsEmpty(inc(pos))) {
if (hasGap) break
else hasGap = true
} else if (this.getChess(inc(pos)) == -target) {
rightIsBlocked = true
break
}
pos = inc(pos)
count++
}
if (!this.positionIsValid(inc(pos))) rightIsBlocked = true
if (this.positionIsEmpty(pos)) {
pos = dec(pos)
rightIsBlocked = false
hasGap = false
count--
}
if (hasGap) count--
return this.scoreOfEvaluation({
count: count,
hasGap: hasGap,
leftIsBlocked: leftIsBlocked,
rightIsBlocked: rightIsBlocked
})
}
/**
* 计算在 (row, col) target 落子的得分(AI落子即收益分, 玩家落子即威胁分)
* @param {number} row 0~14
* @param {number} col 0~14
* @param {AIChess} target AI 或 Player
*/
private computeScore(pos: ChessPosition, target: AIChess.AI | AIChess.Player) {
this.putChessOn(pos, target)
let score = 0
//从上到下
score += this.evaluateContinualLine(pos, target,
(pos: ChessPosition) => { return {row: pos.row - 1, col: pos.col} },
(pos: ChessPosition) => { return {row: pos.row + 1, col: pos.col} })
//从左到右
score += this.evaluateContinualLine(pos, target,
(pos: ChessPosition) => { return { row: pos.row, col: pos.col - 1 } },
(pos: ChessPosition) => { return { row: pos.row, col: pos.col + 1 } })
//从右上到左下
score += this.evaluateContinualLine(pos, target,
(pos: ChessPosition) => { return { row: pos.row - 1, col: pos.col - 1 } },
(pos: ChessPosition) => { return { row: pos.row + 1, col: pos.col + 1 } })
//从左下到右上
score += this.evaluateContinualLine(pos, target,
(pos: ChessPosition) => { return { row: pos.row + 1, col: pos.col - 1 } },
(pos: ChessPosition) => { return { row: pos.row - 1, col: pos.col + 1 } })
this.takeChessFrom(pos)
return score
}
/**计算 AI 所有可能落子的收益 */
private computeProfits() {
for (let r = 0; r < 15; r++) {
for (let c = 0; c < 15; c++) {
if (this.positionIsEmpty({row: r, col: c})) {
this.profits[r][c] = this.computeScore({ row: r, col: c }, AIChess.AI)
} else {
this.profits[r][c] = -1
}
}
}
}
/**获取最大收益点 */
private getMaxProfitPosition(): ChessPosition {
let p = {
row: 0,
col: 0
}
for (let r = 0; r < 15; r++) {
for (let c = 0; c < 15; c++) {
if (this.profits[r][c] > this.profits[p.row][p.col]) {
p.row = r
p.col = c
}
}
}
return p
}
/**计算玩家所有可能落子的威胁 */
private computeThreats() {
for (let r = 0; r < 15; r++) {
for (let c = 0; c < 15; c++) {
if (this.positionIsEmpty({ row: r, col: c })) {
this.threats[r][c] = this.computeScore({ row: r, col: c }, AIChess.Player)
} else {
this.threats[r][c] = -1
}
}
}
}
/**获取最大威胁点 */
private getMaxThreatPosition(): ChessPosition {
let p = {
row: 0,
col: 0
}
for (let r = 0; r < 15; r++) {
for (let c = 0; c < 15; c++) {
if (this.threats[r][c] > this.threats[p.row][p.col]) {
p.row = r
p.col = c
}
}
}
return p
}
/**
* Min-Max 决策找出对大收益点
* 搜索深度取决于 maxSearchDepth
*
* @Todo: minmax 算法无法应用于当前的AI,minmax 算法使用给予状态的整体utility函数,
* 而不是仅当落子时计算四周的连子
*
* @param {AIChess} target 决策对象(AI|Player)
*/
private minmaxDecision(target: AIChess.AI | AIChess.Player) {
let currentDepth = 0
let maxValue = (pos: ChessPosition): number => {
currentDepth++
if (currentDepth == this.maxSearchDepth) {
currentDepth--
return this.computeScore(pos, -target)
}
this.putChessOn(pos, -target)
let v = -Infinity
let possiblePositions = this.allPossiblePositions()
for (let pos of possiblePositions) {
v = Math.max(v, minValue(pos))
}
this.takeChessFrom(pos)
currentDepth--
return v
}
let minValue = (pos: ChessPosition): number => {
currentDepth++
if (currentDepth == this.maxSearchDepth) {
currentDepth--
return this.computeScore(pos, target)
}
this.putChessOn(pos, target)
let v = Infinity
let possiblePositions = this.allPossiblePositions()
for (let pos of possiblePositions) {
v = Math.min(v, maxValue(pos))
}
this.takeChessFrom(pos)
currentDepth--
return v
}
let possiblePositions = this.allPossiblePositions()
let pos = possiblePositions[0]
let value = minValue(pos)
for (let i = 1; i < possiblePositions.length; i++) {
if (minValue(possiblePositions[i]) > value) {
pos = possiblePositions[i]
}
}
return pos
}
/**
* 分析对手的动作
*/
public analysAction(action: GomokuAction) {
this.putChessOn({row: action.row - 1, col: action.col - 1}, AIChess.Player)
//判断局棋威胁
this.computeThreats()
//判断下一步收益
this.computeProfits()
}
/**
* 给出下一次动作
*/
public getNextAction(): GomokuAction {
let ppos = this.getMaxProfitPosition()
let tpos = this.getMaxThreatPosition()
let pos = (this.threats[tpos.row][tpos.col] > AIScore.Dangerous && this.threats[tpos.row][tpos.col] > this.profits[ppos.row][ppos.col]) ?
tpos : ppos
if (this.profits[ppos.row][ppos.col] == AIScore.ooooo) pos = ppos
this.putChessOn(pos, AIChess.AI)
return {
row: pos.row + 1,
col: pos.col + 1,
player: GomokuPlayer.White, //AI use white chess @Todo: improve this
}
}
}//class TestAI_2
}//namespace AI
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册