|
|||||||||||
|
Weakening an UCI engine (Windows, Python)
Hello dear all,
inspired by the ChessSystemTal2-v21 invincible? thread and as well by the birth of Absurd-1.0 engine from the same authors (C. Whittington & E. Schröder), mentioned in the very same thread, I wanted to achieve a much weaker version. Currently these engines are pretty useless for human players and chess computers, maybe except the SenseRobot Chess. On another hand, they do provide wild games when facing other mighty chess engines, and that's already an achievement - both authors deserve many thanks for sharing these. Time ago I learnt IT development, I have been pretty efficient writing Cobol but this doesn't help here ![]() So, I asked ChatGPT for some help. This provided me with the basics which nevertheless required many tests and manual improvements. This solution is based on Python; if you don't have it installed check here. The code I use is pretty basic, hence I don't suspect any particular version requirement. It is a "wrapper" meaning the Python code will act between the GUI and the UCI engine. It handles both channel queues, the one the GUI uses to talk to the engine, and the one the engine uses to talk to the GUI. It is so quite similar to known tools such as InBetween and Polyglot, just made for the specific goal of slowing down and limiting the strength of the engine. Here is the Python code: Code:
import subprocess
import threading
import sys
import time
import queue
import re
ENGINE = ["Absurd-1.0.exe"]
DEPTH_LIMIT = 4
INFO_DELAY = 2.5
info_queue = queue.Queue()
bestmove_buffer = None
bestmove_sent = False
engine = subprocess.Popen(
ENGINE,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True,
bufsize=1
)
# -------- GUI → engine --------
def gui_to_engine():
global bestmove_buffer, bestmove_sent
for line in sys.stdin:
line = line.strip()
# reset state for each new move
if line.startswith("position"):
bestmove_buffer = None
bestmove_sent = False
# enforce ponder=false
if line.lower().startswith("setoption name ponder"):
engine.stdin.write("setoption name Ponder value false\n")
engine.stdin.flush()
sys.stdout.write("info Ponder forced to false" + "\n")
sys.stdout.flush()
continue
# replace any go with go depth
if line.startswith("go"):
engine.stdin.write(f"go depth {DEPTH_LIMIT}\n")
engine.stdin.flush()
sys.stdout.write(f"info go depth forced to {DEPTH_LIMIT}\n")
sys.stdout.flush()
continue
engine.stdin.write(line + "\n")
engine.stdin.flush()
# -------- listening to engine --------
def engine_reader():
global bestmove_buffer
for line in engine.stdout:
line = line.strip()
if line.startswith("info") and not line.startswith("info string"):
info_queue.put(line)
elif line.startswith("bestmove"):
# store without posting
bestmove_buffer = line
else:
# uciok, readyok, ...
sys.stdout.write(line + "\n")
sys.stdout.flush()
# -------- slowed down info + triggering logic --------
def info_emitter():
global bestmove_sent, bestmove_buffer
while True:
line = info_queue.get()
if not bestmove_sent:
time.sleep(INFO_DELAY)
trigger = False
# --- A condition: opening move (Polyglot syntax) ---
if line == "info depth 1 time 0 nodes 0 nps 0 cpuload 0":
trigger = True
sys.stdout.write("info move played from opening library\n")
sys.stdout.flush()
# --- B condition: max depth reached ---
else:
m = re.search(r"\bdepth\s+(\d+)", line)
if m:
reached = int(m.group(1))
if reached >= DEPTH_LIMIT:
trigger = True
# display line
if not bestmove_sent:
sys.stdout.write(line + "\n")
sys.stdout.flush()
# post bestmove once max depth PV displayed
if trigger and bestmove_buffer and not bestmove_sent:
sys.stdout.write(bestmove_buffer + "\n")
sys.stdout.flush()
bestmove_sent = True
bestmove_buffer = None
# -------- Starting up --------
threading.Thread(target=gui_to_engine, daemon=True).start()
threading.Thread(target=engine_reader, daemon=True).start()
info_emitter()
Adjust the Depth & Delay to your taste, and to the expected game time setting. Sometimes, in complex positions, more PVs will be displayed (with selective depth increasing along), resulting in more time used to move, which is quite natural. Some moves will also be played much faster; hence a human-like pace. Ponder is disabled (but the opponent may ponder, if wanted, and make good use of the slowed engine time to think). Opening moves should still be played a tempo. How to use? I assume Python is installed on your PC; in the GUI (tested using Arena and HIARCS Chess Explorer Pro) you may choose the command line engine target as a .bat file instead of a .exe; so we need a tiny .bat file including only one line: python Wrapper_v2.py The above assumes you saved the Python code under the name Wrapper_v2.py (feel free to change that). I also provide a .zip file including both Python code and bat file. They must be located in the same directory where the wrapped engine is. The Wrapper ignores GUI instructions about pondering and time control; hence you can have the engine face any opponent granted any time control (great for playing as a human or launching a tournament including MessChess engines). Please let me know if specific issues occur; and if the solution is useful to you. I tested it with a couple of engines, including SF18 and polyglot (and of course Absurd and CSTal2_v21 as well). I also want to test Patricia 5 soon ![]() MfG, Tibono p.s.: I provided a new, enhanced version (SlowWrapper v4), please read down a couple of posts for more information, and get the new attachment. Geändert von Tibono (10.02.2026 um 21:00 Uhr) |
| Folgende 3 Benutzer sagen Danke zu Tibono für den nützlichen Beitrag: | ||
| Folgender Benutzer sagt Danke zu spacious_mind für den nützlichen Beitrag: | ||
Tibono (09.02.2026) | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
I watched two games with swapped colors Absurd 1.0 vs Patricia 5, both throttled to depth 4. I know I could have run this "bullet-like" using the normal engines and selecting depth 4 as the common GUI level, but I wasn't interested in. I wanted to be the kibitzer, and I was. Funny enough, Patricia 5 always increased depth one by one, resulting in 10secs /move (4 PVs, 2.5 secs/PV display for the setting I chose). On another hand, Absurd is more on the chatterbox side, frequently changing PV on intermediate depths. Yet overall he moved slightly under 15secs/move on average. And lost both games.
I also watched two games with swapped colors Absurd 1.0 vs ACI Boris set to 15secs/move. Two wins for Absurd. But YES, such matches can happen. Main (header) outcomes from CARA analysis: Code:
Absurd 1.0 NNUE SW Overview ======== Total Games: 4 Win Rate: 50.0% Record: 2-0-2 Average Accuracy: 78.9% Estimated Elo: 1131 Average CPL: 87.8 Top 3 Move %: 53.4% Patricia 5 NNUE SW Overview ======== Total Games: 2 Win Rate: 100.0% Record: 2-0-0 Average Accuracy: 85.8% Estimated Elo: 1323 Average CPL: 25.2 Top 3 Move %: 61.8% MC ACI Boris Overview ======== Total Games: 2 Win Rate: 0.0% Record: 0-0-2 Average Accuracy: 67.4% Estimated Elo: 1033 Average CPL: 121.6 Top 3 Move %: 40.9% In the names of the engines, SW stands for 'SlowWrapper' version; MC for MessChess. One can easily duplicate engines to keep one full-speed, full strength version alongside a "SlowWrapped" one. Last but not least: using SlowWrapper, the CPU stays mostly idle for the throttled down engine... Ecological, isn't it? All the best, Tibono |
| Folgende 3 Benutzer sagen Danke zu Tibono für den nützlichen Beitrag: | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
Hi all,
I simplified the triggering logic (for the GUI to apply the engine move) and made it more compliant with some UCI engines using internal books. Also, I made sure all the PV lines before bestmove sent by the engine were displayed by the SlowWrapper. As I used the reported depth for halting the display and actually send the bestmove data to the GUI, sometimes additional PVs still at same target depth could be lacking on display, whilst the engine had considered these before reporting its bestmove. There was no impact on the game, yet now the display on the GUI is more reliable, always complete as the engine did report. New version (v4) attached. Don't forget to adapt the engine exe file name, and the depth_limit and info_delay you want. By the way, info_delay in seconds can use decimals (eg 0.05 would be 50ms - even if such a low value would not help much slowing the engine down). Regards, Tibono ps: new release v4.1, please see hereunder. Geändert von Tibono (10.02.2026 um 22:55 Uhr) |
| Folgende 2 Benutzer sagen Danke zu Tibono für den nützlichen Beitrag: | ||
Mapi (10.02.2026), spacious_mind (10.02.2026) | ||
|
||||
|
AW: Weakening an UCI engine (Windows, Python)
Hi Tibono,
this is a very cool short aproach about a proxy engine. I worked on the same years ago to fix a blunderproblem for the DGTplasticwaste. If you want a engine that play's alway's on your own level, you must search for a move in some variant's that plays close to equal. The effect is a curiously playing engine that always puts you in the endgame, no matter how badly you play. Dirk |
| Folgender Benutzer sagt Danke zu DirkS für den nützlichen Beitrag: | ||
Tibono (10.02.2026) | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
Hi,
a quick win: now that the triggering is smarter, engine weakening can be chosen as limiting either depth (as before) or nodes. In the first version, reaching a specific depth was rather easy to check from the info lines provided by the engine, but reaching a target nodes number was not reliable. The engine could decide to move early, after a lower number of nodes reached (maybe forecasting any further search would too much overstep the target, maybe considering the move obvious or without any decent alternative). Since I now use a smarter triggering, this tricky case with nodes limit is no more any issue. The change in the code is very light; now you have to edit the Wrapper header to set either LIMIT_TYPE = "depth" or LIMIT_TYPE = "nodes", and that's pretty all. Then, as usual, enter values for the chosen limit and delay. Attachment provided. Hope this helps, Tibono ps: with more tests I saw some engines don't understand uppercase values for "go depth" or "go nodes"; hence please set limits as fixed above, using lowercase for values. I'll re attach the fixed zip file in a following post. Geändert von Tibono (11.02.2026 um 08:55 Uhr) |
| Folgende 3 Benutzer sagen Danke zu Tibono für den nützlichen Beitrag: | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
By the way: the much smarter triggering idea came from my old brain, not from ChatGPT's
![]() |
| Folgender Benutzer sagt Danke zu Tibono für den nützlichen Beitrag: | ||
DirkS (11.02.2026) | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
Fixed v4.1 (with more tests I saw some engines don't understand uppercase values for "go depth" or "go nodes"; hence please set limits using lowercase for values). No change to the code, just the comments and example setting, to make it clear.
example: Code:
LIMIT_TYPE = "nodes" # choose "nodes" or "depth" LIMIT_VALUE = 1000 INFO_DELAY = 1.75 # in seconds |
| Folgender Benutzer sagt Danke zu Tibono für den nützlichen Beitrag: | ||
kamoj (12.02.2026) | ||
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
Hi, I wanted to consider those who don't have Python on the PC and maybe are reluctant to install it.
I got some fine help from "Le Chat" (French AI) to consider solutions and I chose to install and use PyInstaller. It can build an exe from the .py script. Of course this prevents the user to enter the required parameters straight into the script, so for this exe version I use a SlowWrapper.ini file (this more and more looks like polyglot or inbetween architecture ).Example SlowWrapper.ini: Code:
# this file must be stored in the same directory as the engine [Parametres] # please set here the .exe file name of the engine ENGINE = Absurd-1.0.exe # please set either depth or nodes (do not use uppercase) LIMIT_TYPE = depth # please set the limit value (integer) LIMIT_VALUE = 4 # please set the throttling delay for display of info lines (in seconds; 1.75 = 1750 ms) INFO_DELAY = 1.75 Of course, those who have Python installed and maybe want to experiment can keep on using the Python script and .bat, setting the parameters directly in the script (check v4.1 attachment previously posted). MfG, Tibono |
|
|||||||||||
|
AW: Weakening an UCI engine (Windows, Python)
Hi Tibono,,,
Great Tool . Thanx you..Mark 1 |
![]() |
|
|
Ähnliche Themen
|
||||
| Thema | Erstellt von | Forum | Antworten | Letzter Beitrag |
| Test: Chessnut EVO Maia engine testing | Ray | Die ganze Welt der Schachcomputer / World of chess computers | 7 | 21.02.2024 11:25 |
| Frage: Freie Engine (Uci) für PC - Spielstil | Ecki | Die ganze Welt der Schachcomputer / World of chess computers | 4 | 05.04.2015 16:03 |
| News: Revelation als UCI engine: PCSengine software | krval | Die ganze Welt der Schachcomputer / World of chess computers | 1 | 13.08.2013 16:06 |
| Mephisto PC-Modul als UCI Engine | FluidDynamics | Die ganze Welt der Schachcomputer / World of chess computers | 0 | 14.02.2008 08:53 |
| Fruit als Engine? | Robert | Die ganze Welt der Schachcomputer / World of chess computers | 3 | 04.08.2005 08:26 |