Created
January 29, 2017 00:12
-
-
Save popey456963/fa8607b414b42a7060a06330654ceb1a to your computer and use it in GitHub Desktop.
Revisions
-
popey456963 created this gist
Jan 29, 2017 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,397 @@ 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()