├── .gitignore
├── .DS_Store
├── .idea
├── misc.xml
├── scopes
│ └── scope_settings.xml
├── xcode.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── ReactChess.iml
├── runConfigurations
│ └── ReactChess.xml
└── workspace.xml
├── ReactChess.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── clairesarsam.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── clairesarsam.xcuserdatad
│ │ ├── xcschemes
│ │ └── xcschememanagement.plist
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
├── xcshareddata
│ └── xcschemes
│ │ └── ReactChess.xcscheme
└── project.pbxproj
├── package.json
├── iOS
├── AppDelegate.h
├── main.m
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── AppDelegate.m
└── Base.lproj
│ └── LaunchScreen.xib
├── javascript
├── square.ios.js
├── constants.ios.js
├── piece.ios.js
├── board.ios.js
└── chess.js
└── index.ios.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/csarsam/ReactNativeChess/HEAD/.DS_Store
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/xcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/project.xcworkspace/xcuserdata/clairesarsam.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/csarsam/ReactNativeChess/HEAD/ReactChess.xcodeproj/project.xcworkspace/xcuserdata/clairesarsam.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ReactChess",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node_modules/react-native/packager/packager.sh"
7 | },
8 | "dependencies": {
9 | "react-native": "^0.1.0",
10 | "chess.js": "0.1.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iOS/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/iOS/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/xcuserdata/clairesarsam.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ReactChess.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 13B07F861A680F5B00A75B9A
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/ReactChess.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/iOS/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations/ReactChess.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/xcuserdata/clairesarsam.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/javascript/square.ios.js:
--------------------------------------------------------------------------------
1 | const React = require('react-native');
2 | const {
3 | AppRegistry,
4 | StyleSheet,
5 | Text,
6 | TouchableHighlight,
7 | View
8 | } = React;
9 | const CONSTANTS = require('./constants.ios');
10 |
11 | const Square = React.createClass({
12 | render() {
13 | const color = this.props.column % 2 === 1 ?
14 | (this.props.row % 2 === 1 ? '#464646' : '#7F7E7E') :
15 | (this.props.row % 2 === 1 ? '#7F7E7E' : '#464646');
16 |
17 | const styles = {
18 | backgroundColor: this.props.selected ? '#376060' : color,
19 | width: 375/8,
20 | height: 375/8
21 | };
22 |
23 | const onPress = () => {
24 | this.props.onSquareSelect(this.props.row, this.props.column);
25 | };
26 |
27 | if (this.props.selectable) {
28 | return (
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | else
37 | return (
38 |
39 |
40 | );
41 | }
42 | });
43 |
44 | module.exports = Square;
45 |
--------------------------------------------------------------------------------
/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/iOS/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import "RCTRootView.h"
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | NSURL *jsCodeLocation;
19 |
20 | // Loading JavaScript code - uncomment the one you want.
21 |
22 | // OPTION 1
23 | // Load from development server. Start the server from the repository root:
24 | //
25 | // $ npm start
26 | //
27 | // To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
28 | // iOS device are on the same Wi-Fi network.
29 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];
30 |
31 | // OPTION 2
32 | // Load from pre-bundled file on disk. To re-generate the static bundle, run
33 | //
34 | // $ curl http://localhost:8081/index.ios.bundle -o main.jsbundle
35 | //
36 | // and uncomment the next following line
37 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
38 |
39 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
40 | moduleName:@"ReactChess"
41 | launchOptions:launchOptions];
42 |
43 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
44 | UIViewController *rootViewController = [[UIViewController alloc] init];
45 | rootViewController.view = rootView;
46 | self.window.rootViewController = rootViewController;
47 | [self.window makeKeyAndVisible];
48 | return YES;
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/index.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var React = require('react-native');
3 | var {
4 | AppRegistry,
5 | StyleSheet,
6 | Text,
7 | View,
8 | Animation,
9 | } = React;
10 |
11 | var Chess = require('./javascript/chess');
12 | var Board = require('./javascript/board.ios');
13 | var CONSTANTS = require('./javascript/constants.ios');
14 |
15 | var game;
16 |
17 | var ReactChess = React.createClass({
18 | getInitialState() {
19 | return {
20 | turn: CONSTANTS.WHITE
21 | };
22 | },
23 |
24 | render() {
25 | var history = game.history({ verbose: true });
26 | return (
27 |
28 |
29 | {game.game_over() ?
30 | game.in_checkmate() ?
31 | this.state.turn === CONSTANTS.WHITE ?
32 | 'White is in checkmate' : 'Black is in checkmate' :
33 | `The game has ended in ${game.in_checkmate()}` :
34 | this.state.turn === CONSTANTS.WHITE ? 'White moves' : 'Black moves'}
35 |
36 |
37 |
38 |
39 |
40 | {history.length > 0 ?
41 | `${history[history.length - 1].to} => ${history[history.length - 1].from}` : ''}
42 |
43 |
44 | );
45 | },
46 |
47 | turnComplete() {
48 | this.setState({ turn: game.turn() === 'b' ? CONSTANTS.BLACK : CONSTANTS.WHITE });
49 | },
50 |
51 | componentWillMount() {
52 | game = new Chess();
53 | },
54 |
55 | componentDidMount() {
56 | setTimeout(() => {
57 | Animation.startAnimation(this.refs['this'], 300, 0, 'easeInOutQuad', {opacity: 1});
58 | }, 0);
59 | }
60 | });
61 |
62 | var styles = StyleSheet.create({
63 | container: {
64 | flex: 1,
65 | opacity: 0,
66 | justifyContent: 'center',
67 | alignItems: 'center',
68 | backgroundColor: '#F5FCFF',
69 | },
70 | turn: {
71 | fontSize: 30,
72 | position: 'absolute',
73 | width: 375,
74 | textAlign: 'center',
75 | top: 50
76 | },
77 | history: {
78 | fontSize: 20,
79 | position: 'absolute',
80 | textAlign: 'center',
81 | width: 375,
82 | top: 550
83 | }
84 | });
85 |
86 | AppRegistry.registerComponent('ReactChess', () => ReactChess);
87 |
--------------------------------------------------------------------------------
/javascript/constants.ios.js:
--------------------------------------------------------------------------------
1 | const COLUMNS = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
2 | const ROWS = [8, 7, 6, 5, 4, 3, 2, 1];
3 |
4 | const PIECES = ['p', 'b', 'c', 'n', 'k', 'q'];
5 | const PAWN = 'p', BISHOP = 'b', CASTLE = 'c', KNIGHT = 'n', KING = 'k', QUEEN = 'q';
6 | const BLACK = '#000000';
7 | const WHITE = '#FFFFFF';
8 |
9 | const initialBoard = [
10 | [
11 | { piece: CASTLE, color: WHITE, key: 0 },
12 | { piece: KNIGHT, color: WHITE, key: 1 },
13 | { piece: BISHOP, color: WHITE, key: 2 },
14 | { piece: QUEEN, color: WHITE, key: 3 },
15 | { piece: KING, color: WHITE, key: 4 },
16 | { piece: BISHOP, color: WHITE, key: 5 },
17 | { piece: KNIGHT, color: WHITE, key: 6 },
18 | { piece: CASTLE, color: WHITE, key: 7 }
19 | ],
20 | [
21 | { piece: PAWN, color: WHITE, key: 8 },
22 | { piece: PAWN, color: WHITE, key: 9 },
23 | { piece: PAWN, color: WHITE, key: 10 },
24 | { piece: PAWN, color: WHITE, key: 11 },
25 | { piece: PAWN, color: WHITE, key: 12 },
26 | { piece: PAWN, color: WHITE, key: 13 },
27 | { piece: PAWN, color: WHITE, key: 14 },
28 | { piece: PAWN, color: WHITE, key: 15 }
29 | ],
30 | [
31 | null,
32 | null,
33 | null,
34 | null,
35 | null,
36 | null,
37 | null,
38 | null
39 | ],
40 | [
41 | null,
42 | null,
43 | null,
44 | null,
45 | null,
46 | null,
47 | null,
48 | null
49 | ],
50 | [
51 | null,
52 | null,
53 | null,
54 | null,
55 | null,
56 | null,
57 | null,
58 | null
59 | ],
60 | [
61 | null,
62 | null,
63 | null,
64 | null,
65 | null,
66 | null,
67 | null,
68 | null
69 | ],
70 | [
71 | { piece: PAWN, color: BLACK, key: 16 },
72 | { piece: PAWN, color: BLACK, key: 17 },
73 | { piece: PAWN, color: BLACK, key: 18 },
74 | { piece: PAWN, color: BLACK, key: 19 },
75 | { piece: PAWN, color: BLACK, key: 20 },
76 | { piece: PAWN, color: BLACK, key: 21 },
77 | { piece: PAWN, color: BLACK, key: 22 },
78 | { piece: PAWN, color: BLACK, key: 23 }
79 | ],
80 | [
81 | { piece: CASTLE, color: BLACK, key: 24 },
82 | { piece: KNIGHT, color: BLACK, key: 25 },
83 | { piece: BISHOP, color: BLACK, key: 26 },
84 | { piece: QUEEN, color: BLACK, key: 27 },
85 | { piece: KING, color: BLACK, key: 28 },
86 | { piece: BISHOP, color: BLACK, key: 29 },
87 | { piece: KNIGHT, color: BLACK, key: 30 },
88 | { piece: CASTLE, color: BLACK, key: 31 }
89 | ]
90 | ];
91 |
92 | module.exports = {
93 | PAWN: PAWN,
94 | CASTLE: CASTLE,
95 | KNIGHT: KNIGHT,
96 | QUEEN: QUEEN,
97 | KING: KING,
98 | BISHOP: BISHOP,
99 | COLUMNS: COLUMNS,
100 | ROWS: ROWS,
101 | PIECES: PIECES,
102 | BLACK: BLACK,
103 | WHITE: WHITE,
104 | initialBoard: initialBoard
105 | };
--------------------------------------------------------------------------------
/javascript/piece.ios.js:
--------------------------------------------------------------------------------
1 | const React = require('react-native');
2 | const {
3 | AppRegistry,
4 | StyleSheet,
5 | Text,
6 | TouchableHighlight,
7 | Animation,
8 | View
9 | } = React;
10 | const CONSTANTS = require('./constants.ios');
11 |
12 | const Piece = React.createClass({
13 | render() {
14 | const containerStyle = {
15 | top: this.props.row * (375/8),
16 | left: this.props.column * (375/8)
17 | };
18 | const textStyle = {
19 | color: this.props.color
20 | };
21 |
22 | const onPress = () => {
23 | this.props.onPieceSelect(this.props.row, this.props.column, this.props.color);
24 | };
25 |
26 | if (this.props.selectable)
27 | return (
28 |
29 |
30 |
31 | {this.props.piece.toUpperCase()}
32 |
33 |
34 |
35 | );
36 | else
37 | return (
38 |
39 |
40 | {this.props.piece.toUpperCase()}
41 |
42 |
43 | );
44 | },
45 |
46 | componentWillUpdate(nextProps, nextState) {
47 | if (this.props.row != nextProps.row || this.props.column != nextProps.column) {
48 | const x = (375/8) * (nextProps.column + .5),
49 | y = (375/8) * (nextProps.row + .5);
50 |
51 | if (this.props.piece === CONSTANTS.KNIGHT) {
52 | const diffX = Math.abs(this.props.column - nextProps.column),
53 | diffY = Math.abs(this.props.row - nextProps.row);
54 | var midX, midY;
55 | if (Math.max(diffX, diffY) === diffX) {
56 | midX = (375/8) * (nextProps.column + .5);
57 | midY = (375/8) * (this.props.row + .5);
58 | } else {
59 | midX = (375/8) * (this.props.column + .5);
60 | midY = (375/8) * (nextProps.row + .5);
61 | }
62 | Animation.startAnimation(this.refs['this'], 300, 0, 'easeInOutCirc', {position: [midX, midY]});
63 | setTimeout(() => {
64 | Animation.startAnimation(this.refs['this'], 150, 0, 'easeInOutCirc', {position: [x, y]});
65 | }, 300);
66 | } else {
67 | Animation.startAnimation(this.refs['this'], 500, 0, 'easeInOutCirc', {position: [x, y]});
68 | }
69 | }
70 | },
71 |
72 | componentDidMount() {
73 | setTimeout(() => {
74 | Animation.startAnimation(this.refs['this'], 500, 0, 'easeInQuad', {opacity: 1});
75 | }, (150 * (7 - Math.abs(this.props.column - 3.5))));
76 | // setTimeout(() => {
77 | // Animation.startAnimation(this.refs['this'], 500, 0, 'easeInQuad', {opacity: 1});
78 | // }, (100 * Math.sqrt(Math.pow(this.props.column - 3, 2))));
79 | }
80 | });
81 |
82 | const styles = StyleSheet.create({
83 | container: {
84 | position: 'absolute',
85 | width: 375/8,
86 | height: 375/8,
87 | backgroundColor: 'rgba(0, 0, 0, 0)',
88 | opacity: 0
89 | },
90 | text: {
91 | fontSize: 40,
92 | textAlign: 'center',
93 | fontWeight: 'bold'
94 | }
95 | });
96 |
97 | module.exports = Piece;
98 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/xcshareddata/xcschemes/ReactChess.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/iOS/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/javascript/board.ios.js:
--------------------------------------------------------------------------------
1 | const React = require('react-native');
2 | const {
3 | AppRegistry,
4 | StyleSheet,
5 | Text,
6 | View
7 | } = React;
8 | const Square = require('./square.ios');
9 | const Piece = require('./piece.ios');
10 | const CONSTANTS = require('./constants.ios');
11 |
12 | var keys = [
13 | [0, 1, 2, 3, 4, 5, 6, 7],
14 | [8, 9, 10, 11, 12, 13, 14, 15],
15 | [null, null, null, null, null, null, null, null],
16 | [null, null, null, null, null, null, null, null],
17 | [null, null, null, null, null, null, null, null],
18 | [null, null, null, null, null, null, null, null],
19 | [16, 17, 18, 19, 20, 21, 22, 23],
20 | [24, 25, 26, 27, 28, 29, 30, 31]
21 | ];
22 |
23 | const Board = React.createClass({
24 | getInitialState() {
25 | return {
26 | selectedPiece: null
27 | };
28 | },
29 |
30 | render() {
31 | var squares = [], pieces = [];
32 | var moves = [];
33 |
34 | const gameState = this.props.game.fen().split(' ')[0].split('/');
35 |
36 | if (this.state.selectedPiece !== null) {
37 | const currentSquare = { square:
38 | CONSTANTS.COLUMNS[this.state.selectedPiece.column] + CONSTANTS.ROWS[this.state.selectedPiece.row],
39 | verbose: true
40 | };
41 | moves = [];
42 | this.props.game.moves(currentSquare).map((move) => {
43 | moves.push(move.to);
44 | });
45 | }
46 |
47 | gameState.map((row, rowIndex) => {
48 | var column = 0;
49 | for (var i = 0; i < row.length; i++) {
50 | if (row.charAt(i).match(/\d/)) {
51 | for (var j = 0; j < parseInt(row.charAt(i)); j++) {
52 | squares.push(
53 |
63 | );
64 | column++;
65 | }
66 | }
67 | else if (row.charAt(i).match(/[A-Za-z]/)) {
68 | squares.push(
69 |
79 | );
80 | color = row.charAt(i).match(/[A-Z]/) ? CONSTANTS.WHITE : CONSTANTS.BLACK;
81 | key = color + row.charAt(i).toLowerCase();
82 | pieces.push(
83 |
92 | );
93 | column++;
94 | }
95 | }
96 | });
97 |
98 | return (
99 |
100 | {squares.concat(pieces)}
101 |
102 | );
103 | },
104 |
105 | onPieceSelected(row, column, color) {
106 | if (this.state.selectedPiece !== null) {
107 | if (this.props.turn !== color) {
108 | this.onSquareSelected(row, column);
109 | } else {
110 | if (this.state.selectedPiece.row !== row || this.state.selectedPiece.column !== column)
111 | this.setState({ selectedPiece: {row: row, column: column} });
112 | else
113 | this.setState({ selectedPiece: null });
114 | }
115 | } else {
116 | this.setState({ selectedPiece: {row: row, column: column} });
117 | }
118 | },
119 |
120 | onSquareSelected(row, column) {
121 | if (this.state.selectedPiece === null) {
122 | return;
123 | }
124 | const move = {
125 | from: CONSTANTS.COLUMNS[this.state.selectedPiece.column] + CONSTANTS.ROWS[this.state.selectedPiece.row],
126 | to: CONSTANTS.COLUMNS[column] + CONSTANTS.ROWS[row]
127 | };
128 | if (this.props.game.move(move)) {
129 | keys[row][column] = keys[this.state.selectedPiece.row][this.state.selectedPiece.column];
130 | keys[this.state.selectedPiece.row][this.state.selectedPiece.column] = null;
131 | }
132 | this.props.turnComplete();
133 | }
134 | });
135 |
136 | const styles = StyleSheet.create({
137 | container: {
138 | width: 375,
139 | height: 375,
140 | backgroundColor: '#F5FCFF',
141 | flexDirection: 'row',
142 | flexWrap: 'wrap',
143 | }
144 | });
145 |
146 | module.exports = Board;
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | true
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | 1427402432863
177 |
178 | 1427402432863
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
212 |
215 |
216 |
217 |
218 |
219 |
220 |
223 |
224 |
225 |
226 |
227 |
228 |
--------------------------------------------------------------------------------
/ReactChess.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 00481BE81AC0C86700671115 /* libRCTWebSocketDebugger.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00481BE61AC0C7FA00671115 /* libRCTWebSocketDebugger.a */; };
11 | 00481BEA1AC0C89D00671115 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 00481BE91AC0C89D00671115 /* libicucore.dylib */; };
12 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
13 | 00C302E61ABCBA2D00DB3ED1 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */; };
14 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
15 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
16 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
17 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
18 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
19 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
20 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
21 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
22 | 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
23 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
24 | AF1765C01AC604C600AE3E79 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF1765BF1AC604B500AE3E79 /* libRCTAnimation.a */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXContainerItemProxy section */
28 | 00481BE51AC0C7FA00671115 /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */;
31 | proxyType = 2;
32 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
33 | remoteInfo = RCTWebSocketDebugger;
34 | };
35 | 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
36 | isa = PBXContainerItemProxy;
37 | containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
38 | proxyType = 2;
39 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
40 | remoteInfo = RCTActionSheet;
41 | };
42 | 00C302B31ABCB8E700DB3ED1 /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */;
45 | proxyType = 2;
46 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
47 | remoteInfo = RCTAdSupport;
48 | };
49 | 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
52 | proxyType = 2;
53 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
54 | remoteInfo = RCTGeolocation;
55 | };
56 | 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
57 | isa = PBXContainerItemProxy;
58 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
59 | proxyType = 2;
60 | remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
61 | remoteInfo = RCTImage;
62 | };
63 | 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
64 | isa = PBXContainerItemProxy;
65 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
66 | proxyType = 2;
67 | remoteGlobalIDString = 58B511DB1A9E6C8500147676;
68 | remoteInfo = RCTNetwork;
69 | };
70 | 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
71 | isa = PBXContainerItemProxy;
72 | containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
73 | proxyType = 2;
74 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
75 | remoteInfo = RCTVibration;
76 | };
77 | 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
78 | isa = PBXContainerItemProxy;
79 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
80 | proxyType = 2;
81 | remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
82 | remoteInfo = React;
83 | };
84 | 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
85 | isa = PBXContainerItemProxy;
86 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
87 | proxyType = 2;
88 | remoteGlobalIDString = 58B5119B1A9E6C1200147676;
89 | remoteInfo = RCTText;
90 | };
91 | AF1765BE1AC604B500AE3E79 /* PBXContainerItemProxy */ = {
92 | isa = PBXContainerItemProxy;
93 | containerPortal = AF1765BA1AC604B500AE3E79 /* RCTAnimation.xcodeproj */;
94 | proxyType = 2;
95 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
96 | remoteInfo = RCTAnimation;
97 | };
98 | /* End PBXContainerItemProxy section */
99 |
100 | /* Begin PBXFileReference section */
101 | 00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocketDebugger.xcodeproj; path = "node_modules/react-native/Libraries/RCTWebSocketDebugger/RCTWebSocketDebugger.xcodeproj"; sourceTree = ""; };
102 | 00481BE91AC0C89D00671115 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
103 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; };
104 | 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = "node_modules/react-native/Libraries/AdSupport/RCTAdSupport.xcodeproj"; sourceTree = ""; };
105 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; };
106 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; };
107 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; };
108 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; };
109 | 13B07F961A680F5B00A75B9A /* ReactChess.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactChess.app; sourceTree = BUILT_PRODUCTS_DIR; };
110 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = iOS/AppDelegate.h; sourceTree = ""; };
111 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = iOS/AppDelegate.m; sourceTree = ""; };
112 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
113 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = iOS/Images.xcassets; sourceTree = ""; };
114 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = iOS/Info.plist; sourceTree = ""; };
115 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = iOS/main.m; sourceTree = ""; };
116 | 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; };
117 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; };
118 | AF1765BA1AC604B500AE3E79 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "node_modules/react-native/Libraries/Animation/RCTAnimation.xcodeproj"; sourceTree = ""; };
119 | /* End PBXFileReference section */
120 |
121 | /* Begin PBXFrameworksBuildPhase section */
122 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
123 | isa = PBXFrameworksBuildPhase;
124 | buildActionMask = 2147483647;
125 | files = (
126 | AF1765C01AC604C600AE3E79 /* libRCTAnimation.a in Frameworks */,
127 | 00481BEA1AC0C89D00671115 /* libicucore.dylib in Frameworks */,
128 | 146834051AC3E58100842450 /* libReact.a in Frameworks */,
129 | 00481BE81AC0C86700671115 /* libRCTWebSocketDebugger.a in Frameworks */,
130 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
131 | 00C302E61ABCBA2D00DB3ED1 /* libRCTAdSupport.a in Frameworks */,
132 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
133 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
134 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
135 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
136 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
137 | );
138 | runOnlyForDeploymentPostprocessing = 0;
139 | };
140 | /* End PBXFrameworksBuildPhase section */
141 |
142 | /* Begin PBXGroup section */
143 | 00481BDC1AC0C7FA00671115 /* Products */ = {
144 | isa = PBXGroup;
145 | children = (
146 | 00481BE61AC0C7FA00671115 /* libRCTWebSocketDebugger.a */,
147 | );
148 | name = Products;
149 | sourceTree = "";
150 | };
151 | 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
152 | isa = PBXGroup;
153 | children = (
154 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
155 | );
156 | name = Products;
157 | sourceTree = "";
158 | };
159 | 00C302B01ABCB8E700DB3ED1 /* Products */ = {
160 | isa = PBXGroup;
161 | children = (
162 | 00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */,
163 | );
164 | name = Products;
165 | sourceTree = "";
166 | };
167 | 00C302B61ABCB90400DB3ED1 /* Products */ = {
168 | isa = PBXGroup;
169 | children = (
170 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
171 | );
172 | name = Products;
173 | sourceTree = "";
174 | };
175 | 00C302BC1ABCB91800DB3ED1 /* Products */ = {
176 | isa = PBXGroup;
177 | children = (
178 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
179 | );
180 | name = Products;
181 | sourceTree = "";
182 | };
183 | 00C302D41ABCB9D200DB3ED1 /* Products */ = {
184 | isa = PBXGroup;
185 | children = (
186 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
187 | );
188 | name = Products;
189 | sourceTree = "";
190 | };
191 | 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
192 | isa = PBXGroup;
193 | children = (
194 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
195 | );
196 | name = Products;
197 | sourceTree = "";
198 | };
199 | 13B07FAE1A68108700A75B9A /* ReactChess */ = {
200 | isa = PBXGroup;
201 | children = (
202 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
203 | 13B07FB01A68108700A75B9A /* AppDelegate.m */,
204 | 13B07FB51A68108700A75B9A /* Images.xcassets */,
205 | 13B07FB61A68108700A75B9A /* Info.plist */,
206 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
207 | 13B07FB71A68108700A75B9A /* main.m */,
208 | );
209 | name = ReactChess;
210 | sourceTree = "";
211 | };
212 | 146834001AC3E56700842450 /* Products */ = {
213 | isa = PBXGroup;
214 | children = (
215 | 146834041AC3E56700842450 /* libReact.a */,
216 | );
217 | name = Products;
218 | sourceTree = "";
219 | };
220 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
221 | isa = PBXGroup;
222 | children = (
223 | AF1765BA1AC604B500AE3E79 /* RCTAnimation.xcodeproj */,
224 | 146833FF1AC3E56700842450 /* React.xcodeproj */,
225 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
226 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
227 | 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */,
228 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
229 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
230 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
231 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
232 | 00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */,
233 | 00481BE91AC0C89D00671115 /* libicucore.dylib */,
234 | );
235 | name = Libraries;
236 | sourceTree = "";
237 | };
238 | 832341B11AAA6A8300B99B32 /* Products */ = {
239 | isa = PBXGroup;
240 | children = (
241 | 832341B51AAA6A8300B99B32 /* libRCTText.a */,
242 | );
243 | name = Products;
244 | sourceTree = "";
245 | };
246 | 83CBB9F61A601CBA00E9B192 = {
247 | isa = PBXGroup;
248 | children = (
249 | 13B07FAE1A68108700A75B9A /* ReactChess */,
250 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
251 | 83CBBA001A601CBA00E9B192 /* Products */,
252 | );
253 | sourceTree = "";
254 | };
255 | 83CBBA001A601CBA00E9B192 /* Products */ = {
256 | isa = PBXGroup;
257 | children = (
258 | 13B07F961A680F5B00A75B9A /* ReactChess.app */,
259 | );
260 | name = Products;
261 | sourceTree = "";
262 | };
263 | AF1765BB1AC604B500AE3E79 /* Products */ = {
264 | isa = PBXGroup;
265 | children = (
266 | AF1765BF1AC604B500AE3E79 /* libRCTAnimation.a */,
267 | );
268 | name = Products;
269 | sourceTree = "";
270 | };
271 | /* End PBXGroup section */
272 |
273 | /* Begin PBXNativeTarget section */
274 | 13B07F861A680F5B00A75B9A /* ReactChess */ = {
275 | isa = PBXNativeTarget;
276 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactChess" */;
277 | buildPhases = (
278 | 13B07F871A680F5B00A75B9A /* Sources */,
279 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
280 | 13B07F8E1A680F5B00A75B9A /* Resources */,
281 | );
282 | buildRules = (
283 | );
284 | dependencies = (
285 | );
286 | name = ReactChess;
287 | productName = "Hello World";
288 | productReference = 13B07F961A680F5B00A75B9A /* ReactChess.app */;
289 | productType = "com.apple.product-type.application";
290 | };
291 | /* End PBXNativeTarget section */
292 |
293 | /* Begin PBXProject section */
294 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
295 | isa = PBXProject;
296 | attributes = {
297 | LastUpgradeCheck = 0610;
298 | ORGANIZATIONNAME = Facebook;
299 | };
300 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactChess" */;
301 | compatibilityVersion = "Xcode 3.2";
302 | developmentRegion = English;
303 | hasScannedForEncodings = 0;
304 | knownRegions = (
305 | en,
306 | Base,
307 | );
308 | mainGroup = 83CBB9F61A601CBA00E9B192;
309 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
310 | projectDirPath = "";
311 | projectReferences = (
312 | {
313 | ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
314 | ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
315 | },
316 | {
317 | ProductGroup = 00C302B01ABCB8E700DB3ED1 /* Products */;
318 | ProjectRef = 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */;
319 | },
320 | {
321 | ProductGroup = AF1765BB1AC604B500AE3E79 /* Products */;
322 | ProjectRef = AF1765BA1AC604B500AE3E79 /* RCTAnimation.xcodeproj */;
323 | },
324 | {
325 | ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
326 | ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
327 | },
328 | {
329 | ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
330 | ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
331 | },
332 | {
333 | ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
334 | ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
335 | },
336 | {
337 | ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
338 | ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
339 | },
340 | {
341 | ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
342 | ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
343 | },
344 | {
345 | ProductGroup = 00481BDC1AC0C7FA00671115 /* Products */;
346 | ProjectRef = 00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */;
347 | },
348 | {
349 | ProductGroup = 146834001AC3E56700842450 /* Products */;
350 | ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
351 | },
352 | );
353 | projectRoot = "";
354 | targets = (
355 | 13B07F861A680F5B00A75B9A /* ReactChess */,
356 | );
357 | };
358 | /* End PBXProject section */
359 |
360 | /* Begin PBXReferenceProxy section */
361 | 00481BE61AC0C7FA00671115 /* libRCTWebSocketDebugger.a */ = {
362 | isa = PBXReferenceProxy;
363 | fileType = archive.ar;
364 | path = libRCTWebSocketDebugger.a;
365 | remoteRef = 00481BE51AC0C7FA00671115 /* PBXContainerItemProxy */;
366 | sourceTree = BUILT_PRODUCTS_DIR;
367 | };
368 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
369 | isa = PBXReferenceProxy;
370 | fileType = archive.ar;
371 | path = libRCTActionSheet.a;
372 | remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
373 | sourceTree = BUILT_PRODUCTS_DIR;
374 | };
375 | 00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */ = {
376 | isa = PBXReferenceProxy;
377 | fileType = archive.ar;
378 | path = libRCTAdSupport.a;
379 | remoteRef = 00C302B31ABCB8E700DB3ED1 /* PBXContainerItemProxy */;
380 | sourceTree = BUILT_PRODUCTS_DIR;
381 | };
382 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
383 | isa = PBXReferenceProxy;
384 | fileType = archive.ar;
385 | path = libRCTGeolocation.a;
386 | remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
387 | sourceTree = BUILT_PRODUCTS_DIR;
388 | };
389 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
390 | isa = PBXReferenceProxy;
391 | fileType = archive.ar;
392 | path = libRCTImage.a;
393 | remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
394 | sourceTree = BUILT_PRODUCTS_DIR;
395 | };
396 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
397 | isa = PBXReferenceProxy;
398 | fileType = archive.ar;
399 | path = libRCTNetwork.a;
400 | remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
401 | sourceTree = BUILT_PRODUCTS_DIR;
402 | };
403 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
404 | isa = PBXReferenceProxy;
405 | fileType = archive.ar;
406 | path = libRCTVibration.a;
407 | remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
408 | sourceTree = BUILT_PRODUCTS_DIR;
409 | };
410 | 146834041AC3E56700842450 /* libReact.a */ = {
411 | isa = PBXReferenceProxy;
412 | fileType = archive.ar;
413 | path = libReact.a;
414 | remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
415 | sourceTree = BUILT_PRODUCTS_DIR;
416 | };
417 | 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
418 | isa = PBXReferenceProxy;
419 | fileType = archive.ar;
420 | path = libRCTText.a;
421 | remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
422 | sourceTree = BUILT_PRODUCTS_DIR;
423 | };
424 | AF1765BF1AC604B500AE3E79 /* libRCTAnimation.a */ = {
425 | isa = PBXReferenceProxy;
426 | fileType = archive.ar;
427 | path = libRCTAnimation.a;
428 | remoteRef = AF1765BE1AC604B500AE3E79 /* PBXContainerItemProxy */;
429 | sourceTree = BUILT_PRODUCTS_DIR;
430 | };
431 | /* End PBXReferenceProxy section */
432 |
433 | /* Begin PBXResourcesBuildPhase section */
434 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
435 | isa = PBXResourcesBuildPhase;
436 | buildActionMask = 2147483647;
437 | files = (
438 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
439 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
440 | );
441 | runOnlyForDeploymentPostprocessing = 0;
442 | };
443 | /* End PBXResourcesBuildPhase section */
444 |
445 | /* Begin PBXSourcesBuildPhase section */
446 | 13B07F871A680F5B00A75B9A /* Sources */ = {
447 | isa = PBXSourcesBuildPhase;
448 | buildActionMask = 2147483647;
449 | files = (
450 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
451 | 13B07FC11A68108700A75B9A /* main.m in Sources */,
452 | );
453 | runOnlyForDeploymentPostprocessing = 0;
454 | };
455 | /* End PBXSourcesBuildPhase section */
456 |
457 | /* Begin PBXVariantGroup section */
458 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
459 | isa = PBXVariantGroup;
460 | children = (
461 | 13B07FB21A68108700A75B9A /* Base */,
462 | );
463 | name = LaunchScreen.xib;
464 | path = iOS;
465 | sourceTree = "";
466 | };
467 | /* End PBXVariantGroup section */
468 |
469 | /* Begin XCBuildConfiguration section */
470 | 13B07F941A680F5B00A75B9A /* Debug */ = {
471 | isa = XCBuildConfiguration;
472 | buildSettings = {
473 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
474 | FRAMEWORK_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(DEVELOPER_FRAMEWORKS_DIR)",
477 | );
478 | HEADER_SEARCH_PATHS = (
479 | "$(inherited)",
480 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
481 | "$(SRCROOT)/node_modules/react-native/React/**",
482 | );
483 | INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist";
484 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
485 | OTHER_LDFLAGS = "-ObjC";
486 | PRODUCT_NAME = ReactChess;
487 | };
488 | name = Debug;
489 | };
490 | 13B07F951A680F5B00A75B9A /* Release */ = {
491 | isa = XCBuildConfiguration;
492 | buildSettings = {
493 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
494 | FRAMEWORK_SEARCH_PATHS = (
495 | "$(inherited)",
496 | "$(DEVELOPER_FRAMEWORKS_DIR)",
497 | );
498 | HEADER_SEARCH_PATHS = (
499 | "$(inherited)",
500 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
501 | "$(SRCROOT)/node_modules/react-native/React/**",
502 | );
503 | INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist";
504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
505 | OTHER_LDFLAGS = "-ObjC";
506 | PRODUCT_NAME = ReactChess;
507 | };
508 | name = Release;
509 | };
510 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
511 | isa = XCBuildConfiguration;
512 | buildSettings = {
513 | ALWAYS_SEARCH_USER_PATHS = NO;
514 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
515 | CLANG_CXX_LIBRARY = "libc++";
516 | CLANG_ENABLE_MODULES = YES;
517 | CLANG_ENABLE_OBJC_ARC = YES;
518 | CLANG_WARN_BOOL_CONVERSION = YES;
519 | CLANG_WARN_CONSTANT_CONVERSION = YES;
520 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
521 | CLANG_WARN_EMPTY_BODY = YES;
522 | CLANG_WARN_ENUM_CONVERSION = YES;
523 | CLANG_WARN_INT_CONVERSION = YES;
524 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
525 | CLANG_WARN_UNREACHABLE_CODE = YES;
526 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
527 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
528 | COPY_PHASE_STRIP = NO;
529 | ENABLE_STRICT_OBJC_MSGSEND = YES;
530 | GCC_C_LANGUAGE_STANDARD = gnu99;
531 | GCC_DYNAMIC_NO_PIC = NO;
532 | GCC_OPTIMIZATION_LEVEL = 0;
533 | GCC_PREPROCESSOR_DEFINITIONS = (
534 | "DEBUG=1",
535 | "$(inherited)",
536 | );
537 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
538 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
539 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
540 | GCC_WARN_UNDECLARED_SELECTOR = YES;
541 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
542 | GCC_WARN_UNUSED_FUNCTION = YES;
543 | GCC_WARN_UNUSED_VARIABLE = YES;
544 | HEADER_SEARCH_PATHS = (
545 | "$(inherited)",
546 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
547 | "$(SRCROOT)/node_modules/react-native/React/**",
548 | );
549 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
550 | MTL_ENABLE_DEBUG_INFO = YES;
551 | ONLY_ACTIVE_ARCH = YES;
552 | SDKROOT = iphoneos;
553 | };
554 | name = Debug;
555 | };
556 | 83CBBA211A601CBA00E9B192 /* Release */ = {
557 | isa = XCBuildConfiguration;
558 | buildSettings = {
559 | ALWAYS_SEARCH_USER_PATHS = NO;
560 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
561 | CLANG_CXX_LIBRARY = "libc++";
562 | CLANG_ENABLE_MODULES = YES;
563 | CLANG_ENABLE_OBJC_ARC = YES;
564 | CLANG_WARN_BOOL_CONVERSION = YES;
565 | CLANG_WARN_CONSTANT_CONVERSION = YES;
566 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
567 | CLANG_WARN_EMPTY_BODY = YES;
568 | CLANG_WARN_ENUM_CONVERSION = YES;
569 | CLANG_WARN_INT_CONVERSION = YES;
570 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
571 | CLANG_WARN_UNREACHABLE_CODE = YES;
572 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
573 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
574 | COPY_PHASE_STRIP = YES;
575 | ENABLE_NS_ASSERTIONS = NO;
576 | ENABLE_STRICT_OBJC_MSGSEND = YES;
577 | GCC_C_LANGUAGE_STANDARD = gnu99;
578 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
579 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
580 | GCC_WARN_UNDECLARED_SELECTOR = YES;
581 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
582 | GCC_WARN_UNUSED_FUNCTION = YES;
583 | GCC_WARN_UNUSED_VARIABLE = YES;
584 | HEADER_SEARCH_PATHS = (
585 | "$(inherited)",
586 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
587 | "$(SRCROOT)/node_modules/react-native/React/**",
588 | );
589 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
590 | MTL_ENABLE_DEBUG_INFO = NO;
591 | SDKROOT = iphoneos;
592 | VALIDATE_PRODUCT = YES;
593 | };
594 | name = Release;
595 | };
596 | /* End XCBuildConfiguration section */
597 |
598 | /* Begin XCConfigurationList section */
599 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactChess" */ = {
600 | isa = XCConfigurationList;
601 | buildConfigurations = (
602 | 13B07F941A680F5B00A75B9A /* Debug */,
603 | 13B07F951A680F5B00A75B9A /* Release */,
604 | );
605 | defaultConfigurationIsVisible = 0;
606 | defaultConfigurationName = Release;
607 | };
608 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactChess" */ = {
609 | isa = XCConfigurationList;
610 | buildConfigurations = (
611 | 83CBBA201A601CBA00E9B192 /* Debug */,
612 | 83CBBA211A601CBA00E9B192 /* Release */,
613 | );
614 | defaultConfigurationIsVisible = 0;
615 | defaultConfigurationName = Release;
616 | };
617 | /* End XCConfigurationList section */
618 | };
619 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
620 | }
621 |
--------------------------------------------------------------------------------
/javascript/chess.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /*
3 | * Copyright (c) 2014, Jeff Hlywa (jhlywa@gmail.com)
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * 1. Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *
27 | *----------------------------------------------------------------------------*/
28 |
29 | /* minified license below */
30 |
31 | /*! Copyright (c) 2014, Jeff Hlywa (jhlywa@gmail.com)
32 | * Released under the BSD license
33 | * https://github.com/jhlywa/chess.js/blob/master/LICENSE
34 | */
35 |
36 | var Chess = function(fen) {
37 |
38 | /* jshint indent: false */
39 |
40 | var BLACK = 'b';
41 | var WHITE = 'w';
42 |
43 | var EMPTY = -1;
44 |
45 | var PAWN = 'p';
46 | var KNIGHT = 'n';
47 | var BISHOP = 'b';
48 | var ROOK = 'r';
49 | var QUEEN = 'q';
50 | var KING = 'k';
51 |
52 | var SYMBOLS = 'pnbrqkPNBRQK';
53 |
54 | var DEFAULT_POSITION = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
55 |
56 | var POSSIBLE_RESULTS = ['1-0', '0-1', '1/2-1/2', '*'];
57 |
58 | var PAWN_OFFSETS = {
59 | b: [16, 32, 17, 15],
60 | w: [-16, -32, -17, -15]
61 | };
62 |
63 | var PIECE_OFFSETS = {
64 | n: [-18, -33, -31, -14, 18, 33, 31, 14],
65 | b: [-17, -15, 17, 15],
66 | r: [-16, 1, 16, -1],
67 | q: [-17, -16, -15, 1, 17, 16, 15, -1],
68 | k: [-17, -16, -15, 1, 17, 16, 15, -1]
69 | };
70 |
71 | var ATTACKS = [
72 | 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0,20, 0,
73 | 0,20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0,20, 0, 0,
74 | 0, 0,20, 0, 0, 0, 0, 24, 0, 0, 0, 0,20, 0, 0, 0,
75 | 0, 0, 0,20, 0, 0, 0, 24, 0, 0, 0,20, 0, 0, 0, 0,
76 | 0, 0, 0, 0,20, 0, 0, 24, 0, 0,20, 0, 0, 0, 0, 0,
77 | 0, 0, 0, 0, 0,20, 2, 24, 2,20, 0, 0, 0, 0, 0, 0,
78 | 0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
79 | 24,24,24,24,24,24,56, 0, 56,24,24,24,24,24,24, 0,
80 | 0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
81 | 0, 0, 0, 0, 0,20, 2, 24, 2,20, 0, 0, 0, 0, 0, 0,
82 | 0, 0, 0, 0,20, 0, 0, 24, 0, 0,20, 0, 0, 0, 0, 0,
83 | 0, 0, 0,20, 0, 0, 0, 24, 0, 0, 0,20, 0, 0, 0, 0,
84 | 0, 0,20, 0, 0, 0, 0, 24, 0, 0, 0, 0,20, 0, 0, 0,
85 | 0,20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0,20, 0, 0,
86 | 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0,20
87 | ];
88 |
89 | var RAYS = [
90 | 17, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 15, 0,
91 | 0, 17, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 0, 0,
92 | 0, 0, 17, 0, 0, 0, 0, 16, 0, 0, 0, 0, 15, 0, 0, 0,
93 | 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0,
94 | 0, 0, 0, 0, 17, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0,
95 | 0, 0, 0, 0, 0, 17, 0, 16, 0, 15, 0, 0, 0, 0, 0, 0,
96 | 0, 0, 0, 0, 0, 0, 17, 16, 15, 0, 0, 0, 0, 0, 0, 0,
97 | 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1,-1, -1, -1, -1, 0,
98 | 0, 0, 0, 0, 0, 0,-15,-16,-17, 0, 0, 0, 0, 0, 0, 0,
99 | 0, 0, 0, 0, 0,-15, 0,-16, 0,-17, 0, 0, 0, 0, 0, 0,
100 | 0, 0, 0, 0,-15, 0, 0,-16, 0, 0,-17, 0, 0, 0, 0, 0,
101 | 0, 0, 0,-15, 0, 0, 0,-16, 0, 0, 0,-17, 0, 0, 0, 0,
102 | 0, 0,-15, 0, 0, 0, 0,-16, 0, 0, 0, 0,-17, 0, 0, 0,
103 | 0,-15, 0, 0, 0, 0, 0,-16, 0, 0, 0, 0, 0,-17, 0, 0,
104 | -15, 0, 0, 0, 0, 0, 0,-16, 0, 0, 0, 0, 0, 0,-17
105 | ];
106 |
107 | var SHIFTS = { p: 0, n: 1, b: 2, r: 3, q: 4, k: 5 };
108 |
109 | var FLAGS = {
110 | NORMAL: 'n',
111 | CAPTURE: 'c',
112 | BIG_PAWN: 'b',
113 | EP_CAPTURE: 'e',
114 | PROMOTION: 'p',
115 | KSIDE_CASTLE: 'k',
116 | QSIDE_CASTLE: 'q'
117 | };
118 |
119 | var BITS = {
120 | NORMAL: 1,
121 | CAPTURE: 2,
122 | BIG_PAWN: 4,
123 | EP_CAPTURE: 8,
124 | PROMOTION: 16,
125 | KSIDE_CASTLE: 32,
126 | QSIDE_CASTLE: 64
127 | };
128 |
129 | var RANK_1 = 7;
130 | var RANK_2 = 6;
131 | var RANK_3 = 5;
132 | var RANK_4 = 4;
133 | var RANK_5 = 3;
134 | var RANK_6 = 2;
135 | var RANK_7 = 1;
136 | var RANK_8 = 0;
137 |
138 | var SQUARES = {
139 | a8: 0, b8: 1, c8: 2, d8: 3, e8: 4, f8: 5, g8: 6, h8: 7,
140 | a7: 16, b7: 17, c7: 18, d7: 19, e7: 20, f7: 21, g7: 22, h7: 23,
141 | a6: 32, b6: 33, c6: 34, d6: 35, e6: 36, f6: 37, g6: 38, h6: 39,
142 | a5: 48, b5: 49, c5: 50, d5: 51, e5: 52, f5: 53, g5: 54, h5: 55,
143 | a4: 64, b4: 65, c4: 66, d4: 67, e4: 68, f4: 69, g4: 70, h4: 71,
144 | a3: 80, b3: 81, c3: 82, d3: 83, e3: 84, f3: 85, g3: 86, h3: 87,
145 | a2: 96, b2: 97, c2: 98, d2: 99, e2: 100, f2: 101, g2: 102, h2: 103,
146 | a1: 112, b1: 113, c1: 114, d1: 115, e1: 116, f1: 117, g1: 118, h1: 119
147 | };
148 |
149 | var ROOKS = {
150 | w: [{square: SQUARES.a1, flag: BITS.QSIDE_CASTLE},
151 | {square: SQUARES.h1, flag: BITS.KSIDE_CASTLE}],
152 | b: [{square: SQUARES.a8, flag: BITS.QSIDE_CASTLE},
153 | {square: SQUARES.h8, flag: BITS.KSIDE_CASTLE}]
154 | };
155 |
156 | var board = new Array(128);
157 | var kings = {w: EMPTY, b: EMPTY};
158 | var turn = WHITE;
159 | var castling = {w: 0, b: 0};
160 | var ep_square = EMPTY;
161 | var half_moves = 0;
162 | var move_number = 1;
163 | var history = [];
164 | var header = {};
165 |
166 | /* if the user passes in a fen string, load it, else default to
167 | * starting position
168 | */
169 | if (typeof fen === 'undefined') {
170 | load(DEFAULT_POSITION);
171 | } else {
172 | load(fen);
173 | }
174 |
175 | function clear() {
176 | board = new Array(128);
177 | kings = {w: EMPTY, b: EMPTY};
178 | turn = WHITE;
179 | castling = {w: 0, b: 0};
180 | ep_square = EMPTY;
181 | half_moves = 0;
182 | move_number = 1;
183 | history = [];
184 | header = {};
185 | update_setup(generate_fen());
186 | }
187 |
188 | function reset() {
189 | load(DEFAULT_POSITION);
190 | }
191 |
192 | function load(fen) {
193 | var tokens = fen.split(/\s+/);
194 | var position = tokens[0];
195 | var square = 0;
196 | var valid = SYMBOLS + '12345678/';
197 |
198 | if (!validate_fen(fen).valid) {
199 | return false;
200 | }
201 |
202 | clear();
203 |
204 | for (var i = 0; i < position.length; i++) {
205 | var piece = position.charAt(i);
206 |
207 | if (piece === '/') {
208 | square += 8;
209 | } else if (is_digit(piece)) {
210 | square += parseInt(piece, 10);
211 | } else {
212 | var color = (piece < 'a') ? WHITE : BLACK;
213 | put({type: piece.toLowerCase(), color: color}, algebraic(square));
214 | square++;
215 | }
216 | }
217 |
218 | turn = tokens[1];
219 |
220 | if (tokens[2].indexOf('K') > -1) {
221 | castling.w |= BITS.KSIDE_CASTLE;
222 | }
223 | if (tokens[2].indexOf('Q') > -1) {
224 | castling.w |= BITS.QSIDE_CASTLE;
225 | }
226 | if (tokens[2].indexOf('k') > -1) {
227 | castling.b |= BITS.KSIDE_CASTLE;
228 | }
229 | if (tokens[2].indexOf('q') > -1) {
230 | castling.b |= BITS.QSIDE_CASTLE;
231 | }
232 |
233 | ep_square = (tokens[3] === '-') ? EMPTY : SQUARES[tokens[3]];
234 | half_moves = parseInt(tokens[4], 10);
235 | move_number = parseInt(tokens[5], 10);
236 |
237 | update_setup(generate_fen());
238 |
239 | return true;
240 | }
241 |
242 | function validate_fen(fen) {
243 | var errors = {
244 | 0: 'No errors.',
245 | 1: 'FEN string must contain six space-delimited fields.',
246 | 2: '6th field (move number) must be a positive integer.',
247 | 3: '5th field (half move counter) must be a non-negative integer.',
248 | 4: '4th field (en-passant square) is invalid.',
249 | 5: '3rd field (castling availability) is invalid.',
250 | 6: '2nd field (side to move) is invalid.',
251 | 7: '1st field (piece positions) does not contain 8 \'/\'-delimited rows.',
252 | 8: '1st field (piece positions) is invalid [consecutive numbers].',
253 | 9: '1st field (piece positions) is invalid [invalid piece].',
254 | 10: '1st field (piece positions) is invalid [row too large].',
255 | };
256 |
257 | /* 1st criterion: 6 space-seperated fields? */
258 | var tokens = fen.split(/\s+/);
259 | if (tokens.length !== 6) {
260 | return {valid: false, error_number: 1, error: errors[1]};
261 | }
262 |
263 | /* 2nd criterion: move number field is a integer value > 0? */
264 | if (isNaN(tokens[5]) || (parseInt(tokens[5], 10) <= 0)) {
265 | return {valid: false, error_number: 2, error: errors[2]};
266 | }
267 |
268 | /* 3rd criterion: half move counter is an integer >= 0? */
269 | if (isNaN(tokens[4]) || (parseInt(tokens[4], 10) < 0)) {
270 | return {valid: false, error_number: 3, error: errors[3]};
271 | }
272 |
273 | /* 4th criterion: 4th field is a valid e.p.-string? */
274 | if (!/^(-|[abcdefgh][36])$/.test(tokens[3])) {
275 | return {valid: false, error_number: 4, error: errors[4]};
276 | }
277 |
278 | /* 5th criterion: 3th field is a valid castle-string? */
279 | if( !/^(KQ?k?q?|Qk?q?|kq?|q|-)$/.test(tokens[2])) {
280 | return {valid: false, error_number: 5, error: errors[5]};
281 | }
282 |
283 | /* 6th criterion: 2nd field is "w" (white) or "b" (black)? */
284 | if (!/^(w|b)$/.test(tokens[1])) {
285 | return {valid: false, error_number: 6, error: errors[6]};
286 | }
287 |
288 | /* 7th criterion: 1st field contains 8 rows? */
289 | var rows = tokens[0].split('/');
290 | if (rows.length !== 8) {
291 | return {valid: false, error_number: 7, error: errors[7]};
292 | }
293 |
294 | /* 8th criterion: every row is valid? */
295 | for (var i = 0; i < rows.length; i++) {
296 | /* check for right sum of fields AND not two numbers in succession */
297 | var sum_fields = 0;
298 | var previous_was_number = false;
299 |
300 | for (var k = 0; k < rows[i].length; k++) {
301 | if (!isNaN(rows[i][k])) {
302 | if (previous_was_number) {
303 | return {valid: false, error_number: 8, error: errors[8]};
304 | }
305 | sum_fields += parseInt(rows[i][k], 10);
306 | previous_was_number = true;
307 | } else {
308 | if (!/^[prnbqkPRNBQK]$/.test(rows[i][k])) {
309 | return {valid: false, error_number: 9, error: errors[9]};
310 | }
311 | sum_fields += 1;
312 | previous_was_number = false;
313 | }
314 | }
315 | if (sum_fields !== 8) {
316 | return {valid: false, error_number: 10, error: errors[10]};
317 | }
318 | }
319 |
320 | /* everything's okay! */
321 | return {valid: true, error_number: 0, error: errors[0]};
322 | }
323 |
324 | function generate_fen() {
325 | var empty = 0;
326 | var fen = '';
327 |
328 | for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
329 | if (board[i] == null) {
330 | empty++;
331 | } else {
332 | if (empty > 0) {
333 | fen += empty;
334 | empty = 0;
335 | }
336 | var color = board[i].color;
337 | var piece = board[i].type;
338 |
339 | fen += (color === WHITE) ?
340 | piece.toUpperCase() : piece.toLowerCase();
341 | }
342 |
343 | if ((i + 1) & 0x88) {
344 | if (empty > 0) {
345 | fen += empty;
346 | }
347 |
348 | if (i !== SQUARES.h1) {
349 | fen += '/';
350 | }
351 |
352 | empty = 0;
353 | i += 8;
354 | }
355 | }
356 |
357 | var cflags = '';
358 | if (castling[WHITE] & BITS.KSIDE_CASTLE) { cflags += 'K'; }
359 | if (castling[WHITE] & BITS.QSIDE_CASTLE) { cflags += 'Q'; }
360 | if (castling[BLACK] & BITS.KSIDE_CASTLE) { cflags += 'k'; }
361 | if (castling[BLACK] & BITS.QSIDE_CASTLE) { cflags += 'q'; }
362 |
363 | /* do we have an empty castling flag? */
364 | cflags = cflags || '-';
365 | var epflags = (ep_square === EMPTY) ? '-' : algebraic(ep_square);
366 |
367 | return [fen, turn, cflags, epflags, half_moves, move_number].join(' ');
368 | }
369 |
370 | function set_header(args) {
371 | for (var i = 0; i < args.length; i += 2) {
372 | if (typeof args[i] === 'string' &&
373 | typeof args[i + 1] === 'string') {
374 | header[args[i]] = args[i + 1];
375 | }
376 | }
377 | return header;
378 | }
379 |
380 | /* called when the initial board setup is changed with put() or remove().
381 | * modifies the SetUp and FEN properties of the header object. if the FEN is
382 | * equal to the default position, the SetUp and FEN are deleted
383 | * the setup is only updated if history.length is zero, ie moves haven't been
384 | * made.
385 | */
386 | function update_setup(fen) {
387 | if (history.length > 0) return;
388 |
389 | if (fen !== DEFAULT_POSITION) {
390 | header['SetUp'] = '1';
391 | header['FEN'] = fen;
392 | } else {
393 | delete header['SetUp'];
394 | delete header['FEN'];
395 | }
396 | }
397 |
398 | function get(square) {
399 | var piece = board[SQUARES[square]];
400 | return (piece) ? {type: piece.type, color: piece.color} : null;
401 | }
402 |
403 | function put(piece, square) {
404 | /* check for valid piece object */
405 | if (!('type' in piece && 'color' in piece)) {
406 | return false;
407 | }
408 |
409 | /* check for piece */
410 | if (SYMBOLS.indexOf(piece.type.toLowerCase()) === -1) {
411 | return false;
412 | }
413 |
414 | /* check for valid square */
415 | if (!(square in SQUARES)) {
416 | return false;
417 | }
418 |
419 | var sq = SQUARES[square];
420 |
421 | /* don't let the user place more than one king */
422 | if (piece.type == KING &&
423 | !(kings[piece.color] == EMPTY || kings[piece.color] == sq)) {
424 | return false;
425 | }
426 |
427 | board[sq] = {type: piece.type, color: piece.color};
428 | if (piece.type === KING) {
429 | kings[piece.color] = sq;
430 | }
431 |
432 | update_setup(generate_fen());
433 |
434 | return true;
435 | }
436 |
437 | function remove(square) {
438 | var piece = get(square);
439 | board[SQUARES[square]] = null;
440 | if (piece && piece.type === KING) {
441 | kings[piece.color] = EMPTY;
442 | }
443 |
444 | update_setup(generate_fen());
445 |
446 | return piece;
447 | }
448 |
449 | function build_move(board, from, to, flags, promotion) {
450 | var move = {
451 | color: turn,
452 | from: from,
453 | to: to,
454 | flags: flags,
455 | piece: board[from].type
456 | };
457 |
458 | if (promotion) {
459 | move.flags |= BITS.PROMOTION;
460 | move.promotion = promotion;
461 | }
462 |
463 | if (board[to]) {
464 | move.captured = board[to].type;
465 | } else if (flags & BITS.EP_CAPTURE) {
466 | move.captured = PAWN;
467 | }
468 | return move;
469 | }
470 |
471 | function generate_moves(options) {
472 | function add_move(board, moves, from, to, flags) {
473 | /* if pawn promotion */
474 | if (board[from].type === PAWN &&
475 | (rank(to) === RANK_8 || rank(to) === RANK_1)) {
476 | var pieces = [QUEEN, ROOK, BISHOP, KNIGHT];
477 | for (var i = 0, len = pieces.length; i < len; i++) {
478 | moves.push(build_move(board, from, to, flags, pieces[i]));
479 | }
480 | } else {
481 | moves.push(build_move(board, from, to, flags));
482 | }
483 | }
484 |
485 | var moves = [];
486 | var us = turn;
487 | var them = swap_color(us);
488 | var second_rank = {b: RANK_7, w: RANK_2};
489 |
490 | var first_sq = SQUARES.a8;
491 | var last_sq = SQUARES.h1;
492 | var single_square = false;
493 |
494 | /* do we want legal moves? */
495 | var legal = (typeof options !== 'undefined' && 'legal' in options) ?
496 | options.legal : true;
497 |
498 | /* are we generating moves for a single square? */
499 | if (typeof options !== 'undefined' && 'square' in options) {
500 | if (options.square in SQUARES) {
501 | first_sq = last_sq = SQUARES[options.square];
502 | single_square = true;
503 | } else {
504 | /* invalid square */
505 | return [];
506 | }
507 | }
508 |
509 | for (var i = first_sq; i <= last_sq; i++) {
510 | /* did we run off the end of the board */
511 | if (i & 0x88) { i += 7; continue; }
512 |
513 | var piece = board[i];
514 | if (piece == null || piece.color !== us) {
515 | continue;
516 | }
517 |
518 | if (piece.type === PAWN) {
519 | /* single square, non-capturing */
520 | var square = i + PAWN_OFFSETS[us][0];
521 | if (board[square] == null) {
522 | add_move(board, moves, i, square, BITS.NORMAL);
523 |
524 | /* double square */
525 | var square = i + PAWN_OFFSETS[us][1];
526 | if (second_rank[us] === rank(i) && board[square] == null) {
527 | add_move(board, moves, i, square, BITS.BIG_PAWN);
528 | }
529 | }
530 |
531 | /* pawn captures */
532 | for (j = 2; j < 4; j++) {
533 | var square = i + PAWN_OFFSETS[us][j];
534 | if (square & 0x88) continue;
535 |
536 | if (board[square] != null &&
537 | board[square].color === them) {
538 | add_move(board, moves, i, square, BITS.CAPTURE);
539 | } else if (square === ep_square) {
540 | add_move(board, moves, i, ep_square, BITS.EP_CAPTURE);
541 | }
542 | }
543 | } else {
544 | for (var j = 0, len = PIECE_OFFSETS[piece.type].length; j < len; j++) {
545 | var offset = PIECE_OFFSETS[piece.type][j];
546 | var square = i;
547 |
548 | while (true) {
549 | square += offset;
550 | if (square & 0x88) break;
551 |
552 | if (board[square] == null) {
553 | add_move(board, moves, i, square, BITS.NORMAL);
554 | } else {
555 | if (board[square].color === us) break;
556 | add_move(board, moves, i, square, BITS.CAPTURE);
557 | break;
558 | }
559 |
560 | /* break, if knight or king */
561 | if (piece.type === 'n' || piece.type === 'k') break;
562 | }
563 | }
564 | }
565 | }
566 |
567 | /* check for castling if: a) we're generating all moves, or b) we're doing
568 | * single square move generation on the king's square
569 | */
570 | if ((!single_square) || last_sq === kings[us]) {
571 | /* king-side castling */
572 | if (castling[us] & BITS.KSIDE_CASTLE) {
573 | var castling_from = kings[us];
574 | var castling_to = castling_from + 2;
575 |
576 | if (board[castling_from + 1] == null &&
577 | board[castling_to] == null &&
578 | !attacked(them, kings[us]) &&
579 | !attacked(them, castling_from + 1) &&
580 | !attacked(them, castling_to)) {
581 | add_move(board, moves, kings[us] , castling_to,
582 | BITS.KSIDE_CASTLE);
583 | }
584 | }
585 |
586 | /* queen-side castling */
587 | if (castling[us] & BITS.QSIDE_CASTLE) {
588 | var castling_from = kings[us];
589 | var castling_to = castling_from - 2;
590 |
591 | if (board[castling_from - 1] == null &&
592 | board[castling_from - 2] == null &&
593 | board[castling_from - 3] == null &&
594 | !attacked(them, kings[us]) &&
595 | !attacked(them, castling_from - 1) &&
596 | !attacked(them, castling_to)) {
597 | add_move(board, moves, kings[us], castling_to,
598 | BITS.QSIDE_CASTLE);
599 | }
600 | }
601 | }
602 |
603 | /* return all pseudo-legal moves (this includes moves that allow the king
604 | * to be captured)
605 | */
606 | if (!legal) {
607 | return moves;
608 | }
609 |
610 | /* filter out illegal moves */
611 | var legal_moves = [];
612 | for (var i = 0, len = moves.length; i < len; i++) {
613 | make_move(moves[i]);
614 | if (!king_attacked(us)) {
615 | legal_moves.push(moves[i]);
616 | }
617 | undo_move();
618 | }
619 |
620 | return legal_moves;
621 | }
622 |
623 | /* convert a move from 0x88 coordinates to Standard Algebraic Notation
624 | * (SAN)
625 | */
626 | function move_to_san(move) {
627 | var output = '';
628 |
629 | if (move.flags & BITS.KSIDE_CASTLE) {
630 | output = 'O-O';
631 | } else if (move.flags & BITS.QSIDE_CASTLE) {
632 | output = 'O-O-O';
633 | } else {
634 | var disambiguator = get_disambiguator(move);
635 |
636 | if (move.piece !== PAWN) {
637 | output += move.piece.toUpperCase() + disambiguator;
638 | }
639 |
640 | if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {
641 | if (move.piece === PAWN) {
642 | output += algebraic(move.from)[0];
643 | }
644 | output += 'x';
645 | }
646 |
647 | output += algebraic(move.to);
648 |
649 | if (move.flags & BITS.PROMOTION) {
650 | output += '=' + move.promotion.toUpperCase();
651 | }
652 | }
653 |
654 | make_move(move);
655 | if (in_check()) {
656 | if (in_checkmate()) {
657 | output += '#';
658 | } else {
659 | output += '+';
660 | }
661 | }
662 | undo_move();
663 |
664 | return output;
665 | }
666 |
667 | function attacked(color, square) {
668 | for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
669 | /* did we run off the end of the board */
670 | if (i & 0x88) { i += 7; continue; }
671 |
672 | /* if empty square or wrong color */
673 | if (board[i] == null || board[i].color !== color) continue;
674 |
675 | var piece = board[i];
676 | var difference = i - square;
677 | var index = difference + 119;
678 |
679 | if (ATTACKS[index] & (1 << SHIFTS[piece.type])) {
680 | if (piece.type === PAWN) {
681 | if (difference > 0) {
682 | if (piece.color === WHITE) return true;
683 | } else {
684 | if (piece.color === BLACK) return true;
685 | }
686 | continue;
687 | }
688 |
689 | /* if the piece is a knight or a king */
690 | if (piece.type === 'n' || piece.type === 'k') return true;
691 |
692 | var offset = RAYS[index];
693 | var j = i + offset;
694 |
695 | var blocked = false;
696 | while (j !== square) {
697 | if (board[j] != null) { blocked = true; break; }
698 | j += offset;
699 | }
700 |
701 | if (!blocked) return true;
702 | }
703 | }
704 |
705 | return false;
706 | }
707 |
708 | function king_attacked(color) {
709 | return attacked(swap_color(color), kings[color]);
710 | }
711 |
712 | function in_check() {
713 | return king_attacked(turn);
714 | }
715 |
716 | function in_checkmate() {
717 | return in_check() && generate_moves().length === 0;
718 | }
719 |
720 | function in_stalemate() {
721 | return !in_check() && generate_moves().length === 0;
722 | }
723 |
724 | function insufficient_material() {
725 | var pieces = {};
726 | var bishops = [];
727 | var num_pieces = 0;
728 | var sq_color = 0;
729 |
730 | for (var i = SQUARES.a8; i<= SQUARES.h1; i++) {
731 | sq_color = (sq_color + 1) % 2;
732 | if (i & 0x88) { i += 7; continue; }
733 |
734 | var piece = board[i];
735 | if (piece) {
736 | pieces[piece.type] = (piece.type in pieces) ?
737 | pieces[piece.type] + 1 : 1;
738 | if (piece.type === BISHOP) {
739 | bishops.push(sq_color);
740 | }
741 | num_pieces++;
742 | }
743 | }
744 |
745 | /* k vs. k */
746 | if (num_pieces === 2) { return true; }
747 |
748 | /* k vs. kn .... or .... k vs. kb */
749 | else if (num_pieces === 3 && (pieces[BISHOP] === 1 ||
750 | pieces[KNIGHT] === 1)) { return true; }
751 |
752 | /* kb vs. kb where any number of bishops are all on the same color */
753 | else if (num_pieces === pieces[BISHOP] + 2) {
754 | var sum = 0;
755 | var len = bishops.length;
756 | for (var i = 0; i < len; i++) {
757 | sum += bishops[i];
758 | }
759 | if (sum === 0 || sum === len) { return true; }
760 | }
761 |
762 | return false;
763 | }
764 |
765 | function in_threefold_repetition() {
766 | /* TODO: while this function is fine for casual use, a better
767 | * implementation would use a Zobrist key (instead of FEN). the
768 | * Zobrist key would be maintained in the make_move/undo_move functions,
769 | * avoiding the costly that we do below.
770 | */
771 | var moves = [];
772 | var positions = {};
773 | var repetition = false;
774 |
775 | while (true) {
776 | var move = undo_move();
777 | if (!move) break;
778 | moves.push(move);
779 | }
780 |
781 | while (true) {
782 | /* remove the last two fields in the FEN string, they're not needed
783 | * when checking for draw by rep */
784 | var fen = generate_fen().split(' ').slice(0,4).join(' ');
785 |
786 | /* has the position occurred three or move times */
787 | positions[fen] = (fen in positions) ? positions[fen] + 1 : 1;
788 | if (positions[fen] >= 3) {
789 | repetition = true;
790 | }
791 |
792 | if (!moves.length) {
793 | break;
794 | }
795 | make_move(moves.pop());
796 | }
797 |
798 | return repetition;
799 | }
800 |
801 | function push(move) {
802 | history.push({
803 | move: move,
804 | kings: {b: kings.b, w: kings.w},
805 | turn: turn,
806 | castling: {b: castling.b, w: castling.w},
807 | ep_square: ep_square,
808 | half_moves: half_moves,
809 | move_number: move_number
810 | });
811 | }
812 |
813 | function make_move(move) {
814 | var us = turn;
815 | var them = swap_color(us);
816 | push(move);
817 |
818 | board[move.to] = board[move.from];
819 | board[move.from] = null;
820 |
821 | /* if ep capture, remove the captured pawn */
822 | if (move.flags & BITS.EP_CAPTURE) {
823 | if (turn === BLACK) {
824 | board[move.to - 16] = null;
825 | } else {
826 | board[move.to + 16] = null;
827 | }
828 | }
829 |
830 | /* if pawn promotion, replace with new piece */
831 | if (move.flags & BITS.PROMOTION) {
832 | board[move.to] = {type: move.promotion, color: us};
833 | }
834 |
835 | /* if we moved the king */
836 | if (board[move.to].type === KING) {
837 | kings[board[move.to].color] = move.to;
838 |
839 | /* if we castled, move the rook next to the king */
840 | if (move.flags & BITS.KSIDE_CASTLE) {
841 | var castling_to = move.to - 1;
842 | var castling_from = move.to + 1;
843 | board[castling_to] = board[castling_from];
844 | board[castling_from] = null;
845 | } else if (move.flags & BITS.QSIDE_CASTLE) {
846 | var castling_to = move.to + 1;
847 | var castling_from = move.to - 2;
848 | board[castling_to] = board[castling_from];
849 | board[castling_from] = null;
850 | }
851 |
852 | /* turn off castling */
853 | castling[us] = '';
854 | }
855 |
856 | /* turn off castling if we move a rook */
857 | if (castling[us]) {
858 | for (var i = 0, len = ROOKS[us].length; i < len; i++) {
859 | if (move.from === ROOKS[us][i].square &&
860 | castling[us] & ROOKS[us][i].flag) {
861 | castling[us] ^= ROOKS[us][i].flag;
862 | break;
863 | }
864 | }
865 | }
866 |
867 | /* turn off castling if we capture a rook */
868 | if (castling[them]) {
869 | for (var i = 0, len = ROOKS[them].length; i < len; i++) {
870 | if (move.to === ROOKS[them][i].square &&
871 | castling[them] & ROOKS[them][i].flag) {
872 | castling[them] ^= ROOKS[them][i].flag;
873 | break;
874 | }
875 | }
876 | }
877 |
878 | /* if big pawn move, update the en passant square */
879 | if (move.flags & BITS.BIG_PAWN) {
880 | if (turn === 'b') {
881 | ep_square = move.to - 16;
882 | } else {
883 | ep_square = move.to + 16;
884 | }
885 | } else {
886 | ep_square = EMPTY;
887 | }
888 |
889 | /* reset the 50 move counter if a pawn is moved or a piece is captured */
890 | if (move.piece === PAWN) {
891 | half_moves = 0;
892 | } else if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {
893 | half_moves = 0;
894 | } else {
895 | half_moves++;
896 | }
897 |
898 | if (turn === BLACK) {
899 | move_number++;
900 | }
901 | turn = swap_color(turn);
902 | }
903 |
904 | function undo_move() {
905 | var old = history.pop();
906 | if (old == null) { return null; }
907 |
908 | var move = old.move;
909 | kings = old.kings;
910 | turn = old.turn;
911 | castling = old.castling;
912 | ep_square = old.ep_square;
913 | half_moves = old.half_moves;
914 | move_number = old.move_number;
915 |
916 | var us = turn;
917 | var them = swap_color(turn);
918 |
919 | board[move.from] = board[move.to];
920 | board[move.from].type = move.piece; // to undo any promotions
921 | board[move.to] = null;
922 |
923 | if (move.flags & BITS.CAPTURE) {
924 | board[move.to] = {type: move.captured, color: them};
925 | } else if (move.flags & BITS.EP_CAPTURE) {
926 | var index;
927 | if (us === BLACK) {
928 | index = move.to - 16;
929 | } else {
930 | index = move.to + 16;
931 | }
932 | board[index] = {type: PAWN, color: them};
933 | }
934 |
935 |
936 | if (move.flags & (BITS.KSIDE_CASTLE | BITS.QSIDE_CASTLE)) {
937 | var castling_to, castling_from;
938 | if (move.flags & BITS.KSIDE_CASTLE) {
939 | castling_to = move.to + 1;
940 | castling_from = move.to - 1;
941 | } else if (move.flags & BITS.QSIDE_CASTLE) {
942 | castling_to = move.to - 2;
943 | castling_from = move.to + 1;
944 | }
945 |
946 | board[castling_to] = board[castling_from];
947 | board[castling_from] = null;
948 | }
949 |
950 | return move;
951 | }
952 |
953 | /* this function is used to uniquely identify ambiguous moves */
954 | function get_disambiguator(move) {
955 | var moves = generate_moves();
956 |
957 | var from = move.from;
958 | var to = move.to;
959 | var piece = move.piece;
960 |
961 | var ambiguities = 0;
962 | var same_rank = 0;
963 | var same_file = 0;
964 |
965 | for (var i = 0, len = moves.length; i < len; i++) {
966 | var ambig_from = moves[i].from;
967 | var ambig_to = moves[i].to;
968 | var ambig_piece = moves[i].piece;
969 |
970 | /* if a move of the same piece type ends on the same to square, we'll
971 | * need to add a disambiguator to the algebraic notation
972 | */
973 | if (piece === ambig_piece && from !== ambig_from && to === ambig_to) {
974 | ambiguities++;
975 |
976 | if (rank(from) === rank(ambig_from)) {
977 | same_rank++;
978 | }
979 |
980 | if (file(from) === file(ambig_from)) {
981 | same_file++;
982 | }
983 | }
984 | }
985 |
986 | if (ambiguities > 0) {
987 | /* if there exists a similar moving piece on the same rank and file as
988 | * the move in question, use the square as the disambiguator
989 | */
990 | if (same_rank > 0 && same_file > 0) {
991 | return algebraic(from);
992 | }
993 | /* if the moving piece rests on the same file, use the rank symbol as the
994 | * disambiguator
995 | */
996 | else if (same_file > 0) {
997 | return algebraic(from).charAt(1);
998 | }
999 | /* else use the file symbol */
1000 | else {
1001 | return algebraic(from).charAt(0);
1002 | }
1003 | }
1004 |
1005 | return '';
1006 | }
1007 |
1008 | function ascii() {
1009 | var s = ' +------------------------+\n';
1010 | for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
1011 | /* display the rank */
1012 | if (file(i) === 0) {
1013 | s += ' ' + '87654321'[rank(i)] + ' |';
1014 | }
1015 |
1016 | /* empty piece */
1017 | if (board[i] == null) {
1018 | s += ' . ';
1019 | } else {
1020 | var piece = board[i].type;
1021 | var color = board[i].color;
1022 | var symbol = (color === WHITE) ?
1023 | piece.toUpperCase() : piece.toLowerCase();
1024 | s += ' ' + symbol + ' ';
1025 | }
1026 |
1027 | if ((i + 1) & 0x88) {
1028 | s += '|\n';
1029 | i += 8;
1030 | }
1031 | }
1032 | s += ' +------------------------+\n';
1033 | s += ' a b c d e f g h\n';
1034 |
1035 | return s;
1036 | }
1037 |
1038 | /*****************************************************************************
1039 | * UTILITY FUNCTIONS
1040 | ****************************************************************************/
1041 | function rank(i) {
1042 | return i >> 4;
1043 | }
1044 |
1045 | function file(i) {
1046 | return i & 15;
1047 | }
1048 |
1049 | function algebraic(i){
1050 | var f = file(i), r = rank(i);
1051 | return 'abcdefgh'.substring(f,f+1) + '87654321'.substring(r,r+1);
1052 | }
1053 |
1054 | function swap_color(c) {
1055 | return c === WHITE ? BLACK : WHITE;
1056 | }
1057 |
1058 | function is_digit(c) {
1059 | return '0123456789'.indexOf(c) !== -1;
1060 | }
1061 |
1062 | /* pretty = external move object */
1063 | function make_pretty(ugly_move) {
1064 | var move = clone(ugly_move);
1065 | move.san = move_to_san(move);
1066 | move.to = algebraic(move.to);
1067 | move.from = algebraic(move.from);
1068 |
1069 | var flags = '';
1070 |
1071 | for (var flag in BITS) {
1072 | if (BITS[flag] & move.flags) {
1073 | flags += FLAGS[flag];
1074 | }
1075 | }
1076 | move.flags = flags;
1077 |
1078 | return move;
1079 | }
1080 |
1081 | function clone(obj) {
1082 | var dupe = (obj instanceof Array) ? [] : {};
1083 |
1084 | for (var property in obj) {
1085 | if (typeof property === 'object') {
1086 | dupe[property] = clone(obj[property]);
1087 | } else {
1088 | dupe[property] = obj[property];
1089 | }
1090 | }
1091 |
1092 | return dupe;
1093 | }
1094 |
1095 | function trim(str) {
1096 | return str.replace(/^\s+|\s+$/g, '');
1097 | }
1098 |
1099 | /*****************************************************************************
1100 | * DEBUGGING UTILITIES
1101 | ****************************************************************************/
1102 | function perft(depth) {
1103 | var moves = generate_moves({legal: false});
1104 | var nodes = 0;
1105 | var color = turn;
1106 |
1107 | for (var i = 0, len = moves.length; i < len; i++) {
1108 | make_move(moves[i]);
1109 | if (!king_attacked(color)) {
1110 | if (depth - 1 > 0) {
1111 | var child_nodes = perft(depth - 1);
1112 | nodes += child_nodes;
1113 | } else {
1114 | nodes++;
1115 | }
1116 | }
1117 | undo_move();
1118 | }
1119 |
1120 | return nodes;
1121 | }
1122 |
1123 | return {
1124 | /***************************************************************************
1125 | * PUBLIC CONSTANTS (is there a better way to do this?)
1126 | **************************************************************************/
1127 | WHITE: WHITE,
1128 | BLACK: BLACK,
1129 | PAWN: PAWN,
1130 | KNIGHT: KNIGHT,
1131 | BISHOP: BISHOP,
1132 | ROOK: ROOK,
1133 | QUEEN: QUEEN,
1134 | KING: KING,
1135 | SQUARES: (function() {
1136 | /* from the ECMA-262 spec (section 12.6.4):
1137 | * "The mechanics of enumerating the properties ... is
1138 | * implementation dependent"
1139 | * so: for (var sq in SQUARES) { keys.push(sq); } might not be
1140 | * ordered correctly
1141 | */
1142 | var keys = [];
1143 | for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
1144 | if (i & 0x88) { i += 7; continue; }
1145 | keys.push(algebraic(i));
1146 | }
1147 | return keys;
1148 | })(),
1149 | FLAGS: FLAGS,
1150 |
1151 | /***************************************************************************
1152 | * PUBLIC API
1153 | **************************************************************************/
1154 | load: function(fen) {
1155 | return load(fen);
1156 | },
1157 |
1158 | reset: function() {
1159 | return reset();
1160 | },
1161 |
1162 | moves: function(options) {
1163 | /* The internal representation of a chess move is in 0x88 format, and
1164 | * not meant to be human-readable. The code below converts the 0x88
1165 | * square coordinates to algebraic coordinates. It also prunes an
1166 | * unnecessary move keys resulting from a verbose call.
1167 | */
1168 |
1169 | var ugly_moves = generate_moves(options);
1170 | var moves = [];
1171 |
1172 | for (var i = 0, len = ugly_moves.length; i < len; i++) {
1173 |
1174 | /* does the user want a full move object (most likely not), or just
1175 | * SAN
1176 | */
1177 | if (typeof options !== 'undefined' && 'verbose' in options &&
1178 | options.verbose) {
1179 | moves.push(make_pretty(ugly_moves[i]));
1180 | } else {
1181 | moves.push(move_to_san(ugly_moves[i]));
1182 | }
1183 | }
1184 |
1185 | return moves;
1186 | },
1187 |
1188 | in_check: function() {
1189 | return in_check();
1190 | },
1191 |
1192 | in_checkmate: function() {
1193 | return in_checkmate();
1194 | },
1195 |
1196 | in_stalemate: function() {
1197 | return in_stalemate();
1198 | },
1199 |
1200 | in_draw: function() {
1201 | return half_moves >= 100 ||
1202 | in_stalemate() ||
1203 | insufficient_material() ||
1204 | in_threefold_repetition();
1205 | },
1206 |
1207 | insufficient_material: function() {
1208 | return insufficient_material();
1209 | },
1210 |
1211 | in_threefold_repetition: function() {
1212 | return in_threefold_repetition();
1213 | },
1214 |
1215 | game_over: function() {
1216 | return half_moves >= 100 ||
1217 | in_checkmate() ||
1218 | in_stalemate() ||
1219 | insufficient_material() ||
1220 | in_threefold_repetition();
1221 | },
1222 |
1223 | validate_fen: function(fen) {
1224 | return validate_fen(fen);
1225 | },
1226 |
1227 | fen: function() {
1228 | return generate_fen();
1229 | },
1230 |
1231 | pgn: function(options) {
1232 | /* using the specification from http://www.chessclub.com/help/PGN-spec
1233 | * example for html usage: .pgn({ max_width: 72, newline_char: "
" })
1234 | */
1235 | var newline = (typeof options === 'object' &&
1236 | typeof options.newline_char === 'string') ?
1237 | options.newline_char : '\n';
1238 | var max_width = (typeof options === 'object' &&
1239 | typeof options.max_width === 'number') ?
1240 | options.max_width : 0;
1241 | var result = [];
1242 | var header_exists = false;
1243 |
1244 | /* add the PGN header headerrmation */
1245 | for (var i in header) {
1246 | /* TODO: order of enumerated properties in header object is not
1247 | * guaranteed, see ECMA-262 spec (section 12.6.4)
1248 | */
1249 | result.push('[' + i + ' \"' + header[i] + '\"]' + newline);
1250 | header_exists = true;
1251 | }
1252 |
1253 | if (header_exists && history.length) {
1254 | result.push(newline);
1255 | }
1256 |
1257 | /* pop all of history onto reversed_history */
1258 | var reversed_history = [];
1259 | while (history.length > 0) {
1260 | reversed_history.push(undo_move());
1261 | }
1262 |
1263 | var moves = [];
1264 | var move_string = '';
1265 | var pgn_move_number = 1;
1266 |
1267 | /* build the list of moves. a move_string looks like: "3. e3 e6" */
1268 | while (reversed_history.length > 0) {
1269 | var move = reversed_history.pop();
1270 |
1271 | /* if the position started with black to move, start PGN with 1. ... */
1272 | if (pgn_move_number === 1 && move.color === 'b') {
1273 | move_string = '1. ...';
1274 | pgn_move_number++;
1275 | } else if (move.color === 'w') {
1276 | /* store the previous generated move_string if we have one */
1277 | if (move_string.length) {
1278 | moves.push(move_string);
1279 | }
1280 | move_string = pgn_move_number + '.';
1281 | pgn_move_number++;
1282 | }
1283 |
1284 | move_string = move_string + ' ' + move_to_san(move);
1285 | make_move(move);
1286 | }
1287 |
1288 | /* are there any other leftover moves? */
1289 | if (move_string.length) {
1290 | moves.push(move_string);
1291 | }
1292 |
1293 | /* is there a result? */
1294 | if (typeof header.Result !== 'undefined') {
1295 | moves.push(header.Result);
1296 | }
1297 |
1298 | /* history should be back to what is was before we started generating PGN,
1299 | * so join together moves
1300 | */
1301 | if (max_width === 0) {
1302 | return result.join('') + moves.join(' ');
1303 | }
1304 |
1305 | /* wrap the PGN output at max_width */
1306 | var current_width = 0;
1307 | for (var i = 0; i < moves.length; i++) {
1308 | /* if the current move will push past max_width */
1309 | if (current_width + moves[i].length > max_width && i !== 0) {
1310 |
1311 | /* don't end the line with whitespace */
1312 | if (result[result.length - 1] === ' ') {
1313 | result.pop();
1314 | }
1315 |
1316 | result.push(newline);
1317 | current_width = 0;
1318 | } else if (i !== 0) {
1319 | result.push(' ');
1320 | current_width++;
1321 | }
1322 | result.push(moves[i]);
1323 | current_width += moves[i].length;
1324 | }
1325 |
1326 | return result.join('');
1327 | },
1328 |
1329 | load_pgn: function(pgn, options) {
1330 | function mask(str) {
1331 | return str.replace(/\\/g, '\\');
1332 | }
1333 |
1334 | /* convert a move from Standard Algebraic Notation (SAN) to 0x88
1335 | * coordinates
1336 | */
1337 | function move_from_san(move) {
1338 | var moves = generate_moves();
1339 | for (var i = 0, len = moves.length; i < len; i++) {
1340 | /* strip off any trailing move decorations: e.g Nf3+?! */
1341 | if (move.replace(/[+#?!=]+$/,'') ==
1342 | move_to_san(moves[i]).replace(/[+#?!=]+$/,'')) {
1343 | return moves[i];
1344 | }
1345 | }
1346 | return null;
1347 | }
1348 |
1349 | function get_move_obj(move) {
1350 | return move_from_san(trim(move));
1351 | }
1352 |
1353 | function has_keys(object) {
1354 | var has_keys = false;
1355 | for (var key in object) {
1356 | has_keys = true;
1357 | }
1358 | return has_keys;
1359 | }
1360 |
1361 | function parse_pgn_header(header, options) {
1362 | var newline_char = (typeof options === 'object' &&
1363 | typeof options.newline_char === 'string') ?
1364 | options.newline_char : '\r?\n';
1365 | var header_obj = {};
1366 | var headers = header.split(new RegExp(mask(newline_char)));
1367 | var key = '';
1368 | var value = '';
1369 |
1370 | for (var i = 0; i < headers.length; i++) {
1371 | key = headers[i].replace(/^\[([A-Z][A-Za-z]*)\s.*\]$/, '$1');
1372 | value = headers[i].replace(/^\[[A-Za-z]+\s"(.*)"\]$/, '$1');
1373 | if (trim(key).length > 0) {
1374 | header_obj[key] = value;
1375 | }
1376 | }
1377 |
1378 | return header_obj;
1379 | }
1380 |
1381 | var newline_char = (typeof options === 'object' &&
1382 | typeof options.newline_char === 'string') ?
1383 | options.newline_char : '\r?\n';
1384 | var regex = new RegExp('^(\\[(.|' + mask(newline_char) + ')*\\])' +
1385 | '(' + mask(newline_char) + ')*' +
1386 | '1.(' + mask(newline_char) + '|.)*$', 'g');
1387 |
1388 | /* get header part of the PGN file */
1389 | var header_string = pgn.replace(regex, '$1');
1390 |
1391 | /* no info part given, begins with moves */
1392 | if (header_string[0] !== '[') {
1393 | header_string = '';
1394 | }
1395 |
1396 | reset();
1397 |
1398 | /* parse PGN header */
1399 | var headers = parse_pgn_header(header_string, options);
1400 | for (var key in headers) {
1401 | set_header([key, headers[key]]);
1402 | }
1403 |
1404 | /* delete header to get the moves */
1405 | var ms = pgn.replace(header_string, '').replace(new RegExp(mask(newline_char), 'g'), ' ');
1406 |
1407 | /* delete comments */
1408 | ms = ms.replace(/(\{[^}]+\})+?/g, '');
1409 |
1410 | /* delete move numbers */
1411 | ms = ms.replace(/\d+\./g, '');
1412 |
1413 |
1414 | /* trim and get array of moves */
1415 | var moves = trim(ms).split(new RegExp(/\s+/));
1416 |
1417 | /* delete empty entries */
1418 | moves = moves.join(',').replace(/,,+/g, ',').split(',');
1419 | var move = '';
1420 |
1421 | for (var half_move = 0; half_move < moves.length - 1; half_move++) {
1422 | move = get_move_obj(moves[half_move]);
1423 |
1424 | /* move not possible! (don't clear the board to examine to show the
1425 | * latest valid position)
1426 | */
1427 | if (move == null) {
1428 | return false;
1429 | } else {
1430 | make_move(move);
1431 | }
1432 | }
1433 |
1434 | /* examine last move */
1435 | move = moves[moves.length - 1];
1436 | if (POSSIBLE_RESULTS.indexOf(move) > -1) {
1437 | if (has_keys(header) && typeof header.Result === 'undefined') {
1438 | set_header(['Result', move]);
1439 | }
1440 | }
1441 | else {
1442 | move = get_move_obj(move);
1443 | if (move == null) {
1444 | return false;
1445 | } else {
1446 | make_move(move);
1447 | }
1448 | }
1449 | return true;
1450 | },
1451 |
1452 | header: function() {
1453 | return set_header(arguments);
1454 | },
1455 |
1456 | ascii: function() {
1457 | return ascii();
1458 | },
1459 |
1460 | turn: function() {
1461 | return turn;
1462 | },
1463 |
1464 | move: function(move) {
1465 | /* The move function can be called with in the following parameters:
1466 | *
1467 | * .move('Nxb7') <- where 'move' is a case-sensitive SAN string
1468 | *
1469 | * .move({ from: 'h7', <- where the 'move' is a move object (additional
1470 | * to :'h8', fields are ignored)
1471 | * promotion: 'q',
1472 | * })
1473 | */
1474 | var move_obj = null;
1475 | var moves = generate_moves();
1476 |
1477 | if (typeof move === 'string') {
1478 | /* convert the move string to a move object */
1479 | for (var i = 0, len = moves.length; i < len; i++) {
1480 | if (move === move_to_san(moves[i])) {
1481 | move_obj = moves[i];
1482 | break;
1483 | }
1484 | }
1485 | } else if (typeof move === 'object') {
1486 | /* convert the pretty move object to an ugly move object */
1487 | for (var i = 0, len = moves.length; i < len; i++) {
1488 | if (move.from === algebraic(moves[i].from) &&
1489 | move.to === algebraic(moves[i].to) &&
1490 | (!('promotion' in moves[i]) ||
1491 | move.promotion === moves[i].promotion)) {
1492 | move_obj = moves[i];
1493 | break;
1494 | }
1495 | }
1496 | }
1497 |
1498 | /* failed to find move */
1499 | if (!move_obj) {
1500 | return null;
1501 | }
1502 |
1503 | /* need to make a copy of move because we can't generate SAN after the
1504 | * move is made
1505 | */
1506 | var pretty_move = make_pretty(move_obj);
1507 |
1508 | make_move(move_obj);
1509 |
1510 | return pretty_move;
1511 | },
1512 |
1513 | undo: function() {
1514 | var move = undo_move();
1515 | return (move) ? make_pretty(move) : null;
1516 | },
1517 |
1518 | clear: function() {
1519 | return clear();
1520 | },
1521 |
1522 | put: function(piece, square) {
1523 | return put(piece, square);
1524 | },
1525 |
1526 | get: function(square) {
1527 | return get(square);
1528 | },
1529 |
1530 | remove: function(square) {
1531 | return remove(square);
1532 | },
1533 |
1534 | perft: function(depth) {
1535 | return perft(depth);
1536 | },
1537 |
1538 | square_color: function(square) {
1539 | if (square in SQUARES) {
1540 | var sq_0x88 = SQUARES[square];
1541 | return ((rank(sq_0x88) + file(sq_0x88)) % 2 === 0) ? 'light' : 'dark';
1542 | }
1543 |
1544 | return null;
1545 | },
1546 |
1547 | history: function(options) {
1548 | var reversed_history = [];
1549 | var move_history = [];
1550 | var verbose = (typeof options !== 'undefined' && 'verbose' in options &&
1551 | options.verbose);
1552 |
1553 | while (history.length > 0) {
1554 | reversed_history.push(undo_move());
1555 | }
1556 |
1557 | while (reversed_history.length > 0) {
1558 | var move = reversed_history.pop();
1559 | if (verbose) {
1560 | move_history.push(make_pretty(move));
1561 | } else {
1562 | move_history.push(move_to_san(move));
1563 | }
1564 | make_move(move);
1565 | }
1566 |
1567 | return move_history;
1568 | }
1569 |
1570 | };
1571 | };
1572 |
1573 | module.exports = Chess;
--------------------------------------------------------------------------------