Created
January 29, 2017 00:12
-
-
Save popey456963/fa8607b414b42a7060a06330654ceb1a to your computer and use it in GitHub Desktop.
JavaScript Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var chalk = require('chalk') | |
var generate = require('project-name-generator') | |
var Bot = function() { | |
this.pastPlayers = 0 | |
this.playerIndex = 0 | |
this.colours = { | |
"empty": chalk.gray, | |
"mountain": chalk.white, | |
"unknown": chalk.yellow, | |
"friendly": chalk.green, | |
"enemy": chalk.red, | |
"friendlyGeneral": chalk.blue, | |
"enemyGeneral": chalk.magenta, | |
"city": chalk.cyan | |
} | |
this.character = { | |
"empty": "E", | |
"mountain": "M", | |
"unknown": "?", | |
"friendly": "F", | |
"enemy": "B", | |
"friendlyGeneral": "FG", | |
"enemyGeneral": "EG", | |
"city": "C" | |
} | |
this.width = 0 | |
this.height = 0 | |
this.ignoreEvents = ['game_lost', 'game_won', 'queue_update', 'game_start', 'game_update'] | |
this.ourGeneral = [-1, -1] | |
this.generals = [] | |
this.movementOptions = [[-1, 0], [1, 0], [0, -1], [0, 1]] | |
this.attackIndex = 0 | |
this.lastMap = [] | |
this.lastCities = [] | |
this.firstUpdate = true | |
} | |
Bot.prototype.connect = function(url) { | |
this.socket = require('socket.io-client')(url, { transports: ['websocket'] }) | |
var onevent = this.socket.onevent | |
this.socket.onevent = function(packet) { | |
var args = packet.data || [] | |
onevent.call(this, packet) | |
packet.data = ["*"].concat(args) | |
onevent.call(this, packet) | |
} | |
} | |
Bot.prototype.play = function(name, user_id, type) { | |
if (type == undefined) { | |
this.socket.emit('play', name, user_id) | |
} else { | |
this.socket.emit('join_private', type, name, user_id) | |
} | |
} | |
Bot.prototype.forceStart = function(start) { | |
this.socket.emit('set_force_start', null, start) | |
} | |
Bot.prototype.onConnect = function(callback) { | |
this.socket.on('connect', callback) | |
} | |
Bot.prototype.onDisconnect = function(callback) { | |
this.socket.on('disconnect', callback) | |
} | |
Bot.prototype.onLose = function(callback) { | |
this.socket.on('game_lost', callback) | |
} | |
Bot.prototype.onWin = function(callback) { | |
this.socket.on('game_won', callback) | |
} | |
Bot.prototype.onQueueUpdate = function(callback) { | |
this.socket.on('queue_update', function(playerCount) { | |
if (playerCount != this.pastPlayers) { | |
callback(playerCount) | |
this.pastPlayers = playerCount | |
} | |
}) | |
} | |
Bot.prototype.onGameStart = function(callback) { | |
this.socket.on('game_start', function(data) { | |
Bot.playerIndex = data.playerIndex | |
callback(data) | |
}) | |
} | |
Bot.prototype.onChat = function(callback) { | |
this.socket.on('chat_message', function(room, data) { | |
callback(data) | |
}) | |
} | |
Bot.prototype.onGameUpdate = function(callback) { | |
this.socket.on('game_update', function(data) { | |
if (this.firstUpdate) { | |
data.lastMap = [] | |
for (var i = 0; i < data.map_diff[2] * data.map_diff[3]; i++) { | |
data.lastMap.push(0) | |
} | |
this.firstUpdate = false | |
} | |
data.map = this.patch(this.lastMap, data.map_diff) | |
this.lastMap = data.map.concat([]) | |
data.cities = this.patch(this.lastCities, data.cities_diff) | |
this.lastCities = data.cities.concat([]) | |
console.log(JSON.stringify(data)) | |
this.width = parseInt(data.map[0]) | |
this.height = parseInt(data.map[1]) | |
var map_data = this.patch(this.lastMap, data.map.slice(2, 2 + this.width * this.height)) | |
var map = [] | |
var mountain_data = data.map.slice(2 + this.width * this.height, 3 + 2 * this.width * this.height) | |
var counter = 0 | |
for (var j = 0; j < this.height; j++) { | |
var line = [] | |
for (var i = 0; i < this.width; i++) { | |
line.push([map_data[counter]]) | |
counter++ | |
} | |
map.push(line) | |
} | |
var counter = 0 | |
var y = 0 | |
for (var j = 0; j < this.height; j++) { | |
var x = 0 | |
for (var i = 0; i < this.width; i++) { | |
if (mountain_data[counter] == -1) { | |
map[y][x].push("empty") | |
} else if (mountain_data[counter] == -2 || mountain_data[counter] == -4) { | |
map[y][x].push("mountain") | |
} else if (mountain_data[counter] == -3) { | |
map[y][x].push("unknown") | |
} else if (mountain_data[counter] == Bot.playerIndex) { | |
map[y][x].push("friendly") | |
} else { | |
map[y][x].push("enemy") | |
} | |
counter++ | |
x++ | |
} | |
y++ | |
} | |
this.generals = [] | |
for (var i = 0; i < data.generals.length; i++) { | |
if (data.generals[i] != -1 && i != Bot.playerIndex) { | |
var generalXY = this.toXY(data.generals[i]) | |
if (i == Bot.playerIndex) { | |
map[generalXY[1]][generalXY[0]][1] = "friendlyGeneral" | |
this.ourGeneral = generalXY | |
} else { | |
map[generalXY[1]][generalXY[0]][1] = "enemyGeneral" | |
this.generals.push(generalXY) | |
} | |
} | |
} | |
for (var i = 0; i < data.cities.length; i++) { | |
if (data.cities[i] != -1) { | |
var mapXY = this.toXY(data.cities[i]) | |
map[mapXY[1]][mapXY[0]][1] = "city" | |
} | |
} | |
callback(data.turn, map) | |
}.bind(this)) | |
} | |
Bot.prototype.onOther = function(callback) { | |
var that = this | |
this.socket.on("*", function(event, data) { | |
if(that.ignoreEvents.indexOf(event) == -1) { | |
callback(event, data) | |
} | |
}) | |
} | |
// patch(a, delta(a, b)) === b | |
Bot.prototype.patch = function(old, diff) { | |
var out = []; | |
var i = 0; | |
while(i < diff.length) { | |
if (diff[i]) { // matching | |
Array.prototype.push.apply(out, old.slice(out.length, out.length + diff[i])); | |
} | |
i++; | |
if (i < diff.length && diff[i]) { // mismatching | |
Array.prototype.push.apply(out, diff.slice(i + 1, i + 1 + diff[i])); | |
i += diff[i]; | |
} | |
i++; | |
} | |
return out; | |
} | |
Bot.prototype.attack = function(from, to) { | |
var from = this.toPoint(from[0], from[1]) | |
var to = this.toPoint(to[0], to[1]) | |
// console.log(this.attackIndex) | |
console.log("Attacking point", to, "with army from", from) | |
this.socket.emit('attack', from, to, false, this.attackIndex) | |
this.attackIndex++ | |
} | |
Bot.prototype.printMap = function(map) { | |
for (var y = 0; y < map.length; y++) { | |
for (var x = 0; x < map[y].length; x++) { | |
var mapValue = map[y][x][0] | |
var mapType = map[y][x][1] | |
if (mapValue != 0) { | |
map[y][x] = this.colours[mapType]((mapValue + " ").substring(0, 4)) | |
} | |
else { | |
map[y][x] = this.colours[mapType]((this.character[mapType] + " ").substring(0, 4)) | |
} | |
} | |
console.log(map[y].join("")) | |
} | |
} | |
Bot.prototype.frontDistance = function(map) { | |
var frontDistance = [...Array(map.length).keys()].map(i => Array(map[0].length)) | |
for (var y = 0; y < map.length; y++) { | |
for (var x = 0; x < map[y].length; x++) { | |
var mapValue = map[y][x][0] | |
var mapType = map[y][x][1] | |
if (mapType == 'empty' || mapType == 'unknown' || mapType == 'enemy' || mapType == 'enemyGeneral') { | |
frontDistance[y][x] = 1 | |
} else if (mapType == 'friendly' || mapType == 'friendlyGeneral') { | |
frontDistance[y][x] = -1 | |
} else { | |
frontDistance[y][x] = -2 | |
} | |
} | |
} | |
var emptySquares = this.countValues(frontDistance, -1) | |
var counter = 1 | |
var more = true | |
while (emptySquares) { | |
for (var y = 0; y < map.length; y++) { | |
for (var x = 0; x < map[y].length; x++) { | |
if (frontDistance[y][x] == -1) { | |
// console.log("Found our square at: " + x + ", " + y) | |
var around = false | |
for (var i = 0; i < this.movementOptions.length; i++) { | |
var newCoords = [x + this.movementOptions[i][0], y + this.movementOptions[i][1]] | |
if (this.inBounds(newCoords[0], newCoords[1])) { | |
if (frontDistance[newCoords[1]][newCoords[0]] == counter) { | |
around = true | |
break | |
} | |
} | |
} | |
if (around) { | |
// console.log("Incrementing it to: " + (counter + 1)) | |
frontDistance[y][x] = counter + 1 | |
} | |
} | |
} | |
} | |
var emptySquares = this.countValues(frontDistance, -1) | |
if (counter > 100) { | |
emptySquares = 0 | |
more = false | |
} | |
counter++ | |
} | |
// console.log(frontDistance) | |
return [more, frontDistance] | |
} | |
Bot.prototype.findLowestHeight = function(frontDistance, map) { | |
lowestHeight = [9999, [-1, -1], [-1, -1]] | |
for (var y = 0; y < map.length; y++) { | |
for (var x = 0; x < map[y].length; x++) { | |
var mapValue = map[y][x][0] | |
var mapType = map[y][x][1] | |
if (mapValue > 1 && (mapType == "friendly" || mapType == "friendlyGeneral")) { | |
if (frontDistance[y][x] < lowestHeight[0]) { | |
var neighbour = [-1, -1] | |
for (var i = 0; i < this.movementOptions.length; i++) { | |
var newCoords = [x + this.movementOptions[i][0], y + this.movementOptions[i][1]] | |
if (this.inBounds(newCoords[0], newCoords[1])) { | |
// console.log(newCoords) | |
// console.log(frontDistance[newCoords[1]][newCoords[0]]) | |
if (frontDistance[newCoords[1]][newCoords[0]] == frontDistance[y][x] - 1) { | |
if (map[newCoords[1]][newCoords[0]][1] == "enemy" || map[newCoords[1]][newCoords[0]][1] == "enemyGeneral") { | |
if (map[y][x][0] - 1 > map[newCoords[1]][newCoords[0]][0]) { | |
// console.log("Setting Neighbour") | |
neighbour = newCoords | |
} | |
} else { | |
neighbour = newCoords | |
} | |
} | |
} | |
} | |
if (!this.arrayEquals(neighbour, [-1, -1])) { | |
lowestHeight = [frontDistance[y][x], [x, y], neighbour] | |
} | |
} | |
} | |
} | |
} | |
return lowestHeight | |
} | |
// TODO: IMPLEMENT | |
Bot.prototype.collectAround = function(x, y) { | |
console.log("Collecting around: " + x + ", " + y) | |
} | |
Bot.prototype.toPoint = function(x, y) { | |
return y * this.width + x | |
} | |
Bot.prototype.toXY = function(point) { | |
return [point % this.width, Math.floor(point / this.width)] | |
} | |
Bot.prototype.toGeneral = function(x, y) { | |
x = x - this.ourGeneral[0] | |
} | |
Bot.prototype.inBounds = function(x, y) { | |
if (x < 0 || y < 0 || x >= this.width || y >= this.height) { | |
return false | |
} | |
return true | |
} | |
Bot.prototype.randomID = function() { | |
return (Math.random().toString(36)+'00000000000000000').slice(2, 11) | |
} | |
Bot.prototype.randomName = function() { | |
return generate().spaced.replace(/\w\S*/g, function(x){return x.charAt(0).toUpperCase() + x.substr(1).toLowerCase()}) | |
} | |
Bot.prototype.add = function(a, b) { | |
return a + b | |
} | |
Bot.prototype.arrayEquals = function(a, b) { | |
if (a === b) return true | |
if (a == null || b == null) return false | |
if (a.length != b.length) return false | |
for (var i = 0; i < a.length; ++i) { | |
if (a[i] !== b[i]) return false | |
} | |
return true | |
} | |
Bot.prototype.countValues = function(array, value) { | |
return array.map(function(row) { | |
return row.reduce(function(n, val) { | |
return n + (val == value) | |
}, 0) | |
}).reduce(this.add, 0) | |
} | |
Bot.prototype.shuffle = function(array) { | |
var currentIndex = array.length, temporaryValue, randomIndex | |
while (0 !== currentIndex) { | |
randomIndex = Math.floor(Math.random() * currentIndex) | |
currentIndex -= 1 | |
temporaryValue = array[currentIndex] | |
array[currentIndex] = array[randomIndex] | |
array[randomIndex] = temporaryValue | |
} | |
return array | |
} | |
module.exports = new Bot() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment