The cool story: I wanted to teach AIs play well in the "allow alliances" game mode, but Per claims that no good diplomacy is possible to script up. I still was willing to try it, but it's too easy to make mistakes or allow unwanted exploits. So i need some way of testing things quickly without playing a whole wz game.
So i made a wrapper script (lets call it test.js) to wrap around the partial AI script i'm testing (lets call it diplomacy.js) in such a way that the second script could be included into the real AI without changes, while the first script emulates the game by calling the necessary functions and event handlers from the second script.
It all runs on rhino, a free command-line JavaScript engine. I just fire up the rhino console, say load("test.js"), it itself loads the diplomacy scripts, and then i call the simple JS functions provided by test.js:
- h(i) - mark player i as a human (disable automatic behaviour);
- m(i) - set i as the current player (needs to be marked as human first);
- o(i) - offer alliance from current player to player i;
- b(i) - break alliance from current player to player i;
- s() - make some random player that is not marked as a human offer or break a random alliance.
Code: Select all
$ rhino
Rhino 1.7 release 4 2012 09 15
js> load("test.js")
me = 0
js> o(1)
0 befriends 1
1 befriends 0
js> s()
_____________________________
>>>> tick
<<<< tack
7 befriends 2
2 befriends 7
teams: [ 0 1 ] [ 2 7 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 8 ] [ 9 ]
me = 0
js> o(3)
0 befriends 3
3 tells 0: You must break your alliance with 1 first.
js> s()
_____________________________
>>>> tick
<<<< tack
6 befriends 0
6 befriends 1
1 befriends 6
teams: [ 0 1 3 ] [ 2 7 ] [ 4 ] [ 5 ] [ 6 ] [ 8 ] [ 9 ]
me = 0
Code: Select all
// hide the internals from the user
(function(_global) {
var maxPlayers = 10; // set anything here
var arr = []; // emulating the alliance matrix
var me = 0; // a global representing "me" for every instance
var humans = []; // humans don't do stuff automatically
// initialize the arrays
for (var i = 0; i < maxPlayers; ++i) {
humans[i] = false;
arr[i] = [];
for (var j = 0; j < maxPlayers; ++j)
arr[i][j] = false;
}
/* for convenience */
function random(max) {
return Math.floor(Math.random() * max);
}
function printme() {
print("me = " + me);
}
/* new script API functions i want implemented */
function offerAlliance(j) {
var i = me;
print(i + " befriends " + j);
arr[i][j] = true;
for (me = 0; me < maxPlayers; ++me)
if (!humans[me])
eventAllianceOffered(i, j);
me = i;
}
function breakAlliance(j) {
var i = me;
print(i + " betrays " + j);
arr[i][j] = false;
for (me = 0; me < maxPlayers; ++me)
if (!humans[me])
eventAllianceBroken(i, j);
me = i;
}
/* emulating existing script API functions */
function allianceExistsBetween(i, j) {
return arr[i][j];
}
function chat(to, message) {
print(me + " tells " + to + ": " + message);
}
function _(str) {
return str;
}
/* include the stuff we're testing */
eval(readFile("diplomacy.js"));
/* the main loop */
function step() {
print("_____________________________");
// emulate waiting for player reaction
print(">>>> tick");
for (me = 0; me < maxPlayers; ++me)
if (!humans[me])
doRelaxAlliances();
// emulate player activity
print("<<<< tack");
me = random(maxPlayers);
if (!humans[me])
doRandomStuff();
// print teams
var str = "teams: "
var printed = [];
for (var i = 0; i < maxPlayers; ++i)
printed[i] = false;
for (var i = 0; i < maxPlayers; ++i)
if (!printed[i]) {
str += "[ " + i + " ";
for (var j = i; j < maxPlayers; ++j)
if (!printed[j] && allianceExistsBetween(i, j)) {
str += j + " ";
printed[j] = true;
}
str += "] ";
}
print(str);
m(0);
}
/* functions for using in the shell */
_global.h = function(i) { humans[i] = true; me = i; printme(); }
_global.m = function(i) { me = humans[i] ? i : me; printme(); }
_global.o = offerAlliance;
_global.b = breakAlliance;
_global.s = step;
// add a human player
h(0);
// end: hide the internals from the user
})(this);
Code: Select all
// for convenience
function A(i, j) {
return allianceExistsBetween(i, j);
}
function eventAllianceOffered(from, to) {
// somebody says he loves us?
// do the necessary blushing.
if (me === to) {
// nothing to do if we are already in love
if (A(me, from))
return;
// what if from is a bad guy,
// who deals with nasty people?
for (var i = 0; i < maxPlayers; ++i)
if (i != me && A(from, i) && !A(me, i)) {
chat(from, _("You must break your alliance with " + i + " first."));
return;
}
// otherwise, friendship is magic
offerAlliance(from);
}
}
function eventAllianceBroken(from, to) {
// was it a reply? nothing special then
if (!A(to, from))
return;
}
function doRandomStuff() {
var i = random(maxPlayers);
// betray friends from time to time
if (random(3) == 0)
if (me !== i && A(me, i)) {
breakAlliance(i);
return;
}
// make friends most of the time
if (me !== i && !A(i, me) && !A(me, i))
for (var j = 0; j < maxPlayers; ++j)
if (me !== j && (i === j || A(i, j)))
offerAlliance(j);
}
function doRelaxAlliances() {
// remove outdated alliance offers
for (var i = 0; i < maxPlayers; ++i)
if (i !== me && A(me, i) && !A(i, me))
breakAlliance(i);
}