About Obsidian

Discussion of anything and everything relating to chess playing software and machines.

Moderators: hgm, chrisw, Rebel

Frank Quisinsky
Posts: 6831
Joined: Wed Nov 18, 2009 7:16 pm
Location: Gutweiler, Germany
Full name: Frank Quisinsky

Re: About Obsidian

Post by Frank Quisinsky »

OK, that sounds like a brilliant idea and a sensible application. Corona, yes ... a difficult time, even for me. OK, you've got me convinced, I'll have a look at that bloody Discord after all. Next week with more peace and quiet. I hope the chess programmers don't discover me, otherwise everyone will want to have a bone to pick with me ... because of the "move-average" trauma, you know. I think Conor is one of those people who doesn't like me and has it in for me.

Must do that in secret mission!
Hope Conor will not read it.
chessica
Posts: 855
Joined: Thu Aug 11, 2022 11:30 pm
Full name: Esmeralda Pinto

Re: About Obsidian

Post by chessica »

mvanthoor wrote: Fri Jan 26, 2024 2:43 pm
Gabor Szots wrote: Fri Jan 26, 2024 1:57 pm It's been my opinion for a long time now that if a very strong engine pops up, developed for some time then abandoned, then it is a clone (sorry, a derivative) with nothing original in it. The author simply abandons it because he has implemented everything there was for the taking and has no ideas of his own.
... This was one of the big reasons for writing Rustic, so I would be able to also write https://rustic-chess.org/. ...
Many thanks for this great work. :D :D :D :D :-) :D
User avatar
jasper.sinclair
Posts: 5
Joined: Fri Nov 17, 2023 2:50 am
Location: USA
Full name: Jasper Sinclair

Re: About Obsidian

Post by jasper.sinclair »

Gabor Szots wrote: Fri Jan 26, 2024 1:57 pm
mvanthoor wrote: Fri Jan 26, 2024 1:14 pm
Sylwy wrote: Fri Jan 26, 2024 11:24 am ...
This engine posted by Gabor has the same main sources:
Gabor Szots wrote: Thu Jan 25, 2024 4:05 pm New engine Molybdenum

rn5f107s2, Germany
https://github.com/rn5f107s2/Molybdenum ... s/tag/v2.0
But the link to the engine programming discord doesn't work.

Even so, I can't believe that there are people who go: "Let's write a chess engine!" Then: "Let's hang around in the Discord and Engine Programming Channels for a few weeks!" Then, 200 commits and a fart later, another 3500 engine drops.

That just feels wrong to me. Either I'm exceedingly stupid because I can't do that, or many others are just (re)writing code without exactly understanding what it does and why. My challenge would then be: if I gave you a text editor, a compiler of your language of choice and your own knowledge and notes (so NOT the source code of your previous engine), could you do it _again_? If not, then... well... you either didn't understand, or you didn't document and forgot.

There are SO many engines that just list a bunch of features and pop out new versions every other day without even listing a changelog. Those are useless to learn from, even if open source. The same goes for "I've been writing a chess engine for the last few weeks and *pop!* here's your new 3500 Elo engine! Enjoy, bye!" And the creator was never seen again. (And may not even have been seen before.)

I ignore all of them. The only new open source engines I follow are the ones for which I can see the beginnings, that document their progress and what they are doing, and why.
I very much agree with all this. I would have written the same if I could find the appropriate words.

It's been my opinion for a long time now that if a very strong engine pops up, developed for some time then abandoned, then it is a clone (sorry, a derivative) with nothing original in it. The author simply abandons it because he has implemented everything there was for the taking and has no ideas of his own.
It's certainly seems possible to me that the author has simply:
lost interest
a family matter intervenes
...or any one of a million other possible life issues that routinely occur, does in fact occur.

But to immediately categorizing it it as a 'clone' because of that?
wow...
User avatar
jasper.sinclair
Posts: 5
Joined: Fri Nov 17, 2023 2:50 am
Location: USA
Full name: Jasper Sinclair

Re: About Obsidian

Post by jasper.sinclair »

Ras wrote: Fri Jan 26, 2024 1:34 pm
DmitriyFrosty wrote: Fri Jan 26, 2024 1:24 pmYou need compare it to Stockfish with pure nnue evaluation (when he uses one network)
Need to compare what with what? The source code? The move output? What do you even mean? Obviously, SF16 is using the network, as seen in my posting.

Also, since you started the thread: give evidence. Both Obsidian and SF16 are on Github. Give specific links to specific files with specific line numbers.
Dimitri has done no wrong? If the Obsidian author wishes to prevent future posts like this one...
I recommend he include an original solution for things like operational macros, instead of what's included in his current source code.
See lines 200-230
https://github.com/gab8192/Obsidian/blo ... an/types.h
DmitriyFrosty
Posts: 58
Joined: Mon Mar 27, 2023 8:29 pm
Full name: Dmitry Frosty

Re: About Obsidian

Post by DmitriyFrosty »

Ras wrote: Fri Jan 26, 2024 1:34 pm
DmitriyFrosty wrote: Fri Jan 26, 2024 1:24 pmYou need compare it to Stockfish with pure nnue evaluation (when he uses one network)
Need to compare what with what? The source code? The move output? What do you even mean? Obviously, SF16 is using the network, as seen in my posting.

Also, since you started the thread: give evidence. Both Obsidian and SF16 are on Github. Give specific links to specific files with specific line numbers.
With source code. At the start, look at search.cpp files of both engines.
Ras
Posts: 2582
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: About Obsidian

Post by Ras »

jasper.sinclair wrote: Sun Jan 28, 2024 11:12 pmI recommend he include an original solution for things like operational macros
Not sure how much you know about chess engines, but convenience macros are just about the least important work in that, plus that they're attributed. This is in no way indicating an SF clone. Look at the actually important parts that make a chess engine, such as the search algo and eval.
DmitriyFrosty wrote: Mon Jan 29, 2024 8:17 amWith source code. At the start, look at search.cpp files of both engines.
Specific line numbers. Not some vague hints.
Rasmus Althoff
https://www.ct800.net
DmitriyFrosty
Posts: 58
Joined: Mon Mar 27, 2023 8:29 pm
Full name: Dmitry Frosty

Re: About Obsidian

Post by DmitriyFrosty »

Ras wrote: Mon Jan 29, 2024 8:22 am
jasper.sinclair wrote: Sun Jan 28, 2024 11:12 pmI recommend he include an original solution for things like operational macros
Not sure how much you know about chess engines, but convenience macros are just about the least important work in that, plus that they're attributed. This is in no way indicating an SF clone. Look at the actually important parts that make a chess engine, such as the search algo and eval.
DmitriyFrosty wrote: Mon Jan 29, 2024 8:17 amWith source code. At the start, look at search.cpp files of both engines.
Specific line numbers. Not some vague hints.
Obsidian. types.h
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <nmmintrin.h>
#include <thread>

const std::string engineVersion = "dev-10.14";

using Key = uint64_t;
using Bitboard = uint64_t;
using TbResult = uint32_t;
using Score = int;

const std::string piecesChar = " PNBRQK pnbrqk";

constexpr int MAX_PLY = 246;
constexpr int MAX_MOVES = 224; // 32*7

#define BitCount(x) _mm_popcnt_u64(x)

inline void sleep(int millis) {
std::this_thread::sleep_for(std::chrono::milliseconds(millis));
}

inline int64_t timeMillis() {

auto sinceEpoch = std::chrono::steady_clock::now().time_since_epoch();

return std::chrono::duration_cast<std::chrono::milliseconds>(sinceEpoch).count();
}

constexpr Score
SCORE_DRAW = 0,
SCORE_MATE = 32000,
SCORE_INFINITE = 32001,
SCORE_NONE = 32002,

SCORE_MATE_IN_MAX_PLY = SCORE_MATE - MAX_PLY,

SCORE_TB_WIN = SCORE_MATE_IN_MAX_PLY - 1, // don't mix with mate scores
SCORE_TB_WIN_IN_MAX_PLY = SCORE_TB_WIN - MAX_PLY,
SCORE_TB_LOSS_IN_MAX_PLY = -SCORE_TB_WIN_IN_MAX_PLY;

enum Move {
MOVE_NONE = 0
};

enum MoveType {
MT_NORMAL, MT_CASTLING, MT_EN_PASSANT, MT_PROMOTION,
};


enum Square : int {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE,

SQUARE_NB = 64
};

enum Direction : int {
NORTH = 8,
EAST = 1,
SOUTH = -NORTH,
WEST = -EAST,

NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST
};

enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8,
RANK_NB = 8
};

enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H,
FILE_NB = 8
};

enum CastlingRights {
NO_CASTLING,
WHITE_OO,
WHITE_OOO = WHITE_OO << 1,
BLACK_OO = WHITE_OO << 2,
BLACK_OOO = WHITE_OO << 3,

SHORT_CASTLING = WHITE_OO | BLACK_OO,
LONG_CASTLING = WHITE_OOO | BLACK_OOO,

WHITE_CASTLING = WHITE_OO | WHITE_OOO,
BLACK_CASTLING = BLACK_OO | BLACK_OOO,

ALL_CASTLING = WHITE_CASTLING | BLACK_CASTLING
};

struct CastlingData {
Square kingSrc, kingDest, rookSrc, rookDest;
};

constexpr CastlingData CASTLING_DATA[9] = {
{},
{SQ_E1, SQ_G1, SQ_H1, SQ_F1}, // WHITE_OO
{SQ_E1, SQ_C1, SQ_A1, SQ_D1}, // WHITE_OOO
{},
{SQ_E8, SQ_G8, SQ_H8, SQ_F8}, // BLACK_OO
{}, {}, {},
{SQ_E8, SQ_C8, SQ_A8, SQ_D8} // BLACK_OOO
};

enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8,
RANK_NB = 8
};

enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H,
FILE_NB = 8
};

// These defines are copied from stockfish types.h

#define ENABLE_BASE_OPERATORS_ON(T) \
inline T operator+(T d1, int d2) { return T(int(d1) + d2); } \
inline T operator-(T d1, int d2) { return T(int(d1) - d2); } \
inline T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, int d2) { return d1 = d1 + d2; } \
inline T& operator-=(T& d1, int d2) { return d1 = d1 - d2; }

#define ENABLE_LOGIC_OPERATORS_ON(T) \
inline T operator~(T d1) { return T(~ int(d1)); } \
inline T operator&(T d1, int d2) { return T(int(d1) & d2); } \
inline T& operator&=(T& d1, int d2) { return d1 = d1 & d2; } \
inline T operator|(T d1, int d2) { return T(int(d1) | d2); } \
inline T& operator|=(T& d1, int d2) { return d1 = d1 | d2; }

#define ENABLE_INCR_OPERATORS_ON(T) \
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
inline T& operator--(T& d) { return d = T(int(d) - 1); }


ENABLE_BASE_OPERATORS_ON(File)
ENABLE_BASE_OPERATORS_ON(Rank)
ENABLE_BASE_OPERATORS_ON(Square)

ENABLE_INCR_OPERATORS_ON(Color)
ENABLE_INCR_OPERATORS_ON(File)
ENABLE_INCR_OPERATORS_ON(Rank)
ENABLE_INCR_OPERATORS_ON(Square)

ENABLE_LOGIC_OPERATORS_ON(CastlingRights)

enum Color : int {
WHITE, BLACK, COLOR_NB = 2
};

enum PieceType : int {
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, ALL_PIECES,
PIECE_TYPE_NB = 8
};


Stockfish types.h
CastlingRights {
NO_CASTLING,
WHITE_OO,
WHITE_OOO = WHITE_OO << 1,
BLACK_OO = WHITE_OO << 2,
BLACK_OOO = WHITE_OO << 3,

KING_SIDE = WHITE_OO | BLACK_OO,
QUEEN_SIDE = WHITE_OOO | BLACK_OOO,
WHITE_CASTLING = WHITE_OO | WHITE_OOO,
BLACK_CASTLING = BLACK_OO | BLACK_OOO,
ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING,

Value VALUE_ZERO = 0;
Value VALUE_DRAW = 0;
Value VALUE_NONE = 32002;
Value VALUE_INFINITE = 32001;

Value VALUE_MATE = 32000;
Value VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY;
Value VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY;

Value VALUE_TB = VALUE_MATE_IN_MAX_PLY - 1;
Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY;
Value VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY;

enum Square : int {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE,

SQUARE_ZERO = 0,
SQUARE_NB = 64
};

enum Direction : int {
NORTH = 8,
EAST = 1,
SOUTH = -NORTH,
WEST = -EAST,

NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST
};

enum File : int {
FILE_A,
FILE_B,
FILE_C,
FILE_D,
FILE_E,
FILE_F,
FILE_G,
FILE_H,
FILE_NB
};

enum Rank : int {
RANK_1,
RANK_2,
RANK_3,
RANK_4,
RANK_5,
RANK_6,
RANK_7,
RANK_8,
RANK_NB
};

enum Piece {
NO_PIECE,
W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN = PAWN + 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
PIECE_NB = 16
};

And its only types.h.
DmitriyFrosty
Posts: 58
Joined: Mon Mar 27, 2023 8:29 pm
Full name: Dmitry Frosty

Re: About Obsidian

Post by DmitriyFrosty »

Obsidian evaluate.cpp

namespace Eval {

// Scale down as 50 move rule approaches
score = score * (200 - pos.halfMoveClock) / 200;

// Make sure the evaluation does not mix with guaranteed win/loss scores
score = std::clamp(score, SCORE_TB_LOSS_IN_MAX_PLY + 1, SCORE_TB_WIN_IN_MAX_PLY - 1);

return score;
}

Stockfish evaluate.cpp

// Damp down the evaluation linearly when shuffling
v = v * (200 - shuffling) / 214;

// Guarantee evaluation does not hit the tablebase range
v = std::clamp(int(v), VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
Ras
Posts: 2582
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: About Obsidian

Post by Ras »

DmitriyFrosty wrote: Mon Jan 29, 2024 8:49 amObsidian. types.h
Yeah, some convenience macros, Irrelevant for originality of the engine and also attributed.
DmitriyFrosty wrote: Mon Jan 29, 2024 8:54 am Obsidian evaluate.cpp

Code: Select all

namespace Eval {

    // Scale down as 50 move rule approaches
    score = score * (200 - pos.halfMoveClock) / 200;

    // Make sure the evaluation does not mix with guaranteed win/loss scores
    score = std::clamp(score, SCORE_TB_LOSS_IN_MAX_PLY + 1, SCORE_TB_WIN_IN_MAX_PLY - 1);

    return score;
  }
Stockfish evaluate.cpp

Code: Select all

// Damp down the evaluation linearly when shuffling
    v = v * (200 - shuffling) / 214;

    // Guarantee evaluation does not hit the tablebase range
    v = std::clamp(int(v), VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
The downscaling is different, and downscaling in itself is common practice. Clamping to TB data is also common practice if using TBs.

How about you look at the actual search, which is the most important part of an engine?
Rasmus Althoff
https://www.ct800.net
DmitriyFrosty
Posts: 58
Joined: Mon Mar 27, 2023 8:29 pm
Full name: Dmitry Frosty

Re: About Obsidian

Post by DmitriyFrosty »

Obsidian timeman.cpp
void calcOptimumTime(Search::Settings& settings, Color us, clock_t* optimumTime, clock_t* maximumTime)
int overhead = Options["Move Overhead"];

int mtg = settings.movestogo ? std::min(settings.movestogo, 50) : 50;
double optScale
clock_t timeLeft = std::max(clock_t(1),
settings.time[us] + settings.inc[us] * (mtg - 1) - overhead * (2 + mtg));
optScale = std::min(0.95 / mtg,
0.88 * settings.time[us] / double(timeLeft));
*optimumTime = clock_t(optScale * timeLeft);
*maximumTime = settings.time[us] * 0.8 - overhead;






Stockfish timeman.cpp
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
double optScale
TimePoint timeLeft = std::max(TimePoint(1),
limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg));
optScale = std::min((0.88 + ply / 116.4) / mtg,
0.88 * limits.time[us] / double(timeLeft));
optimumTime = TimePoint(optScale * timeLeft);
maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, maxScale * optimumTime));