SpoookyJS

Ein multiagentenbasiertes JavaScript-Framework zur Implementation browserbasierter Brettspiele und spielübergreifender künstlicher Intelligenz

Lust auf eine Partie Tic Tac Toe?

Einige Spiele und Spielvariationen wurden bereits mit SpoookyJS umgesetzt - Spiele wie Tic Tac Toe, Dame, Schach, Backgammon, Gomoku oder das Spiel der Amazonen.

Einfache Spielerstellung

Mit SpoookyJS lassen sich browserbasierte Spiele ganz einfach erstellen. Dazu braucht's einzig das aktuelle Downloadpaket des Frameworks - und eine gute Portion JavaScript. Wie die Spielerstellung mit SpoookyJS funktioniert, darüber informieren die Tutorials.
    // ************************************************* //
    // *** Game Definition (games/tictactoe/game.js) *** //
    // ************************************************* //

    // Create a new SpoookyJS game
    var game = new Spoooky.Game;

    game.initialize("Tic Tac Toe");

    game.setDescription("Auf einem quadratischen, 3×3 Felder großen Spielfeld setzen die beiden Spieler " +
        "abwechselnd ihr Zeichen auf ein freies Feld. Der Spieler, der als Erster drei Zeichen " +
        "in eine Zeile, Spalte oder Diagonale setzen kann, gewinnt.");

    game.setGameMode("PLACING");

    // Setup Meta Entities
    var player1 = game.createPlayer({
        name: "Jan",
        type: "HUMAN"
    });

    var player2 = game.createPlayer({
        name: "Scully",
        type: "ARTIFICIAL"
    });

    // Enable active learning of the agent
    //player2.enableLearning();

    var w = "gridCellWhiteWithBorder";

    // Create the game board
    game.setupGridWorld(3, 3, [
        w, w, w,
        w, w, w,
        w, w, w
    ]);

    // Add entity blueprints to the game to use them ingame
    var black = game.addBlueprint(player2, Spoooky.Blueprints.TICTACTOE.entities.black),
        white = game.addBlueprint(player1, Spoooky.Blueprints.TICTACTOE.entities.white);

    game.addEntitiesToGameBoard([
        0, 0, 0,
        0, 0, 0,
        0, 0, 0
    ]);

    // Set the player who will start the game
    game.setPlayer(player1);

    // Game goals for tic tac toe
    // Player 1 has three entities in a row
    game.addGameRuleAtom({
        atomName : "Player1: Three entities in a row",
        atomFunction : "Player Has Number Of Entities In Row",
        atomArguments : {
            number : 3,
            playerID : player1.getID(),
            entityID : white.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 1 has three entities in a row",
        atoms    : ["Player1: Three entities in a row"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 1 has three entities in a row",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 1",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 1 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player1.getID()
        }]});

    // Player 1 has three entities in a column
    game.addGameRuleAtom({
        atomName : "Player1: Three entities in a column",
        atomFunction : "Player Has Number Of Entities In Column",
        atomArguments : {
            number : 3,
            playerID : player1.getID(),
            entityID : white.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 1 has three entities in a column",
        atoms    : ["Player1: Three entities in a column"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 1 has three entities in a column",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 1",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 1 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player1.getID()
        }]});

    // Player 1 has three entities diagonally
    game.addGameRuleAtom({
        atomName : "Player1: Three entities diagonally",
        atomFunction : "Player Has Number Of Entities Diagonally",
        atomArguments : {
            number : 3,
            playerID : player1.getID(),
            entityID : white.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 1 has three entities diagonally",
        atoms    : ["Player1: Three entities diagonally"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 1 has three entities diagonally",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 1",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 1 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player1.getID()
        }]});

    // Game Goals For Player 2
    // Player 2 has three entities in a row
    game.addGameRuleAtom({
        atomName : "Player2: Three entities in a row",
        atomFunction : "Player Has Number Of Entities In Row",
        atomArguments : {
            number : 3,
            playerID : player2.getID(),
            entityID : black.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 2 has three entities in a row",
        atoms    : ["Player2: Three entities in a row"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 2 has three entities in a row",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 2",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 2 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player2.getID()
        }]});

    // Player 2 has three entities in a column
    game.addGameRuleAtom({
        atomName : "Player2: Three entities in a column",
        atomFunction : "Player Has Number Of Entities In Column",
        atomArguments : {
            number : 3,
            playerID : player2.getID(),
            entityID : black.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 2 has three entities in a column",
        atoms    : ["Player2: Three entities in a column"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 2 has three entities in a column",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 2",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 2 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player2.getID()
        }]});

    // Player 2 has three entities diagonally
    game.addGameRuleAtom({
        atomName : "Player2: Three entities diagonally",
        atomFunction : "Player Has Number Of Entities Diagonally",
        atomArguments : {
            number : 3,
            playerID : player2.getID(),
            entityID : black.typeID
        }
    });

    game.assembleGameRule({
        name     : "Player 2 has three entities diagonally",
        atoms    : ["Player2: Three entities diagonally"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Player 2 has three entities diagonally",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output winning Message for player 2",
            jobFunction: "Print Game Process",
            jobArguments: "Spieler 2 gewinnt!"
        }, {
            jobName: "Set the Winner of the Game",
            jobFunction: "Set Winner",
            jobArguments: player2.getID()
        }]});

    // Draw rule
    game.addGameRuleAtom({
        atomName : "Every Field Has Been Played",
        atomFunction : "No Empty Field On The Game Board"
    });

    game.addGameRuleAtom({
        atomName : "Game State is INGAME",
        atomFunction : "Game State Is",
        atomArguments : "INGAME"
    });

    game.assembleGameRule({
        name     : "Draw If Game Board Is Full",
        atoms    : ["Every Field Has Been Played",
            "Game State is INGAME"]
    });

    game.connectGameRuleConsequences({
        ruleName     : "Draw If Game Board Is Full",
        consequences : [{
            jobName: "Stop the Game",
            jobFunction: "Stop Game"
        }, {
            jobName: "Output Draw Message",
            jobFunction: "Print Game Process",
            jobArguments: "Unentschieden!"
        }]});

    // ***************************** //
    // *** Interface / AngularJS *** //
    // ***************************** //
    var SpoookyGame = new Spoooky.AngularWrapper({
        game : game,
        cellWidth : 165,
        cellHeight : 165 });
Monte Carlo Spielbaum im Tic Tac Toe Spiel

Künstliche Intelligenz

Für jedes Spiel, das mit SpoookyJS erstellt wird, stellt das Framework artifizielle Gegner bereit - out of the box. Die Entscheidungsfindung der künstlichen Spieler basiert auf dem Verfahren der Monte Carlo Spielbaumsuche.

Multiagentensystem

In SpoookyJS entscheidet nicht eine einzige künstliche Intelligenz über sinnvolle Züge, sondern ein Agentenensemble. Jeder Agent des Agententeams analysiert den aktuellen Spielzustand auf unterschiedliche Art und Weise und unterbreitet einem übergeordneten Meta Agenten Zugvorschläge.
Agentenensemble
Kempelens Schachtürke

Proof of Concept

Künstliche Intelligenz in digitalen Spielen impliziert zumeist die Verwendung system- und hardwarenaher Programmiersprachen wie C++. SpoookyJS verfolgt den Ansatz einer Machbarkeitsstudie: Zwar sind die spielübergreifenden Gegner in SpoookyJS weit davon entfernt, gut - oder gar perfekt - zu spielen. Mit SpoookyJS steht jedoch ein wiederverwendbares Framework bereit, das Experimente um multiagentenbasierte künstliche Intelligenz in browserbasierten Spielen ermöglicht.

Flexible Systemarchitektur

SpoookyJS ist modular aufgebaut und intendiert die Wiederverwendbarkeit seiner Komponenten und Module.
Systemskizze SpoookyJS

Kontakt und Impressum

SpoookyJS entstand im Rahmen der Dissertation "SpoookyJS - Ein multiagentenbasiertes JavaScript-Framework zur flexiblen Implementation digitaler browserbasierter Spiele und spielübergreifender künstlicher Intelligenz" am Institut für Historisch-Kulturwissenschaftliche Informationsverarbeitung der Universität zu Köln.

Zu finden ist die Dissertation unter https://jan-wieners.de/diss/dissertation_jan-wieners.pdf.

Jan G. Wieners, Münstereifeler Str., 50937 Köln, mail@spoookyjs.de

© 2012-2020 Jan G. Wieners