blob: 5b0a6a3877453bcad049084cb7c76e3c5074f7fa [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<title>Chess Game Tutorial (Part 1)</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<link rel="stylesheet" href="./asciidoctor.css">
<!DOCTYPE html>
<!-- ************* Favicon ************-->
<link rel="icon" href="../../images/favicon.ico" />
<link rel="icon" type="image/png" href="../../images/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="../../images/favicon-16x16.png" sizes="16x16" />
<!-- ************* Back-to-top JQuery ************* -->
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<!-- ************* Prism.js Syntax Highlighter ******-->
<link href="../../styles/prism.min.css" rel="stylesheet"/>
<script src="../../scripts/prism.js"></script>
<!-- ************* Styles ************* -->
<link rel="stylesheet" type="text/css" href="../../styles/n4js-adoc.css">
<!-- ****************** NavBar ****************** -->
<div id="menubar">
<div class="banner">
<a href="../../index.html"><img id="logo" src="../../images/n4js-logo.png" alt="N4JS Language and IDE"></a>
</div>
<ul>
<li><a href="../../downloads.html"></i>Download</a></li>
<li><a href="../../community.html"></i>Community</a></li>
<li><a href="../index.html">Documentation</a></li>
</ul>
</div>
<button id="tocbutton">TOC</button>
</head>
<body class="article">
<div id="header">
<h1>Chess Game Tutorial (Part 1)</h1>
<div id="toc" class="toc">
<div id="toctitle">Jump to topic</div>
<ul class="sectlevel1">
<li><a href="#_overview">Overview</a></li>
<li><a href="#_repository">Repository</a></li>
<li><a href="#_developer_setup_and_generate_folder_src_gen">Developer Setup and generate folder <code>src-gen</code></a>
<ul class="sectlevel2">
<li><a href="#_use_command_line_only">Use command line only</a></li>
<li><a href="#_use_n4js_eclipse_ide">Use N4JS Eclipse IDE</a></li>
</ul>
</li>
<li><a href="#_create_the_application">Create the application</a></li>
<li><a href="#_start_local_web_server">Start local web server</a></li>
<li><a href="#_n4js_type_definitions_of_react">N4JS type definitions of React</a></li>
<li><a href="#_file_extension_n4jsx">File extension n4jsx</a></li>
<li><a href="#_graphical_representation_of_chess_board_and_pieces">Graphical representation of chess board and pieces</a></li>
<li><a href="#_react_components_tree">React components tree</a></li>
<li><a href="#_square_react_component">Square React component</a></li>
<li><a href="#_board_react_component">Board React component</a></li>
<li><a href="#_game_react_component_root">Game React component (root)</a></li>
<li><a href="#_implementation_of_game_rules">Implementation of game rules</a></li>
<li><a href="#_build_with_webpack">Build with Webpack</a></li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="_overview">Overview</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://reactjs.org/" target="_blank" rel="noopener">React</a> is a popular JavaScript library created by Facebook widely used for developing web user interface. N4JS provides full support for React as well as the JavaScript extension <a href="https://reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noopener">JSX</a> for describing UI elements. Internally, we have been using N4JS in combination with React and JSX for years to develop very large e-commerce web applications.
In this tutorial, we will develop a simple and yet fun (!) chess game with N4JS and React. For the purpose of this tutorial, the chess game only allows two humans to play against each other.</p>
</div>
<div class="paragraph">
<p>Before starting with the implementation, let&#8217;s explicitly state several features we would like to have in our application.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>When the chess application is started, a chess board of 8x8 squares shall be showed containing 16 white pieces and 16 black pieces in their initial positions.</p>
</li>
<li>
<p>A player in turn shall be able to use the mouse to pick one of the pieces that she/he wants to move. A picked piece shall be clearly recognizable. Moreover, to aid players, especially beginners, whenever a piece is picked, all possible valid destination squares shall be visually highlighted as well.</p>
</li>
<li>
<p>In addition to the game board, there shall be a game information area that shows which player is in turn. Moreover, the game information area shall show a complete history of the game protocolling each move made by the players. As a bonus, jumping back to a previous state of the history shall be possible.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The final game will look approximately like this. You may want to challenge your co-worker to a game now!</p>
</div>
<div class="paragraph">
<p>
<iframe src="chess.html" width="100%" height="620" frameBorder="0"></iframe>
</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_repository">Repository</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The source code of the chess application can be found at <a href="https://github.com/Eclipse/n4js-tutorials/tree/master/chess-react" target="_blank" rel="noopener">n4js-tutorials/chess-react</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_developer_setup_and_generate_folder_src_gen">Developer Setup and generate folder <code>src-gen</code></h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are two alternatives for the developer setup and the generation of the <code>src-gen</code> folder:
to use either the N4JS Eclipse IDE or use the command line only.</p>
</div>
<div class="sect2">
<h3 id="_use_command_line_only">Use command line only</h3>
<div class="paragraph">
<p>Open the project folder in a shell and execute the following commands:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm install # download node_modules
npm run build # generate js files in folder src-gen</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_use_n4js_eclipse_ide">Use N4JS Eclipse IDE</h3>
<div class="dlist">
<dl>
<dt class="hdlist1">Step 1</dt>
<dd>
<p>Download the latest N4JS IDE from the <a href="https://www.eclipse.org/n4js/downloads.html">N4JS Download Page</a> for your operating system.</p>
</dd>
<dt class="hdlist1">Step 2</dt>
<dd>
<p>The project is already an Eclipse project with the <code>.project</code> file in the root <code>chess-react</code> folder.
Hence, you can simply import it into the N4JS IDE workspace via <code>File &#8658; Import &#8658; Existing Projects into Workspace</code>.
The IDE may complain that npm dependencies declared in <code>package.json</code> are missing.
Use the quickfix <code>run npm/yarn in this project</code> to fix this issue.</p>
</dd>
<dt class="hdlist1">Step 3</dt>
<dd>
<p>In the N4JS IDE, open the library manager (N4JS IDE &#8658; Preferences&#8230;&#8203; &#8658; N4JS &#8658; N4JS External Libraries) and click on the button <code>Re-Build node_modules</code>.</p>
</dd>
<dt class="hdlist1">Step 4</dt>
<dd>
<p>Clean &amp; Build the project. After this step, the project has no compilation errors anymore.</p>
<div class="paragraph">
<p>Now, the folder <code>src-gen</code> should have been created and populated with <code>.js</code> files of the project.
The <code>.js</code> files will be used in the next step by webpack.</p>
</div>
</dd>
</dl>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_create_the_application">Create the application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>package.json</code> defines a script <code>webpack</code> to create the application <code>chess-app.js</code>.
Run it with:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm run webpack</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_start_local_web_server">Start local web server</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>package.json</code> defines a script <code>start</code> for starting the Webpack Dev Server serving the application to a browser on <code><a href="http://localhost:8080" class="bare">http://localhost:8080</a></code>.
To start the web server, run:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm start</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_n4js_type_definitions_of_react">N4JS type definitions of React</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In order to enable N4JS&#8217;s type checking for React, we need to declare <code>@n4jsd/react</code> as a dev dependency in <code>package.json</code> of the project. <code>@n4jsd/react</code> consists of <code>n4jsd</code> files that contain file definitions for React.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"name": "n4js-tutorial-chess",
"devDependencies": {
"@n4jsd/react": "&lt;=16.6.*",
},
"dependencies": {
"react": "^16.6.0",
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The concept of <code>n4jsd</code> files in N4JS is very similar to TypeScript&#8217;s <code>d.ts</code> definition files in that they both do not contain any implementations and are only used for type checking. In addition to React, the <a href="https://github.com/NumberFour/n4jsd" target="_blank" rel="noopener">n4jd repository</a> has <code>n4jsd</code> projects for many popular JavaScript library such as <code>lodash</code> or <code>express</code> etc.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_file_extension_n4jsx">File extension n4jsx</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The standard file extension of N4JS is <code>.n4js</code>. N4JS files containing React and JSX must have the extension <code>.n4jsx</code>.
Also, every <code>.n4jsx</code> has to have import <code>React</code> explicitly.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_graphical_representation_of_chess_board_and_pieces">Graphical representation of chess board and pieces</h2>
<div class="sectionbody">
<div class="paragraph">
<p>At this point, we probably ask the question: <em>How should we draw the chess board?</em>
We could use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas API</a>. To keep the application simple, however, in this tutorial, we draw the chess board with pure CSS using <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox" target="_blank" rel="noopener">flexbox model</a>. In particular, the chess board can be defined as a flex container with <code>flex-wrap: wrap</code> whereas the squares are flex items.</p>
</div>
<div class="paragraph">
<p><em>How about chess pieces?</em>
Instead of images, we use <a href="https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode" target="_blank" rel="noopener">Chess symbols in Unicode</a> to display chess pieces.
There are many ways to represent pieces in N4JS, the simplest way being to declare a <a href="https://www.eclipse.org/n4js/spec/N4JSSpec.html#_string-based-enums" target="_blank" rel="noopener">String-based enum</a> called <code>Piece</code> to represent pieces. The enum literals are the Unicode chess symbols.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">@StringBased
export public enum Piece {
WHITE_PAWN : '♙',
WHITE_ROOK : '♖',
WHITE_KNIGHT : '♘',
WHITE_BISHOP : '♗',
WHITE_QUEEN : '♕',
WHITE_KING: '♔',
BLACK_PAWN : '♟',
BLACK_ROOK : '♜',
BLACK_KNIGHT : '♞',
BLACK_BISHOP : '♝',
BLACK_QUEEN : '♛',
BLACK_KING: '♚'
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The advantage of String-based enums is that in N4JS code, we can use the enum literals, e.g. Piece.WHITE_PAWN etc., to refer to the pieces in the exact the same way as with normal enums. That means, we receive full validation support from N4JS compiler and IDE as with normal enums. In the transpiled JavaScript code, these enum literals are replaced by the corresponding chess symbols (strings).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_react_components_tree">React components tree</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As typical with React applications, we need to decide how the UI of our chess game should be structured as a tree of React components. In this example, we have opted for the following structure.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/chess-react-components.svg" alt="Chess React components tree" width="90%">
</div>
</div>
<div class="paragraph">
<p>The root React component is <code>Game</code> that consists of two areas. The left area is the React component <code>Board</code> showing the chess board while the right area shows the game information.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_square_react_component">Square React component</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the tree of React components in this application, <code>Square</code> is one of the leaf React components. It defines a single square of the chess board that can be clicked by the current user. Its value is either a <code>Piece</code> representing a piece or <code>null</code> if the square is empty. In this example, we define Square as a lightweight functional component since it does not have any state.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Square props
*/
export public interface ~SquareProps extends React.ComponentProps {
public isWhite: boolean;
public piece: Piece;
public onClick: {function(): void}
public isPicked: boolean;
public isValidDestination: boolean;
}
/**
* Board square styles
*/
const boardSquareStyles = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
fontSize: '5vw'
}
/**
* Square React component
*/
export public function Square(props: SquareProps): React.Element&lt;?&gt; {
let backgroundColor: string = props.isWhite? '#EADAB9' : '#C2A482';
// Special square highlighting a picked square or valid destination?
if (props.isPicked) {
backgroundColor = 'lime';
} else if (props.isValidDestination) {
backgroundColor = 'yellow';
}
return (
&lt;div style={Object.assign({}, boardSquareStyles, {backgroundColor: backgroundColor})}
onClick={props.onClick}&gt;
{props.piece}
&lt;/div&gt;
);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The functional definition of <code>Square</code>, in fact of any React component, must have a single <code>props</code> parameter of a subtype of <code>React.ComponentProps</code> and return an instance of type <code>React.Element&lt;?&gt;</code>. In this example, <code>SquareProps</code> dictates that when a <code>Square</code> is instantiated, it expects the following <em>mandatory</em> <code>props</code>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>isWhite</code>: <code>true</code> if the square is a white square and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>piece</code>: the piece on the square, of type <code>Piece</code>. This is necessary because the states of the squares are managed by a parent React component.</p>
</li>
<li>
<p><code>isPicked</code>: <code>true</code> if the square contains a piece that has been picked by the current player with the intention to move it to a new position and <code>false</code> otherwise. This is necessary to change the background of the square to highlight that the square has been picked.</p>
</li>
<li>
<p><code>isValidDestination</code>: <code>true</code> if the square should be highlighted as a valid destination for a picked square and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>onClick</code>: the event handler to be called when the square is clicked. <code>Square</code> component uses this event handler to inform the parent <code>Board</code> component of the clicking event.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In addition to having explicit types, the props can be declared as mandatory (as in this example) or <em>optional</em> with the help of the question mark. For instance, if we would declare <code>public piece?: string</code>, it would mean that <code>piece</code> would be an optional property when creating <code>Square</code>.</p>
</div>
<div class="paragraph">
<p>Here we start to see the advantages of an N4JS implementation over a pure non-typed JavaScript implementation. First, since the props required by <code>Square</code> are made explicit, the code is more readable. Second, when a <code>Square</code> component is created, the compiler will enforce the types of the props. Third, the N4JS compiler will complain if a mandatory prop is missing. And all these validations happen <em>at compile time</em> during development. In pure JavaScript, we would recognize type mismatch or missing mandatory props problem much later <em>at runtime</em>, possibly during production.</p>
</div>
<div class="paragraph">
<p>The <code>render</code> method of the <code>Square</code> component returns an JSX expression, particularly a <code>&lt;div&gt;</code> whose content is the piece to be displayed. The CSS style is dynamically calculated to set the background color based on the values of the passed props.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_board_react_component">Board React component</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>Board</code> React component represents the chess board. Even though it does not have state, we define it as a class because it contains helper methods. The most important <em>prop</em> needed by this React component is <code>squares</code> that is an 8x8 array of <code>Piece</code> containing an arrangement of pieces on the board. To avoid tiring mental calculation, we use the browser&#8217;s coordinate system, i.e. the top left square has the coordinate <code>(0,0)</code> while the bottom right&#8217;s coordinate is <code>(7,7)</code>. Note that the coordinates of the 8x8 <code>Pieace</code> array is different from that of <a href="https://en.wikipedia.org/wiki/Algebraic_notation_(chess)" target="_blank" rel="noopener">algebraic chess notation</a>.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/chess-board-coordinate-system.svg" alt="Chess board coordinate system" width="70%">
</div>
</div>
<div class="paragraph">
<p>In addition to 8x8 black/white squares, we should also display the conventional board&#8217;s coordinates because these coordinates are used for displaying the game history.</p>
</div>
<div class="paragraph">
<p><em>How can we create such a board with pure CSS?</em> The probably easiest way is to use <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" target="_blank" rel="noopener">flexbox model</a>.
In particular, the board is defined as a <em>flex container</em> with <code>flex-wrap: wrap</code>.
The squares displaying chess pieces and coordinates in algebraic chess notation are <em>flex items</em>. Together with squares displaying coordinates (called <em>coordinate squares</em> in this implementation), there are 10 x 10 squares inside the <code>Board</code> component in total. As a result, each square occupies 10% width and 10% height of the board&#8217;s width and height. The following diagram graphically depicts this.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/chess-board-flexbox.svg" alt="Chess board with flexbox" width="60%">
</div>
</div>
<div class="paragraph">
<p>Since we have to deal a lot with coordinates, we define the <code>Coordinate</code> data structure to represent (row,column) coordinates.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">export public class Coordinate {
public row: number;
public col: number;
/**
* Spec constructor
*
public constructor(@Spec spec:~i~this) {}
/**
* Compare two coordinates
*/
public equals(other: Coordinate): boolean {
return (this.row == other.row) &amp;&amp; (this.col == other.col);
}
/**
* Convert the this to board's coordinate
*/
public getBoardCoordinateRepresentation() {
const rowLabel = 8 - this.row;
const colLabel = String.fromCharCode('a'.charCodeAt(0) + this.col);
return `(${rowLabel + ',' + colLabel})`;
}
@Override
public toString(): string {
return `(${this.row},${this.col})`;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the class <code>Coordinate</code> above, we define a <a href="https://www.eclipse.org/n4js/spec/N4JSSpec.html#spec-constructor" target="_blank" rel="noopener">Spec constructor</a>. This Spec constructor allows us to instantiate a Coordinate by supplying all public members in an object literal. For example,</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">let c: Coordinate = new Coordinate({ row: 1, col: 2});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Equally interesting is the method <code>toString</code> which should be very familiar to Java developers. This method defines the string representation of a Coordinate.</p>
</div>
<div class="paragraph">
<p>The data structure <code>BoardProps</code> defining the props of <code>Board</code> component is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Board props
*/
export public interface ~BoardProps extends React.ComponentProps {
public squares: Array&lt;Array&lt;Piece&gt;&gt;;
public pickedSquare: Coordinate;
public validDestinations: Array&lt;Coordinate&gt;;
public onClick: {function(Coordinate): void}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition to <code>squares</code>, additional props are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>pickedSquare</code>: the (row, column) coordinate indicating the currently picked square if exists and <code>null</code> otherwise.</p>
</li>
<li>
<p><code>validDestinations</code>: if <code>pickedSquare</code> exists, this array contains the coordinates of the valid destinations of the piece on the picked square.</p>
</li>
<li>
<p><code>onClick</code>: the event handler to be called when the square at a certain position is clicked. <code>Square</code> component informs <code>Board</code> component which in turn informs a parent component about a clicking event.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following screenshot graphically depicts a chess board in which the square <code>(3,7)</code> containing a white knight is picked by the player. The picked square is visually recognizable via the green color. Additionally, all valid destinations of the white knight are highlighted in yellow color.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/chess-picked-square.png" alt="Picked square" width="50%">
</div>
</div>
<div class="paragraph">
<p>The class <code>Board</code>, as any class representing a React component, must extend <code>React.Component</code> and override the <code>render()</code> method.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Board React component
*/
export public class Board extends React.Component&lt;BoardProps, Object&gt; {
/**
* Render the i-th square on the board 0 &lt;= i &lt;= 63
*/
private renderSquare(pos: Coordinate, isWhite: boolean, isPicked: boolean, isValidDestination: boolean, piece: Piece): React.Element&lt;?&gt; {
return (
&lt;div style={squareStyles}&gt;
&lt;Square
isWhite={isWhite}
isPicked={isPicked}
isValidDestination={isValidDestination}
piece={piece}
onClick={() =&gt; this.props.onClick(pos)}
/&gt;
&lt;/div&gt;
);
}
/**
* Render coordinate square
*/
private renderCoordinateSquare(label: string): React.Element&lt;?&gt; {
return (
&lt;div style={squareStyles}&gt;
&lt;CoordinateSquare
label={label}
/&gt;
&lt;/div&gt;
);
}
private renderSquares(): Array&lt;React.Element&lt;?&gt;&gt; {
const squares = new Array&lt;React.Element&lt;?&gt;&gt;();
let isWhiteInitial = true;
// Draw row coordinates: a b c ... h
squares.push(this.renderCoordinateSquare(''));
for (let i = 0; i &lt; 8; i++) {
squares.push(this.renderCoordinateSquare(String.fromCharCode('a'.charCodeAt(0) + i)));
}
squares.push(this.renderCoordinateSquare(''));
for (let row = 0; row &lt; 8; row++) {
// Draw column coordinate: 8 7 6 ... 1
squares.push(this.renderCoordinateSquare((8-row).toString()));
let isWhite = isWhiteInitial;
for (let col = 0; col &lt; 8; col++) {
const pos = new Coordinate({row: row, col: col});
const isPotentialDestination: boolean =
this.props.validDestinations.findIndex(potentialDest =&gt; potentialDest.equals(pos)) &gt;= 0;
squares.push(this.renderSquare(pos, isWhite,
this.props.pickedSquare &amp;&amp; this.props.pickedSquare.equals(pos)? true : false, isPotentialDestination, this.props.squares[pos.row][pos.col]
));
isWhite = !isWhite;
}
isWhiteInitial = !isWhiteInitial;
squares.push(this.renderCoordinateSquare((8-row).toString()));
}
// Draw row coordinates: a b c ... h
squares.push(this.renderCoordinateSquare(''));
for (let i = 0; i &lt; 8; i++) {
squares.push(this.renderCoordinateSquare(String.fromCharCode('a'.charCodeAt(0) + i)));
}
squares.push(this.renderCoordinateSquare(''));
return squares;
}
@Override
public render(): React.Element&lt;?&gt; {
return (
&lt;div style={boardStyles}&gt;
{ this.renderSquares() }
&lt;/div&gt;
);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that <code>React.Component</code> expects two type arguments: the first type argument is the type of props and the second type argument is the type of state. Here, in the <code>render</code> method we create 8x8 <code>Squares</code> components that make up the chess board. We also create two rows and two columns of <code>CoordinateSquare</code> displaying the chess board coordinates.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_game_react_component_root">Game React component (root)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This is the root React component of this application and hence does not have any props. Instead, it has a state represented by <code>GameState</code>. The game state consists of the history of the board as an array of <code>Snapshot</code>, among others.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* A history snapshot
*/
interface ~Snapshot {
public squares: Array&lt;Array&lt;Piece&gt;&gt;;
public lastMoves: Array&lt;Move&gt;;
public whiteKingMoved: boolean;
public leftWhiteRookMoved: boolean;
public rightWhiteRookMoved: boolean;
public blackKingMoved: boolean;
public leftBlackRookMoved: boolean;
public rightBlackRookMoved: boolean;
}
/**
* Game state
*/
interface ~GameState {
public history: Array&lt;Snapshot&gt;;
public stepNumber: int;
public whiteIsNext: boolean;
public pickedSquare: Coordinate;
public validDestinations: Array&lt;Coordinate&gt;;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>A snapshot of the history contains:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>squares</code>: a 2-dimensional array containing an arrangement of pieces on the chess board.</p>
</li>
<li>
<p><code>lastMoves</code>: contains the last moves leading to the arrangement of pieces. The reason why this is an array, instead of a single element, is that a <a href="https://en.wikipedia.org/wiki/Castling" target="_blank" rel="noopener">castling</a> move changes the positions of a king and a rook at the same time.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Further flags such as <code>whiteKingMoved</code> etc. remember if kings or rooks have been moved already. These kinds of information are relevant for handling castling.</p>
</div>
<div class="paragraph">
<p>You may ask what the tilde symbol means, for instance in <code>~Snapshot</code>? The tilde symbol here indicates that <em>structural subtyping</em> should be used during type checking. In essence, it means that when checking whether some object or instance is a subtype of <code>~Snapshot</code>, the type system only cares if that object or instance has all the public fields declared in <code>~Snapshot</code>. And if yes, the object is considered a subtype of <code>Snapshot</code>. This is exactly the behavior what we want here. You should read <a href="https://www.eclipse.org/n4js/features/nominal-and-structural-typing.html" target="_blank" rel="noopener">structural typing vs. nominal subtyping</a> for further explanation.</p>
</div>
<div class="paragraph">
<p><code>GameState</code> stores the entire state of the application and consists of:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>history</code>: array of snapshots capturing the entire history leading up to the current arrangement of the chess board.</p>
</li>
<li>
<p><code>stepNumber</code>: the current step number. Its initial value is <code>0</code>. Each time when a player places a move, it is increased by <code>1</code>.</p>
</li>
<li>
<p><code>whiteIsNext</code>: <code>true</code> if the white player is in turn and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>pickedSquare</code>: the (row,column) coordinate indicating the currently picked square if exists and <code>null</code> otherwise.</p>
</li>
<li>
<p><code>validDestinations</code>: if <code>pickedSquare</code> exists, this array contains the coordinates of the squares being the valid destinations of the piece on the picked square.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here, again thanks to type checking, the N4JS compiler will complain if we, for instance, access a non-existing field of <code>GameState</code> or use the wrong type of a certain field of <code>GameState</code> <em>at compile time</em>. In pure JavaScript, we would recognize those mistakes only at runtime.</p>
</div>
<div class="paragraph">
<p>The <code>Game</code> component is quite complex because it implements the game rules. In the next section, we will look at some of the implementations of the game rules.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implementation_of_game_rules">Implementation of game rules</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>Game</code> component contains logics for implementing the game rules. In this section, we will discuss logics for</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Calculating the set of squares being attacked by a certain piece.</p>
</li>
<li>
<p>Calculating the set of squares being valid destinations (squares) of a certain piece.</p>
</li>
<li>
<p>Checking checkmate.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>We can see that the set of squares being attacked by a certain piece and the set of squares being valid destinations of a certain piece are closely related. For rooks, knights, bishops, queens, these two sets are in fact almost identical with the exception that moving one of these pieces cannot cause the king to be in check. However, pawns are quite special because they
can attack diagonal squares but can only move forwards vertically. Kings have special castling moves that jump two squares.</p>
</div>
<div class="paragraph">
<p>As an example, we will have a look at the algorithm for calculating squares attacked by a bishop. The general movement rule for a bishop looks as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A bishop can move diagonally but the destination must lie within the border of the chess board.</p>
</li>
<li>
<p>A bishop cannot jump over other pieces on its movement.</p>
</li>
<li>
<p>If there is an opponent piece on its movement, a bishop can capture it.</p>
</li>
<li>
<p>A bishop (as any other piece) cannot move if its movement would cause the king (of the same color) to be in check</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following screenshot shows an example highlighting valid destinations for the white bishop.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/bishop-attacking-squares.png" alt="Squares attacked by bishop" width="40%">
</div>
</div>
<div class="paragraph">
<p>There are certainly tons of ways to calculate the set of squares/destinations attacked by a bishop in particular, and by a piece in general. In this tutorial, we have opted for a simple imperative implementation: starting from the current position, we iterate 4 different directions: north west, north east, south east, south west. In each direction, we keep moving forwards as far as possible. The implementation is as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">private calculateDestinationsAttackedByBishop(squares: Array&lt;Array&lt;Piece&gt;&gt;,
figure: Piece, pos: Coordinate): Array&lt;Coordinate&gt; {
const row = pos.row;
const col = pos.col;
const result: Array&lt;Coordinate&gt; = new Array&lt;Coordinate&gt;();
// NORTH WEST, NORTH EAST, SOUTH EAST, SOUTH WEST
const deltas = [[-1,-1], [-1,1], [1,1], [1,-1]];
// Iterate 4 directions
for (let delta of deltas) {
let newPos = new Coordinate({row: row + delta[0], col: col + delta[1]});
while (this.isInsideBoard(newPos)) {
if (!squares[newPos.row][newPos.col]) {
// Square is not occupied
result.push(newPos);
} else {
// Square is occupied
if (this.isPositionOccupiedByFigureSameColor(squares, figure, newPos)) {
break;
}
if (this.isPositionOccupiedByFigureOtherColor(squares, figure, newPos)) {
result.push(newPos);
break;
}
}
newPos = new Coordinate({row: newPos.row + delta[0], col: newPos.col + delta[1]});
}
}
return result;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The set of all valid destinations of a bishop is the set of all squares attacked by the bishop with the condition that moving it does not cause the king to be in check. The method <code>isKingInCheckIfMove</code> in the <code>Game</code> component <em>simulates</em> a move of a piece and checks if the move would cause the king of the same color to be in check.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Check whether the king is in check if the move is made
*/
private isKingInCheckIfMove(attemptedMove: Move) {
// Check if the move causes the king to be in check
const {squares: changedSquares} = this.move(attemptedMove);
const isWhite = this.isWhitepiece(attemptedMove.piece);
const kingPos = this.getKingPosition(changedSquares, isWhite);
if (!kingPos) {
return false;
}
return this.isKingInCheck(changedSquares, isWhite? Piece.WHITE_KING : Piece.BLACK_KING, kingPos)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Checking whether a king is checkmated is interesting. A king is checkmated if all pieces cannot move anymore, i.e. have no valid destinations. This logics is implemented by the method <code>calculateWinner</code> in <code>Game.n4jsx</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Calculate the winner
*/
private calculateWinner(squares: Array&lt;Array&lt;Piece&gt;&gt;): string {
const isWhite = this.state.whiteIsNext;
const allPieces = this.getAllPiecesSameColor(squares, isWhite);
// Checkmate if all pieces have no valid destinations
const checkMate =
this.forAll(allPieces,
(p) =&gt; this.calculateValidDestinations(squares, p.piece, p.pos).length == 0
);
if (checkMate) {
return isWhite? 'Black': 'White';
} else {
return null;
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_build_with_webpack">Build with Webpack</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We use Webpack to bundle all JavaScript files of the application, including dependencies such as React, into a single JavaScript file. Webpack is configured in <code>webpack.config.js</code>. The following diagram graphically depicts the build process with the help of Webpack.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="images/react-build-process.svg" alt="Build process">
</div>
</div>
<div class="paragraph">
<p>The entry file used by Webpack to calculate the dependency graph is <code>src-gen/main.js</code> which depends on <code>react-dom</code> and <code>src-gen/Game.js</code> which depends on &#8230;&#8203; etc. The bundled JavaScript is stored in <code>public/dist/chess-app.js</code> which is then included in <code>index.html</code>.</p>
</div>
<div class="paragraph">
<p>The content of <code>webpack.config.js</code> is as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: {
// Webpack starts calculating dependency graph from this file
app: './src-gen/main.js'
},
output: {
// The output concatenated file
filename: 'chess-app.js',
publicPath: 'dist/',
path: path.resolve(__dirname, 'public/dist')
},
devtool: 'inline-source-map',
/** Configure Webpack Dev server */
devServer: {
// Serve files from the `public` folder at localhost:8080
contentBase: path.join(__dirname, 'public'),
port: 8080,
hot: true,
inline: true
},
plugins: [
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin()
],
resolve: {
alias: {
"n4js-tutorial-chess": __dirname
}
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that we need to specify the entry point <code>./src-gen/main.js</code> instead of <code>./src/main.n4js</code> of course because Webpack and web browser only understand the generated JavaScript files. The concatenated JavaScript file is <code>public/dist/chess-app.js</code> which contains the entire chess application. We also configure a Webpack Dev server with hot loading enabled so that we can start the application locally.</p>
</div>
<div class="paragraph">
<p>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/themes/prism.min.css"></link>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/components/prism-typescript.min.js"></script>
</p>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
</div>
</div>
<!DOCTYPE html>
<div class="Grid social" style="color:#d5dfea">
<div class="Cell Cell--2-12 m-Cell--withMargin">
<h2>Quick Links</h2>
<ul>
<li><a href="../downloads.html">Download</a></li>
<li><a href="index.html">Documentation</a></li>
<li><a href="https://github.com/eclipse/n4js/">Source</a></li>
<li><a href="https://github.com/eclipse/n4js/issues">Issues</a></li>
</ul>
</div>
<div class="Cell Cell--2-12 m-Cell--withMargin">
<br/><br/>
<ul>
<li><a href="https://www.eclipse.org/forums/index.php/f/365/">Forum</a></li>
<li><a href="http://n4js.blogspot.de/">Blog</a></li>
<li><a href="https://dev.eclipse.org/mailman/listinfo/n4js-dev">Mailing List</a></li>
<li><a href="https://projects.eclipse.org/projects/technology.n4js">Eclipse Project Page</a></li>
<li><a href="https://twitter.com/n4jsdev">Tweets by n4jsdev</a></li>
</ul>
</div>
<div class="Cell Cell--2-12 m-Cell--withMargin">
<br/><br/>
<ul>
<li><a href="http://www.eclipse.org/">Eclipse Home</a></li>
<li><a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li>
<li><a href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li>
<li><a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li>
<li><a href="http://www.eclipse.org/legal/">Legal</a></li>
</ul>
</div>
<div style="clear: both; height: 0; overflow: hidden;"></div>
</div>
<script>
// Toggle the table of contents
$( "button#tocbutton" ).click(function() {
if ($("#tocbutton").css('right') == '25px') {
$( "#tocbutton" ).animate({right: '215px'},"slow");
$( "#toc.toc2" ).animate({right: '0'},"slow");
}
else {
$( "#tocbutton" ).animate({right: '25px'},"slow");
$( "#toc.toc2" ).animate({right: '-13rem'},"slow");
}
});
</script>
<script type="text/javascript">
// Create a back to top button
$('body').prepend('<a href="#" class="back-to-top">Back to Top</a>');
var amountScrolled = 300;
$(window).scroll(function() {
if ( $(window).scrollTop() > amountScrolled ) {
$('a.back-to-top').fadeIn('slow');
} else {
$('a.back-to-top').fadeOut('slow');
}
});
$('a.back-to-top, a.simple-back-to-top').click(function() {
$('html, body').animate({
scrollTop: 0
}, 700);
return false;
});
</script>
</body>
</html>