Skip to content

nbqofficial/viking

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

111 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Logo

Viking

Strongest Croatian chess engine.

Play Viking on Lichess

Overview

Viking is a free and strong UCI chess engine that can be used to analyze chess positions and come up with the optimal move. Viking ships with its own lightweight desktop GUI (see Viking GUI below), and because it speaks UCI it also works with any third-party GUI of your choice.

Nibbler Arena Chess GUI

About the engine

Viking is programmed and fine-tuned in a way to play aggressive interesting chess. It will avoid draws at all cost, even if that results in a loss. Playing in this fashion makes the games very entertaining and fun to watch.

Playing strength

Viking's playing strength is not really known at this point and more robust testing is required to confirm. I suspect it is around 2550 ELO for the Stockfish NNUE version, and around 2100 ELO for the hand-crafted evaluation. Viking NNUE version easily obliterates TSCP by Tom Kerrigan and stronger engines like Thor's Hammer by Toma Roncevic (another Croatian-made chess engine).

Accuracy of the following games was analyzed using Stockfish 17.1 NNUE

Blitz 3+2

Viking vs TSCP, Accuracy 95%
TSCP rating
Accuracy
Viking outplays TSCP and converts to a winning endgame.
Viking vs Thor's Hammer, Accuracy 97%
Thor's Hammer rating
Accuracy
A positional masterpiece forcing Thor's Hammer to resign.
Viking vs SOS, Accuracy 94%
SOS rating
Accuracy
Viking holds a draw against a ~2600 engine as black.

Rapid 30+5

Viking vs Octochess, Accuracy 95%
Octochess rating
Accuracy
Viking shows great positional understanding with this brilliant win.
Viking vs AnMon, Accuracy 98%
AnMon rating
Accuracy
Viking manages to hold a draw with very precise and accurate positional play.
Viking vs Beowulf, Accuracy 95%
Beowulf rating
Accuracy
Amazing attacking game featuring three sacrifices forcing Beowulf to resign.

Board representation

Viking uses the bitboard approach for the board representation. Internally it keeps track of 12 bitboards (one per piece type for each color), as well as 3 bitboards for occupied squares (white, black and both). The internal board class also has flags for side-to-move, castling rights, en passant, fifty move rule counter etc. Board class also makes it convinient to store past move history, as well as heuristics such as killer and history moves. Zobrist hashkey is used to differenciate each unique chess position and aids in Viking's transposition table implementation. The choice for this board representation approach is clear: speed and performance.

Move generator

Viking is using precomputed bitboard attack tables for generating pawn, knight and king moves. For slider pieces (bishops, rooks and queens), Viking uses Magic bitboards by default, but it can also be compiled to use Hyperbola Quintessence move generation. That being said, Viking with Magic bitboards produces PERFT speeds of around 25M nodes/second, whereas Hyperbola Quintessence does around 18M nodes/second on regular consumer-grade hardware.

Search

Viking employs traditional negamax alpha-beta pruning search algorithm with many optimizations added on top. These include iterative deepening, null-move pruning, principal variation search, transposition table, late move reductions etc.

Move ordering

Negamax: $O(b^d)$     Alpha-beta (best case): $O(b^{d/2})$

In order to make alpha-beta pruning as efficient as possible, ordering of moves is paramount.

  • Transposition table - If the move is already found in our transposition table, we can just use it.
  • Principal variation - Best move from the previous search depth is likely to be a good move in the deeper search.
  • MVVLVA - Most valuable victim, least valuable attacker. Viking orders captures by relative piece value, where bigger score is given to the move where a low value piece (eg. pawn) captures a higher value piece (eg. bishop).
  • Killer moves - Heuristic used for ordering of quiet moves which caused a beta-cutoff in a sibling node.
  • History moves - Heuristic used for ordering of quiet moves which caused an increase in alpha in the sibling node.
  • Possible attacks - Heuristic used for ordering of quiet moves which, if played, would attack an opponents piece. It is similar in nature to MVVLVA, but used for quiet moves instead of capture moves.

Combining all of these move ordering techniques causes Viking to pick the optimal move within the first few moves around 85% of the time meaning that only about 15% of the time, it must go through more than a couple of moves to obtain a cuttoff.

Evaluation

Viking has two options for position evaluation: Efficiently Updatable Neural Networks (NNUE) or hand-crafted evaluation. NNUE version is quite a bit stronger and is using this Stockfish NNUE renamed to viking.nnue for general aesthetics. I am planning on introducing a config file to hold this, so that the original file names can stay the same. Below you can see what the hand-crafted evaluation uses.

General

  • Material - Value of each piece on the board weighted by opening/endgame phases.
  • Positional - Uses piece-square tables to evaluate position of each piece weighted by opening/endgame phases.
  • Space control - Bonus points for controlling space on the opponent's side of the board.
  • Center control - Most pieces are strongest in the center, so bonus is given for strong central presence.
  • Tempo - Bonus for having the right to make a move, it promotes attacking chess.

King safety

  • Files - Penalty for having open or half-open files in front of the castled king.
  • King ring - Penalty for having too many opponent's pieces near your king.

Pawns

  • Doubled pawns - Penalty is given for doubled or trippled pawns because they can be easily captured.
  • Isolated pawns - Penalty is give for having pawns without other pawns on either side because they need stronger pieces to defend them.
  • Passed pawns - Bonus is given for having a passed pawn because it can often promote in the endgame and is difficult to guard.
  • Undefended pawns - Penalty for having pawns which are not currently defended by other pawns.

Knights

  • Mobility - Bonus for each possible square the knight can jump to.
  • Closed position - Bonus for having a knight in closed positions because they are more useful than bishops.
  • Undefended knights - Penalty for having knights which are not currently defended by pawns (outposts).

Bishops

  • Mobility - Bonus for each possible move the bishop can slide to.
  • Bishop pair - Bonus for having two bishops because they work better in tandem.
  • Blocked bishop - Penalty for having a bishop blocked by pawns (tall pawn).
  • Color complex - Bonus for having bishops which can infiltrate gaps in opponent's defenses

Rooks

  • Mobility - Bonus for each possible move the rook can slide to.
  • Files - Bonus for having rooks on open/half-open files.

Queens

  • Mobility - Bonus for each possible move the queen can slide to.

UCI Protocol

Viking uses UCI protocol which is the most commonly used protocol for communication between chess engines and GUIs or other interfaces. This allows Viking to be connected to popular software like Arena Chess GUI or Nibbler.

Usage

Here is a list of possible commands you can use with Viking command line interface.

uci

Initializes communication and switches the engine into UCI mode.

isready

Checks whether the engine is fully ready to receive commands.

position

Tells the engine what the current position on the board is and optionally provides a move history.

  • startpos → Start from the standard chess initial position.
  • fen → Start from a custom position defined by a FEN string.
  • moves → A list of UCI move strings to play from that starting point.

go

Tells the engine to start calculating the best move given the current position.

  • go → Engine will search infinitelly or until stopped.
  • go depth 10 → Engine will search up to depth 10 and then stop.
  • go movetime 5000 → Engine will search for 5 seconds and then output the best move.
  • go wtime 60000 btime 60000 winc 1000 binc 1000 → Engine will decide it's own search time according to time left.
  • go infinite → Engine will search indefinitelly or until stopped.

perft

Runs engine performance testing from current position to check the overall traversal speed and move generator accuracy.

  • perft 6 → Engine will perform perft test up to depth of 6.

displayboard

Displays the current chess position to the command line interface.

displaymoves

Displays a list of possible moves from the current chess position.

displayaftermove

Causes the engine to display the chess position after making each move.

debug

Tells the engine to display verbose debug logs when analyzing the chess position.

testpos

Engine will check it's optimal move to see if it is among top 3 Stockfish 17.1 NNUE recommendations for accuracy.

  • testpos 5000 → Engine will search 5 seconds per position inside testpos.csv.

Viking GUI

Viking comes with a purpose-built desktop GUI (under the gui/ folder) that lets you load the engine, play against it, watch it think, and analyze full games — without having to install Arena or Nibbler. It's built with Electron so it's cross-platform in principle, but the primary target is Windows.

Features

  • Load any UCI engine via a file dialog — not just Viking.
  • Interactive board with legal-move hints shown when you pick up a piece and last-move highlighting.
  • Live info panel on the right with depth, score, nodes, nps, time, and the full principal variation, plus a raw UCI log and a free-form command input.
  • Best-move arrow drawn on the board while the engine is thinking — including a blue pill showing the current evaluation from White's POV. The arrow sticks around after bestmove until the position changes, and never renders an illegal move.
  • Analyze continuously — toggle an infinite search that automatically restarts whenever the position changes (your move, undo, FEN paste).
  • Engine plays opponent — let the engine reply to each of your moves using the configured depth/movetime.
  • Selfplay — the engine plays both sides from the current position; stops on checkmate, stalemate, insufficient material, 3-fold repetition, or the 50-move rule.
  • FEN load — paste any FEN into the input below the board to jump to that position (Enter or plain paste both work).
  • Evaluation graph under the board that tracks White-POV eval move-by-move as the game progresses.
  • Import PGN — load a game from a .pgn file into the GUI without running any engine analysis.
  • Moves list + navigation — SAN moves on the side, click any to jump, or use ⏮ ◀ ▶ ⏭ / arrow keys / Home / End. Making a move mid-line forks the game.
  • Analyze (PGN) — walks the loaded game through the engine at the configured depth/movetime and computes:
    • White / Black accuracy % (Lichess formula)
    • Top-1 match count per side
    • Inaccuracies / Mistakes / Blunders buckets per side
    • Per-move detail (SAN, engine move, cp before→after, cp loss, accuracy, ✓ on match) in the engine log.
  • Export PGN — save the current game to a .pgn file with engine name, date, result, and SetUp/FEN headers when starting from a custom position.

Setup (Windows)

  1. Install Node.js (once) — grab the LTS installer from https://nodejs.org, run it, then open a new PowerShell or cmd window and check:
    node -v
    npm -v
    
  2. Build the engine. Open viking.sln in Visual Studio, select Release | x64, Build. The binary typically lands at x64\Release\engine.exe.
  3. Install the GUI's dependencies (once):
    cd gui
    npm install
    
    This pulls Electron and friends into gui\node_modules.
  4. Start the GUI:
    npm start
    
    An Electron window opens. Click Load engine…, browse to your engine.exe, and you're connected — the log shows uciok and the engine name appears at the top of the right panel.

Want a standalone installer? npm run dist produces an NSIS .exe installer under gui\dist\.

Typical workflows

  • Play a game against the engine — New game → check engine plays opponent → set a movetime (e.g. 2000 ms) → start moving pieces. Export PGN when done.
  • Analyze your moves live — set the board to the position of interest (drag pieces or paste a FEN), check analyze continuously. The arrow + eval pill update in real time as the search deepens.
  • Watch the engine play itself — set depth/movetime, click Selfplay. Great for stress-testing.
  • Post-game reviewImport PGN your game → click Analyze → walk through moves with ◀ / ▶ and look for the blunders flagged in the summary.

Notes & caveats

  • The chessboard, chess.js, and jQuery are loaded from CDN at runtime so you need internet for a first run. For a fully offline build, install them via npm and switch the <script>/<link> tags in gui/renderer/index.html to local paths.
  • PGN analysis accuracy is only as meaningful as the depth/movetime setting — shallow searches will produce noisy cp-loss numbers.
  • analyze continuously, engine plays opponent, and Selfplay are mutually exclusive by design; starting one cancels the others.

Acknowledgements

Special thanks to

  • Bluefeversoft for actually getting me hooked to computer chess, years ago with Vice tutorials.
  • Maksim Korzh for amazing bitboard chess engine tutorial series which inspired me to improve on my earlier efforts.
  • Stockfish for some implementation ideas and for borrowing their NNUE files.
  • Chessprogramming Wiki for an amazing collection of chess programming knowledge.

About

Strongest Croatian chess engine

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors