Development of my new engine: Crispy

Discussion of chess software programming and technical issues.

Moderator: Ras

pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Development of my new engine: Crispy

Post by pedrojdm2021 »

After many months of development of my first chess engine, and help of chessprogramming wiki and this community i ended up with a decent engine, not the best or fastest one but decent in general aspects. It was such a great adventure where i learned a lot of chess programming stuf.

Now this time i want to do the things correctly, in terms of engine stability and performance, this engine will be in C# too as it is a language that i fully undestand, maybe for a future when i develop the engine correctly i can switch for something more low-level.

This time the engine will be open source, i'll share the github repository as soon as i get the very first version done

One of the things that i want to accomplish with this version is to improve my SEE algoritm to something more performant, and also i want to come up with my own tuned evaluation values, i want to learn and understand Texel's tuning or CLOP tuning, if anyone has something to share about it for a beginner with these things, i will be thankful

That's it for now, i'll be posting here the development progress, any feedback is always welcome! :D
Tearth
Posts: 70
Joined: Thu Feb 25, 2021 5:12 pm
Location: Poland
Full name: Pawel Osikowski

Re: Development of my new engine: Crispy

Post by Tearth »

Good luck! I always enjoy engines written in C#, as two of mine were done like that too.
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Development of my new engine: Crispy

Post by mvanthoor »

pedrojdm2021 wrote: Sun Mar 13, 2022 5:18 pm After many months of development of my first chess engine, and help of chessprogramming wiki and this community i ended up with a decent engine, not the best or fastest one but decent in general aspects. It was such a great adventure where i learned a lot of chess programming stuf.

Now this time i want to do the things correctly
this engine will be in C# too as it is a language that i fully undestand
You lie! C# changes while I'm reading the documentation....
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
dangi12012
Posts: 1062
Joined: Tue Apr 28, 2020 10:03 pm
Full name: Daniel Infuehr

Re: Development of my new engine: Crispy

Post by dangi12012 »

There should be a structured format like the CPW - where new engines are posted and original ideas are discussed.
I think many people write engines and some bring new ideas - but there is no place where 10 new ideas are combined into someting new altogether.

I am writing this because I saw this in comparison of all known sliding algos - that authors themselfes often do not see the similar yet very significant slight alterations that they are making that have huge implications in new code. (IE - transformative ideas that are undiscussed)

Congratiulation on the engine.

Fresh minds bring fresh ideas.
Worlds-fastest-Bitboard-Chess-Movegenerator
Daniel Inführ - Software Developer
pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Re: Development of my new engine: Crispy

Post by pedrojdm2021 »

Tearth wrote: Mon Mar 14, 2022 11:48 am Good luck! I always enjoy engines written in C#, as two of mine were done like that too.
Thank you! and yeah this is some fun stuff to do ( while we don't ran into bugs :mrgreen: ) your engine cosette has been of great inspiration to me :D
pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Re: Development of my new engine: Crispy

Post by pedrojdm2021 »

mvanthoor wrote: Mon Mar 14, 2022 9:42 pm
pedrojdm2021 wrote: Sun Mar 13, 2022 5:18 pm After many months of development of my first chess engine, and help of chessprogramming wiki and this community i ended up with a decent engine, not the best or fastest one but decent in general aspects. It was such a great adventure where i learned a lot of chess programming stuf.

Now this time i want to do the things correctly
this engine will be in C# too as it is a language that i fully undestand
You lie! C# changes while I'm reading the documentation....
Yeah i know that the C# language is growing very fast, but for now i'll keep using .net framework 4.7.1 because i want to maximise compatibility, the project will not be only an Console Application of the C# chess engine, it will be at the same time a C# class library project, that i want to make it possible to be used as a library for other C# projects, like a Game written in Unity for example. :wink:

So yeah, i want it flexible :)

When i want to do only an application console engine, i'll switch to C/C++ or C# with .net 6
pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Re: Development of my new engine: Crispy

Post by pedrojdm2021 »

dangi12012 wrote: Tue Mar 15, 2022 12:46 am There should be a structured format like the CPW - where new engines are posted and original ideas are discussed.
I think many people write engines and some bring new ideas - but there is no place where 10 new ideas are combined into someting new altogether.

I am writing this because I saw this in comparison of all known sliding algos - that authors themselfes often do not see the similar yet very significant slight alterations that they are making that have huge implications in new code. (IE - transformative ideas that are undiscussed)

Congratiulation on the engine.

Fresh minds bring fresh ideas.
Yeah, an engine/project presentation format should be listed there, it would be a good idea !
pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Re: Development of my new engine: Crispy

Post by pedrojdm2021 »

I have the basic UCI and Console application skeleton pretty much done:

Code: Select all

using System.Collections.Generic;
using StringBuilder = System.Text.StringBuilder;

namespace Crispy.UCI
{
    public sealed class UCIClient
    {
        public delegate void OnUCIMessageDelegate(string _message);
        public event OnUCIMessageDelegate OnUCIMessage;
        private string fen;
        private string ucicommand;
        private bool running = false;

        private Dictionary<string,string> positions = new Dictionary<string, string>()
        {
            {"startpos" , "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "}
        };

        /* ---------------------------------------- *
        *
        *              UCI Loop 
        *
        * ---------------------------------------- */

        public bool ParseUCICommand(string _uciCommand)
        {
            ucicommand = _uciCommand;
            return false;
        }

        public void Run()
        {
            running = true;
            UCILoop();
        }

        public void AbortAllTasks()
        {
		
        }

        public void Stop()
        {
            running = false;
        }
        
        private void UCILoop()
        {
            while (running)
            {
                if (string.IsNullOrEmpty(ucicommand)) continue;
                // get args from uci command
                string[] args = ucicommand.Trim().Split();

                if (args.Length < 1) continue;

                // Parse uci command
                switch (args[0])
                {
                    // displays current board representation
                    case "d":

                    break;
                       
                    // ---------------- UCI Commands -----------------

                    case "isready":
                        WriteMessage("readyok");
                        break;

                    case "uci":
                        DisplayEngineInfo();
                    break;

                    case "ucinewgame":

                        break;

                    case "position":
                        Parse_position(args);
                        break;

                    case "go":
                        Parse_go(args);
                        break;

                    default:
                    WriteMessage($"Unknown command: {args[0]}");
                    break;
                }

                // reset uci command
                ucicommand = string.Empty;
            }
        }

        private void DisplayEngineInfo()
        {
            WriteMessage($"id name Crispy");
            WriteMessage($"id author Pedro Duran");
            WriteMessage("readyok");
        }

        /* ---------------------------------------- *
        *
        *              UCI parse 
        *
        * ---------------------------------------- */

        private void Parse_go(string[] _args)
        {
            if(_args.Length == 1 || _args[1] == "infinity")
            {
                WriteMessage("infinite mode");
                return;
            }

            int wtime = GetParamValue<int>(_args, "wtime");
            int btime = GetParamValue<int>(_args, "btime");
            int movetime = GetParamValue<int>(_args, "movetime");
            int depth = GetParamValue<int>(_args, "depth");
            int movestogo = GetParamValue<int>(_args, "movestogo");
        }

        private void Parse_position(string[] _args)
        {
            if (_args.Length == 1) return;

            if (positions.TryGetValue(_args[1] , out string _fen))
            {
                fen = _fen;
            }else if (_args[1] == "fen")
            {
                // position fen [fenstring]
                int endIndex = ucicommand.Contains("moves") ? ucicommand.IndexOf("moves") - 14 : ucicommand.Length - 13;
                fen = ucicommand.Substring(13,endIndex);
            }
            WriteMessage($"fen: '{fen}'");

            // read moves from input
            if (ucicommand.Contains("moves"))
            {
                string[] moves_raw_list = ucicommand.Substring(ucicommand.IndexOf("moves") + 5).Trim().Split();
                WriteMessage("moves: ", true);
                for (int i = 0; i < moves_raw_list.Length; i++)
                {
                    WriteMessage($"{moves_raw_list[i]}, " , true);
                }
                WriteMessage("\n", true);
            }
        }

        private T GetParamValue<T>(string[] _args , string _paramName , T _defaultValue = default(T))
        {
            for (int x = 0; x < _args.Length; x++)
            {
                if (_args[x] == _paramName)
                {
                    int nextIndex = x + 1;
                    if (nextIndex < _args.Length)
                    {
                        return (T)System.Convert.ChangeType(_args[nextIndex] , typeof(T));
                    }
                }
            }
            return _defaultValue;
        }

        /* ---------------------------------------- *
        *
        *             UCI Info
        *
        * ---------------------------------------- */

        private void WriteMessage(string _message , bool _singleLine = false)
        {
            if (!_singleLine) _message += "\n";
            if (OnUCIMessage != null) OnUCIMessage.Invoke(_message);
        }

        public void PrintInfoMessage(string _Infomessage)
        {
           WriteMessage($"info string {_Infomessage}");
        }

        public void PrintBestMove(int _bestMove)
        {
            // placeholder: bestmove
            WriteMessage($"bestmove {_bestMove}");
        }

        public void PrintSearchInfo(int _depth, double _timeElapsed, ulong _nodeCount, int _score, int[] _pv)
        {
            double nps = (_nodeCount / (_timeElapsed / 1000));
            StringBuilder pv_builder = new StringBuilder();
            for (int i = 0; i < _pv.Length; i++) pv_builder.Append($"{_pv[i]} ");

            WriteMessage($"info depth {_depth} time {_timeElapsed} nps {nps} nodes {_nodeCount} score cp {_score} pv {pv_builder.ToString()}");
        }
    }
}
That UCI Client runs in a background thread, it is called in the Main Application "Entry point", that is where the non-uci application commands are parsed, the engine is initialized, and it is contained the engine information such as engine version.

It is clearly the correct way to do it, in my older engine i was running everything in the main-thread, and it was impossible to the user to interrumpt the search using the "stop" command, now i want to allow that.

i've got some inspiration from "Cosette" for the "parse go" part, i wanted something powerful and simple to implement, the other things have been going smoothly, very happy with the results so far :) i know is not very fast progress because i don't have very much free time right now to work in the engine but at least is something :)
pedrojdm2021
Posts: 157
Joined: Fri Apr 30, 2021 7:19 am
Full name: Pedro Duran

Re: Development of my new engine: Crispy

Post by pedrojdm2021 »

I took some time to make a simple diagram to show the program structure, this will help me to not lost focus on the initial structure and avoid mistakes
Image