Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ### Save as autoplayer.md
- #### Fairy Stockfish
- https://github.com/fairy-stockfish/Fairy-Stockfish/releases
- #### variants.ini
- https://github.com/fairy-stockfish/Fairy-Stockfish/blob/master/src/variants.ini
- ```
- [Snails]
- maxRank = 8
- maxFile = h
- customPiece1 = X:fmWfceWifmnD
- customPiece2 = Y:fmFfceFifmnA
- customPiece3 = P:fmWfceFifmnD
- customPiece4 = B:fmFfceWifmnA
- customPiece5 = S:fmKfceKifmnDifmnA
- customPiece6 = G:gR
- enPassantTypes = XYPBS
- doubleStepRegionWhite = *2 *3 *4 *5 *6
- doubleStepRegionBlack = *3 *4 *5 *6 *7
- enPassantRegion = *3 *4 *5 *6
- capturesToHand = true
- pieceDrops = true
- whiteDropRegion = *2
- blackDropRegion = *7
- flagPiece = G
- flagRegionWhite = d1 e1 f1 g1 h1
- flagRegionBlack = d8 e8 f8 g8 h8
- extinctionPieceTypes = G
- extinctionPseudoRoyal = true
- startFen = g7/***5/***5/***5/***5/***5/***5/G7[XYPBSxypbs] w - - 0 1
- ```
- #### autoplayer.ini
- ```
- [Engine0]
- name = Donald
- path = stockfish
- [Engine1]
- name = Waldo
- path = stockfish
- [Common]
- variant = Snails
- threads = 1
- hash = 1024
- [Game]
- movetime_ms = 2000
- limit_moves = 200
- equal_phase = 20
- draw_threshold = 20
- ```
- #### autoplayer.py
- ```
- import subprocess
- import configparser
- import re
- import time
- from datetime import datetime
- class UCIEngine:
- def __init__(self, name, path, threads, tt_size, variant):
- self.name = name
- self.path = path
- self.process = subprocess.Popen(
- self.path,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True,
- bufsize=1,
- )
- self.process.stdout.readline()
- self.send(f"setoption name Threads value {threads}")
- self.send(f"setoption name Hash value {tt_size}")
- self.send("load variants.ini")
- self.send(f"setoption name UCI_Variant value {variant}")
- self.process.stdout.readline()
- def send(self, command):
- self.process.stdin.write(command + "\n")
- self.process.stdin.flush()
- def diagram(self, moves, ranks):
- pos = "startpos" if not moves else f"startpos moves {' '.join(moves)}"
- self.send(f"position {pos}")
- self.send("d")
- diagram = [self.process.stdout.readline().rstrip('\n') for _ in range(2 * ranks + 3)]
- for _ in range(6):
- line = self.process.stdout.readline()
- return diagram
- def move(self, moves, movetime_ms):
- self.send("position startpos" if not moves else f"position startpos moves {' '.join(moves)}")
- self.send(f"go movetime {movetime_ms}")
- start_time = time.time()
- timeout = (movetime_ms / 1000.0) + 0.1
- while time.time() - start_time < timeout:
- line = self.process.stdout.readline()
- if not line:
- break
- line = line.strip()
- if line.startswith("info"):
- m = re.search(r"score\s+(cp|mate)\s+(-?\d+)", line)
- if m:
- kind = m.group(1)
- value = int(m.group(2))
- if line.startswith("bestmove"):
- parts = line.split()
- if len(parts) >= 2:
- best = parts[1]
- return best, kind, value
- return best, kind, value
- def quit(self):
- try:
- self.send("quit")
- self.process.wait(timeout=1)
- except subprocess.TimeoutExpired:
- self.process.terminate()
- finally:
- self.process.terminate()
- def play(engine, white_engine, movetime_ms, limit_moves, equal_phase, draw_threshold, output_file, ranks):
- engine[0].send("stop")
- engine[1].send("stop")
- print(f"\n {engine[white_engine].name} vs {engine[1 - white_engine].name}")
- for line in engine[white_engine].diagram([], ranks):
- print(line)
- moves, scores = [], []
- current = white_engine
- balanced_count = 0
- while True:
- move, kind, value = engine[current].move(moves, movetime_ms)
- if move == "(none)":
- if kind == "mate":
- if scores[-1] == "mate -1":
- winner = current
- else:
- winner = 1 - current
- print(f"\n {'White' if white_engine == winner else 'Black'} [{engine[winner].name}]")
- save(moves, scores, f"{'White' if white_engine == winner else 'Black'}[{engine[winner].name}]", output_file, engine[white_engine], engine[1 - white_engine])
- return engine[winner].name
- else:
- print(f"\n Draw")
- save(moves, scores, "Draw", output_file, engine[white_engine], engine[1 - white_engine])
- return "Draw"
- if kind == "cp" and abs(value) <= draw_threshold:
- balanced_count += 1
- else:
- balanced_count = 0
- if len(moves) >= limit_moves and balanced_count >= equal_phase:
- print("\n Draw by termination")
- save(moves, scores, "Draw", output_file, engine[white_engine], engine[1 - white_engine])
- return "Draw"
- score = f"{kind} {value}"
- moves.append(move)
- scores.append(score)
- print(f"\n {engine[current].name} {(len(moves)+1)//2}: {move} ({score})")
- for line in engine[current].diagram(moves, ranks):
- print(line)
- current ^= 1
- def save(moves, scores, result, filename, white, black):
- timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
- with open(filename, "a", encoding="utf-8") as f:
- f.write(f"Game {timestamp}\n")
- f.write(f"{white.name} vs {black.name}\n")
- f.write(f"{' '.join(f'{m} ({s})' for m, s in zip(moves, scores))}\n")
- f.write(f"{result}\n\n")
- def main():
- config = configparser.ConfigParser()
- config.read('autoplayer.ini')
- variant = config['Common']['variant']
- engine = [None, None]
- try:
- engine[0] = UCIEngine(
- config['Engine0']['name'],
- config['Engine0']['path'],
- config['Common']['threads'],
- config['Common']['hash'],
- variant,
- )
- engine[1] = UCIEngine(
- config['Engine1']['name'],
- config['Engine1']['path'],
- config['Common']['threads'],
- config['Common']['hash'],
- variant,
- )
- movetime_ms = int(config['Game']['movetime_ms'])
- limit_moves = int(config['Game']['limit_moves'])
- equal_phase = int(config['Game']['equal_phase'])
- draw_threshold = int(config['Game']['draw_threshold'])
- output_file = f"{variant}.txt"
- config = configparser.ConfigParser()
- config.read('variants.ini')
- ranks = int(config[variant]['maxRank'])
- results = {engine[0].name: 0, engine[1].name: 0, "Draw": 0}
- white_engine = 0
- games_played = 0
- while True:
- games_played += 1
- result = play(engine, white_engine, movetime_ms, limit_moves, equal_phase, draw_threshold, output_file, ranks)
- if result == "Draw":
- results["Draw"] += 1
- elif result == engine[white_engine].name:
- results[engine[white_engine].name] += 1
- else:
- results[engine[1 - white_engine].name] += 1
- print(f" Score after {games_played} games:")
- print(f" {engine[0].name}: {results[engine[0].name]} wins")
- print(f" {engine[1].name}: {results[engine[1].name]} wins")
- print(f" Draws: {results['Draw']}")
- print("\n" * (2 * ranks - 1), end="")
- white_engine ^= 1
- except KeyboardInterrupt:
- print("\n\nStopping autoplayer")
- except Exception as e:
- print(f"\nError occurred {e}")
- finally:
- for e in engine:
- if e is not None:
- try:
- e.quit()
- except:
- pass
- print("Engines terminated")
- if __name__ == "__main__":
- main()
- ```
Advertisement
Add Comment
Please, Sign In to add comment