P4wn, a smallish javascript chess engine ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ P4wn is both - an online web page and an offline HTML mobile and tablet application - that can play chess. It is quite small, plays well enough to be interesting, and is easy to embed in your pages. The default interface is easy to replace, and the engine is simple and tunable. P4wn is completely free, available under CC0_ or public domain terms. You can use it for anything you want. .. _CC0: http://creativecommons.org/publicdomain/zero/1.0/ How to play =========== If you load ``src/index.html`` (or http://p4wn.sf.net/src) in a modern javascript enabled browser, you should see a small chess board. You are playing white. To change that, click **swap**. You can swap sides at any stage of the game. To move a piece, click on it and click again where you want it to be. If the game is too easy or hard, click on the **computer level** button until it seems about right. Depending on you browser and computer, the slower settings might cause the browser to pop up warning windows. When you make a stupid move, you can undo it by clicking on the **undo** button. To jump back a long way, you can click on a move in the game log. The **pawn becomes ...** button switches between the various possible promotions for a pawn that reaches the end. If you want to change it, do so before you move the pawn. If a draw is technically possible (either through 3 repetitions of the same position, or 50 moves without a capture or pawn move) , a **Draw?** button will appear. You can claim a draw by clicking it. P4wn will never claim a draw on its own, just offer you the button. Where to find it and get help ============================= There is a homepage at http://p4wn.sf.net and git repositories at http://p4wn.git.sourceforge.net/git/gitweb.cgi?p=p4wn/p4wn and https://github.com/douglasbagnall/p4wn. The two git repositories should be pretty similar. Most people seem to use the github one. Zip and tar files of version 2 can be found at http://sourceforge.net/projects/p4wn/files/. The git tree contains several files not included in the version 2 zip and tar files. These are mainly interesting for historical reasons, or for testing, and are unnecessary and potentially confusing if you just want to play chess. So they have been left out and instead you'll get confused when this document refers to them. You can get these files via git, or just look at them on the Github and Sourceforge links above. There is a mailing list at https://lists.sourceforge.net/lists/listinfo/p4wn-chess, and the issue tracker at https://github.com/douglasbagnall/p4wn/issues is used. History ======= Version 1 --------- P4wn was originally written between 2000 and 2002 in a very compressed form, and was entered in the 2002 5k web contest. This version can still be found in the ``5k`` and ``6k`` directories. It is quite obtuse, due to its minified nature and the inexperience of the programmer. Sourceforge CVS era ------------------- In 2004 it gained a sourceforge page (http://p4wn.sf.net) with a CVS tree and a public domain dedication. This spurred a small flurry of forks, as various people tried fixing the obvious bugs and bad graphics or further reducing the code size. These forks never coalesced into anything that could be called a stream of development, no doubt due to the pathological state of the code and a perceived lack of need for small chess playing web pages. The name “p4wn” was originally only intended as a sourceforge subdomain, not to be applied to the chess program itself (which was called “5k chess” or somesuch). People have universally assumed otherwise, so the name sticks. Version 2 --------- In 2012 P4wn was rewritten for readability, correctness, and speed. The code in the ``src`` directory is version 2; that in ``5k`` is version 1. Version 2 followed liberation from CVS into git. Version 2.01 contains an interface fix for Internet Explorer. Version 2.02 introduces changes and wrappers so p4wn runs with an offline.appcache. Now p4wn can be installed as a packaged application or hosted application on Firefox OS devices to run even offline and in full screen. Furthermore p4wn can now be installed and run on iOS devices being started via icon from Home Screen and run in full screen, too. An optimize to screen resolution feature is available now. It provides resolution awareness, e.g. on mobile devices if switching between portrait and landscape, etc. New SVG (Scalable Vector Graphics) chess set has been created from scratch under CC0_. See * http://omerkel.github.io/p4wn/src/index-mobile.html , * http://omerkel.github.io/p4wn/src/index-mobile-1.html , * http://omerkel.github.io/p4wn/src/index-mobile-2.html , * https://marketplace.firefox.com/app/p4wn/ , and * https://marketplace.firefox.com/app/p4wn2/ Differences between version 1 and 2 ----------------------------------- Although they look entirely different, there is a structural and algorithmic continuity between the versions. P4wn 1 was written to run on turn of the century browsers, and to be as small as possible. It works in browsers newer than Netscape 3 and Internet Explorer 4. Version 2 targets HTML5-ish browsers and aims to be as small as is reasonable, while remaining easy to modify and embed. It probably works in all versions of Firefox, Chrome, and Safari, and (more slowly) in Internet Explorer 5.5 and above. P4wn 2 in 2012 works a few thousand times faster than p4wn 1 did is 2002. Much, but not all, of that is down to browser and hardware improvements. Embedding and theming ===================== *TL;DR:* look at ``src/index.html``. If you are trying something more complex than that, look also at ``src/fen-test.html``. Failing that, read on. The default interface (``display.js``) is deliberately primitive, to encourage the development of replacements. Putting it in you own page, method 1 ------------------------------------ Copy the files ``engine.js``, ``display.js``, ``p4wn.css``, and the ``images`` directory into your html directory. Then add these lines to your html:: in the ``
``, :: where you want the board to be, and this:: at the bottom (as seen in ``src/index.html``). Putting it in you own page, method 2 ------------------------------------ You might want the p4wn files somewhere else in your web tree, in which case you would do something like this (replacing ``p4wn/src`` with the correct path):: Your content... Your other content... Putting it in you own page, method 3 (no local copy) ---------------------------------------------------- Replacing every instance of ``p4wn/src`` in the above example with ``http://p4wn.sf.net/src`` ought to work. (Which is not to say http://p4wn.sf.net/src will always contain working and up-to-date code). Theming using CSS ----------------- Start from ``p4wn.css``. A few rules (e.g. the log panel height) are overridden by javascript. If you really need to wrest control back, use the ``!important`` declaration. Or you could write your own version of ``p4wnify()`` from ``display.js`` that doesn’t do that. Theming: images --------------- The images are found in a directory specified by ``P4WN_IMAGE_DIR``. When you have better images, put them where you like and change that variable before calling ``p4wnify()``:: Alternatively you can change the ``P4WN_IMAGE_NAMES`` variable, which is a list of variable names:: var P4WN_IMAGE_NAMES = [ 'empty.gif', '', // 1 is unused 'white_pawn.gif', 'black_pawn.gif', 'white_rook.gif', 'black_rook.gif', 'white_knight.gif', //.... ]; but that is more work. Theming: scale -------------- The size of the board is controlled by the size of each square, which is controlled by two variables:: The images will be scaled to this size. Theming: miscellaneous ---------------------- Should the board flip around when you are playing black, so your pieces are at the bottom? :: P4WN_ROTATE_BOARD = false; //default is true Do you dislike the names of the various levels, or think the default level is wrong? Change these:: P4WN_LEVELS = ['stupid', 'middling', 'default', 'slow', 'slowest']; P4WN_DEFAULT_LEVEL = 2; The names of pieces for pawn promotions can be localised:: P4WN_PROMOTION_STRINGS = ['queen', 'rook', 'knight', 'bishop']; as can the moves in the game log:: P4_ENCODE_LUT = " ♙♟♖♜♘♞♗♝♔♚♕♛"; Should p4wn keep trying deeper and deeper searches until it runs out of time (around a second)? :: P4WN_ADAPTIVE_LEVELS = true; More complicated and deeper adaptations --------------------------------------- It is possible to replace the ``display.js`` interface altogether, or to modify the way the engine plays. But these topics are discussed below. It is time for a break. p4wnify() tries to do what you mean ----------------------------------- For convenience, the ``p4wnify`` function will work with an element ID (as seen in the other examples), a DOM element itself, or a jquery object:: var el = document.getElementById("board-goes-here"); var $el = $("#board-goes-here"); p4wnify(el).next_move(); p4wnify($el).next_move(); The engine.js API and internals =============================== **engine.js** keeps track of the game, finds moves to play, and tries to communicate as much of this as is necessary to the human interface (**display.js**, by default). There are a few functions and a state object you need to worry about if you are writing a new interface, and a number of configurable constants you can fiddle with whether you are replacing ``display.js`` or not. Some terminology ---------------- *FEN*, or `Forsyth-Edwards Notation`_ is a standard for describing chess positions. It is fairly simple and widely used. .. _`Forsyth-Edwards Notation`: http://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation `Algebraic Notation`_ or *AN* is a widely used but not quite precisely defined standard for describing chess *moves*. If you have ever read a chess article you will have seen little clusters of letters and numbers like “*a8=Q Nbxa8*”. That is algebraic notation. P4wn follows the PGN_ dialect which uses upper case Os instead of zeros in castling notation (*O-O-O* vs *0-0-0*), but it tries to understand a wider range, including the long form which names each square rather than the moved piece (e.g. *b1-c3* rather than *Nc3*). .. _`Algebraic Notation`: http://en.wikipedia.org/wiki/Algebraic_chess_notation .. _PGN: http://en.wikipedia.org/wiki/Portable_Game_Notation Finally, a *pseudo-legal move* is a move that is allowed by the movement rules of chess without regard for check. The pseudo legal moves are an easier to find super-set of the actually legal moves. Functions used by display.js ---------------------------- p4_new_game() and p4_fen2state() ++++++++++++++++++++++++++++++++ ``p4_new_game()`` creates a state object representing a game in the initial position. This is actually just a wrapper for ``p4_fen2state(P4_INITIAL_BOARD)``, with ``P4_INITIAL_BOARD`` being the appropriate FEN string. With other FEN strings you can start the game in another position. The ``state`` object has three methods, which are wrappers around global functions in ``engine.js``. You can use the global functions just as well, using this conversion table:: state.findmove(depth) <--> p4_findmove(state, depth) state.move(...) p4_move(state, ...) state.jump_to_moveno(n) p4_jump_to_moveno(state, n) state.findmove(depth) +++++++++++++++++++++ This finds the computer’s moves. ``state`` is the object returned by ``p4_new_game()``, and ``depth`` is an integer 1 less than the depth of the desired search. That is, a ``3`` will give you a 4-ply search. It returns the array ``[start, end, score]``, where ``start`` and ``end`` are board co-ordinates suitable for feeding into ``state.move()``, which is what you need to do if you actually want to make the move it found. state.move(start, end, promotion) or state.move(move_string) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ This moves the piece and updates the board state. ``promotion`` is the piece the pawn should become if this move happens to be moving a pawn to the end. The options are ``P4_ROOK``, ``P4_KNIGHT``, ``P4_BISHOP``, and ``P4_QUEEN``, equating to 4, 6, 8, and 12 respectively. If ``promotion`` is omitted, ``P4_QUEEN`` is assumed. The start and end can take various forms. The native form used by ``display.js`` and ``state.findmove`` are indexes into a 120 element array, which is conceptually a 10x12 board, with the 8x8 board placed at the centre, thus:: + 0123456789 0 ########## 10 ########## 20 #RNBQKBNR# 30 #PPPPPPPP# 40 #........# 50 #........# 60 #........# 70 #........# 80 #pppppppp# 90 #rnbqkbnr# 100 ########## 110 ########## The idea behind this representation is that any piece trying to walk off the board will hit a wall (“``#``” in the diagram), which simplifies bounds checking. There are two rows at top and bottom to catch the knights. The white pieces start in locations 21-28 and 31-38, and the black ones in 91-98 and 81-88, so moving the white kings pawn out 2 rows (*e4* in algebraic notation) would be made using:: state.move(35, 55); But ``state.move`` will also accept a split algebraic form:: state.move('e2', 'e4'); /*start and end in algebraic notation*/ or various complete algebraic forms, where ``end`` and ``promotion`` are both ignored:: state.move('e4'); state.move('e2-e4'); /* 'long' algebraic notation */ If you are using this for, you should set the pawn promotion as part of the algebraic string (or you’ll just get queens): state.move('e8=N'); /*got to end; promote to knight*/ state.move() return value +++++++++++++++++++++++++ You get back an object like this:: { flags: