Skip to content

Commit

Permalink
Homeworlds move generation is active. Prepped for 0.2.1 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Perlkonig committed Oct 31, 2021
1 parent 0ce5d3f commit 4755a8b
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 23 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.1] - 2021-10-31

### Added

- Homeworlds now uses the expanded annotations feature of the renderer.
- There is now a move generator for Homeworlds! It's not particularly efficient, but it appears to at least function.
- A rudimentary AI has been added, but it's very uneven. The move tree for Homeworlds can balloon quickly with a lot of movement actions.

## [0.2.0] - 2021-10-29

### Added
Expand Down
21 changes: 17 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@abstractplay/gameslib",
"version": "0.2.0",
"version": "0.2.1",
"description": "TypeScript implementations of the core Abstract Play games, intended to be wrapped by the front- and backends",
"main": "build/index.js",
"types": "build/index.d.ts",
Expand Down Expand Up @@ -47,6 +47,7 @@
"ajv": "^6.12.6",
"graphology": "^0.21.0",
"graphology-shortest-path": "^1.4.1",
"js-combinatorics": "^1.5.4",
"minmax-wt-alpha-beta-pruning": "^1.0.5",
"rfdc": "^1.3.0"
}
Expand Down
11 changes: 2 additions & 9 deletions src/ais/blam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const gameRules = {

export class BlamAI extends AIBase {
/**
* The Blam AI prefers first of all having more players than anybody else.
* The Blam AI prefers first of all having more pieces than anybody else.
* After that, it values score, then number of captured pieces.
*/
public static evaluate(state: IBlamState): number {
Expand All @@ -51,15 +51,8 @@ export class BlamAI extends AIBase {
stashcounts[k - 1] = v.reduce((a, b) => {return a + b;});
});

// Calculate piece advantage compared with highest (or next highest) player
const mystash = stashcounts[g.currplayer - 1];
delete stashcounts[g.currplayer - 1];
const maxstash = Math.max(...stashcounts);
const diff = mystash - maxstash;
if (Math.abs(diff) > 1) {
score += (diff * wtPieces)
}

score += mystash * wtPieces
score += g.scores[g.currplayer - 1] * wtScore;
score += g.caps[g.currplayer - 1] * wtCaps;

Expand Down
74 changes: 74 additions & 0 deletions src/ais/homeworlds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { HomeworldsGame, IHomeworldsState } from "../games";
import {minmax} from 'minmax-wt-alpha-beta-pruning';
import { AIBase } from "./_base";
import { IAIResult } from ".";

const gameRules = {
listMoves (state: IHomeworldsState): string[] {
const g = new HomeworldsGame(state);
return g.moves();
},
nextState (state: IHomeworldsState, move: string): IHomeworldsState {
const g = new HomeworldsGame(state);
g.move(move);
return g.state();
},
terminalStateEval (state: IHomeworldsState): number|null {
const g = new HomeworldsGame(state);
// g.checkEOG();
if (! g.gameover) {
return null;
}
if (g.winner.includes(g.currplayer)) {
return Infinity;
} else {
return -Infinity;
}
}
}

export class HomeworldsAI extends AIBase {
/**
* The only thing the AI cares about is piece superiority.
* Larger pieces are preferred over smaller ones.
*/
public static evaluate(state: IHomeworldsState): number {
let score = 0;
const wtLge = 2;
const wtMed = 1.5;
const wtSm = 1;

const g = new HomeworldsGame(state);
// Find all ships you own and add their value to your score
const myseat = g.player2seat();
for (const sys of g.systems) {
for (const ship of sys.ships) {
if (ship.owner === myseat) {
switch (ship.size) {
case 1:
score += ship.size * wtSm;
break;
case 2:
score += ship.size * wtMed;
break;
case 3:
score += ship.size * wtLge;
break;
default:
throw new Error("Unrecognized ship size. This should never happen.");
}
}
}
}

return score;
}

public static findmove(state: IHomeworldsState, plies: number): string {
const result: IAIResult = minmax(state, gameRules, HomeworldsAI.evaluate, plies);
if ( (result === undefined) || (! result.hasOwnProperty("bestMove")) || (result.bestMove === undefined) || (result.bestMove === null) ) {
throw new Error("No best move found. This should never happen.");
}
return result.bestMove;
}
}
11 changes: 8 additions & 3 deletions src/ais/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AmazonsAI } from "./amazons";
import { BlamAI } from "./blam";
import { CannonAI } from "./cannon";
import { MchessAI } from "./mchess";
import { HomeworldsAI } from "./homeworlds";

export interface IAIResult {
bestMove: string|null;
Expand All @@ -13,20 +14,22 @@ export interface IAI {
findmove: (state: any, depth: number) => string;
}

export { AIBase, AmazonsAI, BlamAI, CannonAI, MchessAI };
export { AIBase, AmazonsAI, BlamAI, CannonAI, MchessAI, HomeworldsAI };

export const supportedGames: string[] = ["amazons"];
export const fastGames: Map<string, number> = new Map([
["amazons", 1],
["blam", 3],
["cannon", 3],
["mchess", 5]
["mchess", 5],
["homeworlds", 4]
]);
export const slowGames: Map<string, number> = new Map([
["amazons", 2],
["blam", 5],
["cannon", 5],
["mchess", 7]
["mchess", 7],
["homeworlds", 6]
]);

export function AIFactory(game: string): AIBase|undefined {
Expand All @@ -39,6 +42,8 @@ export function AIFactory(game: string): AIBase|undefined {
return new CannonAI();
case "mchess":
return new MchessAI();
case "homeworlds":
return new HomeworldsAI();
}
return;
}
Loading

0 comments on commit 4755a8b

Please sign in to comment.