Een stapsgewijze handleiding voor het bouwen van een eenvoudige schaak-AI

Laten we enkele basisconcepten onderzoeken die ons zullen helpen een eenvoudige schaak-AI te maken:

  • move generatie
  • evaluatie van het bestuur
  • minimax
  • en alpha beta snoeien.

Bij elke stap verbeteren we ons algoritme met een van deze beproefde technieken voor het programmeren van schaken. Ik zal laten zien hoe elk de speelstijl van het algoritme beïnvloedt.

Je kunt het laatste AI-algoritme hier op GitHub bekijken.

Stap 1: Verplaats generatie en bordvisualisatie

We gebruiken de bibliotheek chess.js voor het genereren van bewegingen en chessboard.js voor het visualiseren van het bord. De bibliotheek voor het genereren van bewegingen implementeert in principe alle schaakregels. Op basis hiervan kunnen we alle legale zetten voor een bepaalde bestuursstaat berekenen.

Een visualisatie van de functie voor het genereren van bewegingen. De startpositie wordt gebruikt als invoer en de uitvoer is alle mogelijke bewegingen vanuit die positie.

Met behulp van deze bibliotheken kunnen we ons alleen richten op de meest interessante taak: het algoritme maken dat de beste zet vindt.

We beginnen met het maken van een functie die gewoon een willekeurige zet retourneert van alle mogelijke zetten:

Hoewel dit algoritme geen erg solide schaker is, is het een goed uitgangspunt, omdat we er eigenlijk tegen kunnen spelen:

Zwart speelt willekeurige zetten. Speelbaar op https://jsfiddle.net/lhartikk/m14epfwb/4

Stap 2: Positie-evaluatie

Laten we nu proberen te begrijpen welke kant sterker is in een bepaalde positie. De eenvoudigste manier om dit te bereiken is om de relatieve sterkte van de stukken op het bord te tellen met behulp van de volgende tabel:

Met de evaluatiefunctie kunnen we een algoritme maken dat de beweging kiest die de hoogste evaluatie oplevert:

De enige tastbare verbetering is dat ons algoritme nu een stuk vastlegt als het kan.

Zwart speelt met behulp van de eenvoudige evaluatiefunctie. Speelbaar op https://jsfiddle.net/lhartikk/m5q6fgtb/1/

Stap 3: Zoek in boomstructuur met Minimax

Vervolgens gaan we een zoekboom maken waaruit het algoritme de beste zet kan kiezen. Dit wordt gedaan met behulp van het Minimax-algoritme.

In dit algoritme wordt de recursieve boom van alle mogelijke bewegingen tot op een bepaalde diepte verkend en wordt de positie geëvalueerd aan het einde van de "bladeren" van de boom.

Daarna retourneren we de kleinste of de grootste waarde van het kind naar het bovenliggende knooppunt, afhankelijk van of het een witte of een zwarte is om te verplaatsen. (Dat wil zeggen, we proberen de uitkomst op elk niveau te minimaliseren of te maximaliseren.)

Een visualisatie van het minimax-algoritme in een kunstmatige positie. De beste zet voor wit is b2-c3, omdat we kunnen garanderen dat we een positie kunnen bereiken waar de evaluatie -50 is

Met minimax begint ons algoritme een aantal basistactieken van schaken te begrijpen:

Minimax met diepteniveau 2. Speelbaar op: https://jsfiddle.net/k96eoq0q/1/

De effectiviteit van het minimax-algoritme is sterk gebaseerd op de zoekdiepte die we kunnen bereiken. Dit zullen we in de volgende stap verbeteren.

Stap 4: Alpha-beta snoeien

Alpha-beta-snoei is een optimalisatiemethode voor het minimax-algoritme waarmee we sommige takken in de zoekboom kunnen negeren. Dit helpt ons om de minimax-zoekboom veel dieper te evalueren, terwijl we dezelfde bronnen gebruiken.

Het alpha-beta snoeien is gebaseerd op de situatie waarin we kunnen stoppen met het evalueren van een deel van de zoekboom als we een beweging vinden die tot een slechtere situatie leidt dan een eerder ontdekte beweging.

Het alpha-beta snoeien heeft geen invloed op de uitkomst van het minimax-algoritme - het maakt het alleen sneller.

Het alpha-beta-algoritme is ook efficiënter als we toevallig die paden bezoeken die tot goede bewegingen leiden.

De posities die we niet hoeven te onderzoeken als alpha-beta snoeien wordt gebruikt en de boom wordt bezocht in de beschreven volgorde.

Met alpha-beta krijgen we een significante boost voor het minimax-algoritme, zoals in het volgende voorbeeld wordt getoond:

Het aantal posities dat nodig is om te evalueren of we een zoekopdracht met diepte 4 willen uitvoeren en de 'root'-positie wordt getoond.

Volg deze link om de verbeterde alpha-beta versie van de schaak AI te proberen.

Stap 5: Verbeterde evaluatiefunctie

De initiële evaluatiefunctie is vrij naïef omdat we alleen het materiaal tellen dat op het bord staat. Om dit te verbeteren, voegen we aan de evaluatie een factor toe die rekening houdt met de positie van de stukken. Een ridder in het midden van het bord is bijvoorbeeld beter (omdat deze meer opties heeft en dus actiever is) dan een ridder aan de rand van het bord.

We gebruiken een enigszins aangepaste versie van stuk-vierkanttafels die oorspronkelijk zijn beschreven in de schaak-programmeer-wiki.

De gevisualiseerde stuk-vierkant tabellen gevisualiseerd. We kunnen de evaluatie verlagen of verhogen, afhankelijk van de locatie van het stuk.

Met de volgende verbetering beginnen we een algoritme te krijgen dat een "fatsoenlijk" schaakspel speelt, tenminste vanuit het gezichtspunt van een casual speler:

Verbeterde evaluatie en alpha-beta snoeien met zoekdiepte van 3. Speelbaar op https://jsfiddle.net/q76uzxwe/1/

conclusies

De kracht van zelfs een eenvoudig schaakalgoritme is dat het geen domme fouten maakt. Dit gezegd hebbende, ontbreekt het nog steeds aan strategisch begrip.

Met de methoden die ik hier heb geïntroduceerd, hebben we een schaakspel-algoritme kunnen programmeren dat eenvoudig schaken kan spelen. Het "AI-gedeelte" (exclusief beweging-generatie) van het uiteindelijke algoritme is slechts 200 coderegels, wat betekent dat de basisconcepten vrij eenvoudig te implementeren zijn. Je kunt de definitieve versie bekijken op GitHub.

Enkele verdere verbeteringen die we aan het algoritme kunnen aanbrengen, zijn bijvoorbeeld:

  • move-ordering
  • snellere verplaatsingsgeneratie
  • en eindspel-specifieke evaluatie.

Als je meer wilt weten, bekijk dan de wiki over schaken programmeren. Het is een nuttige bron voor het verkennen van meer dan deze basisconcepten die ik hier heb geïntroduceerd.

Bedankt voor het lezen!