Created
January 29, 2017 00:12
-
-
Save popey456963/fa8607b414b42a7060a06330654ceb1a to your computer and use it in GitHub Desktop.
JavaScript Wrapper
This file contains hidden or 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