Browse Source

render chessboard from FEN

romanmatiasko 9 years ago
parent
commit
c32084701c

+ 2 - 1
gulpfile.js

@@ -29,7 +29,8 @@ var dependencies = [
   'react/addons',
   'immutable',
   'flux',
-  'eventemitter2'
+  'eventemitter2',
+  'chess.js'
 ];
 
 var browserifyTask = function() {

+ 2 - 2
src/js/components/Chat.js

@@ -8,8 +8,8 @@ const Chat = React.createClass({
   
   propTypes: {
     io: React.PropTypes.object.isRequired,
-    token: React.PropTypes.string,
-    color: React.PropTypes.string,
+    token: React.PropTypes.string.isRequired,
+    color: React.PropTypes.oneOf(['white', 'black']).isRequired,
     soundsEnabled: React.PropTypes.bool.isRequired
   },
   mixins: [React.addons.PureRenderMixin],

+ 56 - 2
src/js/components/Chessboard.js

@@ -3,15 +3,21 @@
 const React = require('react');
 const GameStore = require('../stores/GameStore');
 const GameActions = require('../actions/GameActions');
+const ChessPieces = require('../constants/ChessPieces');
 const onGameChange = require('../mixins/onGameChange');
+const maybeReverse = require('../mixins/maybeReverse');
+const Immutable = require('immutable');
+const {Seq, Repeat} = Immutable;
+const PureRenderMixin = React.addons.PureRenderMixin;
 
 const Chessboard = React.createClass({
   
   propTypes: {
     io: React.PropTypes.object.isRequired,
-    maybePlaySound: React.PropTypes.func.isRequired
+    maybePlaySound: React.PropTypes.func.isRequired,
+    color: React.PropTypes.oneOf(['white', 'black']).isRequired
   },
-  mixins: [React.addons.PureRenderMixin, onGameChange],
+  mixins: [PureRenderMixin, onGameChange, maybeReverse],
 
   getInitialState() {
     return {
@@ -19,8 +25,14 @@ const Chessboard = React.createClass({
     };
   },
   render() {
+    const fen = this.state.fen;
+    const placement = fen.split(' ')[0];
+    const rows = this._maybeReverse(placement.split('/'));
+
     return (
       <table className="chessboard">
+        {rows.map((placement, i) =>
+          <Row placement={placement} color={this.props.color} key={i} />)}
       </table>
     );
   },
@@ -31,4 +43,46 @@ const Chessboard = React.createClass({
   }
 });
 
+const Row = React.createClass({
+
+  propTypes: {
+    placement: React.PropTypes.string.isRequired,
+    color: React.PropTypes.oneOf(['white', 'black']).isRequired
+  },
+  mixins: [PureRenderMixin, maybeReverse],
+
+  render() {
+    const placement = this.props.placement;
+    let pieces;
+
+    if (placement.length < 8) {
+      pieces = this._maybeReverse(
+        Seq(placement).flatMap(piece => (
+          /^\d$/.test(piece) ? Repeat('-', parseInt(piece, 10)) : piece
+        ))
+      ).toArray();
+    } else {
+      pieces = this._maybeReverse(placement.split(''));
+    }
+    return (
+      <tr>
+        {pieces.map((piece, i) =>
+          <Column piece={piece} key={i} />)}
+      </tr>
+    );
+  }
+});
+
+const Column = React.createClass({
+
+  propTypes: {
+    piece: React.PropTypes.string.isRequired
+  },
+  mixins: [PureRenderMixin],
+
+  render() {
+    return <td>{ChessPieces[this.props.piece]}</td>;
+  }
+});
+
 module.exports = Chessboard;

+ 5 - 2
src/js/components/ChessboardInterface.js

@@ -12,7 +12,9 @@ const cx = require('classnames');
 const ChessboardInterface = React.createClass({
   
   propTypes: {
-    io: React.PropTypes.object.isRequired
+    io: React.PropTypes.object.isRequired,
+    soundsEnabled: React.PropTypes.bool.isRequired,
+    color: React.PropTypes.oneOf(['white', 'black']).isRequired
   },
   mixins: [React.addons.PureRenderMixin, onGameChange],
 
@@ -40,7 +42,8 @@ const ChessboardInterface = React.createClass({
           <CapturedPieces />
           <Chessboard
             io={this.props.io}
-            maybePlaySound={this._maybePlaySound} />
+            maybePlaySound={this._maybePlaySound}
+            color={this.props.color} />
         </div>
 
         <TableOfMoves />

+ 1 - 1
src/js/components/GameHeader.js

@@ -10,7 +10,7 @@ const GameHeader = React.createClass({
   propTypes: {
     io: React.PropTypes.object.isRequired,
     params: React.PropTypes.array.isRequired,
-    color: React.PropTypes.string,
+    color: React.PropTypes.oneOf(['white', 'black']).isRequired,
     openModal: React.PropTypes.func.isRequired,
     gameOver: React.PropTypes.bool.isRequired
   },

+ 2 - 1
src/js/components/GameInterface.js

@@ -131,7 +131,8 @@ const GameInterface = React.createClass({
 
         <ChessboardInterface
           io={io}
-          soundsEnabled={soundsEnabled} />
+          soundsEnabled={soundsEnabled}
+          color={color} />
 
         <Modal data={this.state.modal} />
       </div>

+ 4 - 4
src/js/constants/ChessPieces.js

@@ -2,10 +2,10 @@ module.exports = {
   // white pieces
   'K': '\u2654',
   'Q': '\u2655',
-  'R': '\u2655',
-  'B': '\u2655',
-  'N': '\u2655',
-  'P': '\u2656',
+  'R': '\u2656',
+  'B': '\u2657',
+  'N': '\u2658',
+  'P': '\u2659',
   // black pieces
   'k': '\u265a',
   'q': '\u265b',

+ 5 - 0
src/js/mixins/maybeReverse.js

@@ -0,0 +1,5 @@
+module.exports = {
+  _maybeReverse(iterable) {
+    return this.props.color === 'black' ? iterable.reverse() : iterable;
+  }
+};

+ 3 - 2
src/js/stores/GameStore.js

@@ -3,6 +3,7 @@
 const AppDispatcher = require('../dispatcher/AppDispatcher');
 const EventEmitter = require('eventemitter2').EventEmitter2; 
 const GameConstants = require('../constants/GameConstants');
+const Chess = require('chess.js').Chess;
 const Immutable = require('immutable');
 const {List, Map, OrderedMap, Set} = Immutable;
 const CHANGE_EVENT = 'change';
@@ -19,7 +20,7 @@ var _capturedPieces = OrderedMap([
 var _moves = List();
 var _promotion = 'q';
 var _turn = 'w';
-var _fen = null;
+var _chess = new Chess();
 
 const GameStore = Object.assign({}, EventEmitter.prototype, {
   getState() {
@@ -36,7 +37,7 @@ const GameStore = Object.assign({}, EventEmitter.prototype, {
     return _moves;
   },
   getFEN() {
-    return _fen;
+    return _chess.fen();
   }
 });