Skip to content

Instantly share code, notes, and snippets.

@CyberShadow
Last active August 29, 2015 14:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CyberShadow/ab468eab7cd070864957 to your computer and use it in GitHub Desktop.
Save CyberShadow/ab468eab7cd070864957 to your computer and use it in GitHub Desktop.
lifecompetes.com bot
*.txt
*.exe
/trace/
import win32.winbase;
import std.algorithm;
import std.array;
import std.conv;
import std.datetime;
import std.parallelism;
import std.range;
import std.socket;
import std.stdio;
import std.string;
import common;
import input;
import net;
void main()
{
calibrate();
string serverAddress = File("serveraddr.txt").readln().strip();
bool isMain;
{
uint mainColor = File("mycolor.txt").readln().strip().to!uint(16);
Board board; uint myColor;
readBoard(board, myColor);
isMain = myColor == mainColor;
}
while(true)
try
{
writeln("Waiting..."); stdout.flush();
waitTurn(isMain ? 25 : 50);
Board board;
uint myColor;
writeln("Capturing..."); stdout.flush();
readBoard(board, myColor);
printBoard(board);
writefln("My color: %06X (%s)", myColor, isMain ? "main" : "helper");
if (canPlace())
{
writeln("Connecting..."); stdout.flush();
auto s = new TcpSocket(getAddress(serverAddress, PORT)[0]);
writeln("Sending..."); stdout.flush();
auto p = ClientPacket(board, myColor);
auto bytes = s.send((&p)[0..1]);
enforce(bytes == p.sizeof, "Too little data sent");
writeln("Waiting for reply..."); stdout.flush();
ServerPacket sp;
bytes = s.receive((&sp)[0..1]);
enforce(bytes == sp.sizeof, "Too little data received");
s.shutdown(SocketShutdown.BOTH);
s.close();
if (sp.x == 0 && sp.y == 0)
{
writeln("Server said to skip this turn.");
continue;
}
writefln("Clicking %d, %d...", sp.x, sp.y); stdout.flush();
clickCell(sp.x, sp.y);
Sleep(250);
submit();
}
else
writeln("Can't place this turn.");
}
catch (Exception e)
writeln(e);
}
diff --git a/public/js/app.js b/public/js/app.js
index a006ccd..303efbe 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -59,6 +59,7 @@ define(['core/game', 'renderer', 'gameclient', 'core/playermanager'], function(G
_this.renderer.updateLeaderboard();
_this.renderer.updatePlayersOnline();
_this.renderer.flashNews();
+ _this.askServer();
}
if (!_this.game.isBehindOnTicks()) {
@@ -114,12 +115,16 @@ define(['core/game', 'renderer', 'gameclient', 'core/playermanager'], function(G
};
App.prototype.setToken = function(token) {
- localStorage.setItem('token', token);
+ //localStorage.setItem('token', token);
+ document.location.hash = '#' + token;
return token;
};
App.prototype.getToken = function() {
- var token = localStorage.getItem('token');
+ //var token = localStorage.getItem('token');
+ var token = false;
+ if (document.location.hash.length > 1)
+ token = document.location.hash.substr(1);
return (token) ? token : false;
};
@@ -134,5 +139,38 @@ define(['core/game', 'renderer', 'gameclient', 'core/playermanager'], function(G
this.playerManager.updatePlayers(state.players);
};
+ App.prototype.askServer = function() {
+ try {
+ var player = this.playerManager.getLocalPlayer();
+ if ((player.cells - this.renderer.flaggedCells.length <= 0)) {
+ console.log('No cells to place this generation.');
+ return;
+ }
+ var s = JSON.stringify({cells:this.game.grid.getCells(), playerId:this.playerManager.getLocalPlayer().id});
+ var xmlhttp = new XMLHttpRequest();
+ var _this = this;
+ xmlhttp.onreadystatechange=function()
+ {
+ if (xmlhttp.readyState==4 && xmlhttp.status==200)
+ {
+ var reply = JSON.parse(xmlhttp.responseText);
+ if (reply.x == 0 && reply.y == 0) {
+ console.log('EMPTY reply from server');
+ return;
+ }
+ console.log('Clicking cell ', reply.x, ' ', reply.y);
+ var cell = _this.game.grid.getCell(reply.x, reply.y);
+ cell.setDirty();
+ _this.gameClient.placeLiveCells([cell]);
+ }
+ }
+ xmlhttp.open("POST","/myserver",true);
+ xmlhttp.send(s);
+ }
+ catch (e) {
+ console.log(e);
+ }
+ }
+
return App;
});
\ No newline at end of file
diff --git a/public/js/gameclient.js b/public/js/gameclient.js
index 75386e4..c988627 100644
--- a/public/js/gameclient.js
+++ b/public/js/gameclient.js
@@ -143,7 +143,7 @@ define(['socket.io'], function(io) {
this._requestState();
}
- this.hidden = document.hidden;
+ //this.hidden = document.hidden;
};
GameClient.prototype._requestState = function() {
import core.runtime;
import std.algorithm;
import std.array;
import std.datetime;
import std.path;
import std.stdio;
import std.string;
import ae.sys.file;
import ae.utils.text;
alias uint[W][H] Board;
enum W = 90;
enum H = 45;
int bx(int x) { return x.max(0).min(W-1); }
int by(int y) { return y.max(0).min(H-1); }
void simulate(ref in Board src, ref Board dst)
{
dst[] = src[];
foreach (int y; 0..H)
{
int j0 = by(y-1);
int j1 = by(y+1) + 1;
foreach (int x; 0..W)
{
int i0 = bx(x-1);
int i1 = bx(x+1) + 1;
int n;
static uint[8] colors;
foreach (j; j0..j1)
foreach (i; i0..i1)
{
if (i==x && j==y)
continue;
if (src[j][i])
colors[n++] = src[j][i];
}
if (src[y][x])
{
if (n < 2 || n > 3)
dst[y][x] = 0;
}
else
if (n == 3)
{
auto a = colors[0..n];
dst[y][x] = a[1]==a[2] ? a[1] : a[0];
}
}
}
}
void simulatePart(ref in Board src, ref Board dst, int cx, int cy, int r)
{
// r++;
int x0 = bx(cx - r);
int x1 = bx(cx + r);
int y0 = by(cy - r);
int y1 = by(cy + r);
foreach (int y; y0..y1)
{
int j0 = by(y-1);
int j1 = by(y+1) + 1;
foreach (int x; x0..x1)
{
int i0 = bx(x-1);
int i1 = bx(x+1) + 1;
int n = 0;
static uint[8] colors;
foreach (j; j0..j1)
foreach (i; i0..i1)
{
if (i==x && j==y)
continue;
if (src[j][i])
colors[n++] = src[j][i];
}
if (src[y][x])
{
if (n < 2 || n > 3)
dst[y][x] = 0;
else
dst[y][x] = src[y][x];
}
else
{
if (n == 3)
{
auto a = colors[0..n];
dst[y][x] = a[1]==a[2] ? a[1] : a[0];
}
else
dst[y][x] = 0;
}
}
}
}
enum TURNS = 40;
alias Forecast = Board[TURNS];
void createForecast(in ref Board src, ref Forecast dst)
{
dst[0] = src;
foreach (n; 1..TURNS)
simulate(dst[n-1], dst[n]);
}
void simulatePlace(in ref Forecast src, ref Forecast dst, int x, int y, uint color)
{
dst = src;
dst[0][y][x] = color;
foreach (n; 1..TURNS)
simulatePart(dst[n-1], dst[n], x, y, n);
}
void printBoard(ref Board board, File f = stdout)
{
auto alphabet = "!@#$%^&*+=-<>:;ABCDEFGHIJKLMNOPQRSTUVWXYZ";
size_t[uint] aa;
foreach (int y; 0..H)
{
foreach (int x; 0..W)
{
auto c = board[y][x];
if (!c)
f.write(" ");
else
if (c & 0xFF000000)
f.write(cast(char)('0' + (c & ~0xFF000000)));
else
f.write(alphabet[c%$]);
}
f.writeln();
}
}
immutable static string instance;
shared static this() { instance = randomString(); }
void saveForecast(ref Forecast forecast, string name, SysTime t)
{
auto fn = "trace/%s-%s/%s/%s.txt".format(Runtime.args[0].baseName().stripExtension(), instance, t.toUnixTime(), name);
ensurePathExists(fn);
auto f = File(fn, "w");
foreach (ref board; forecast)
{
printBoard(board, f);
f.writeln("-".replicate(W));
}
}
uint count(ref Board board, uint color)
{
int result;
foreach (int y; 0..H)
foreach (int x; 0..W)
if (board[y][x] == color)
result++;
return result;
}
import std.algorithm;
import std.array;
import std.conv;
import std.datetime;
import std.parallelism;
import std.range;
import std.stdio;
import std.string;
import ae.net.asockets;
import ae.net.http.responseex;
import ae.net.http.server;
import ae.utils.json;
import common;
enum MAX_CLIENTS_PER_TURN = 3;
struct JsonRequest
{
JsonCell[] cells;
int playerId;
}
struct JsonCell
{
int x, y;
bool dirty;
bool alive = false;
int playerId;
}
struct JsonReply { int x, y; }
void main()
{
uint mainId = File("myid.txt").readln().strip().to!uint();
SysTime firstPacketTime;
Forecast forecast;
uint clientNumber;
auto s = new HttpServer;
s.handleRequest = (HttpRequest request, HttpServerConnection conn) {
string post = cast(string)request.data.joinToHeap();
auto r = jsonParse!JsonRequest(post);
writefln("Got request from player %s (%s).", r.playerId, r.playerId == mainId ? "main" : "helper"); stdout.flush();
Board board;
uint[] boardArr = cast(uint[])(board[]);
foreach (n, ref cell; r.cells)
boardArr[n] = cell.alive ? cell.playerId : 0;
scope(exit) clientNumber++;
auto now = Clock.currTime();
if (firstPacketTime < now - 4.seconds)
{
printBoard(board);
auto t = Clock.currTime();
writeln("Thinking..."); stdout.flush();
createForecast(board, forecast);
saveForecast(forecast, "game", t);
uint[] counts = forecast[].map!(b => count(b, mainId)).array();
writefln("Current: [%(%3d, %)]", counts);
firstPacketTime = now;
clientNumber = 0;
}
JsonReply reply;
if (clientNumber >= MAX_CLIENTS_PER_TURN)
{
writefln("Sending EMPTY reply to client %d (%s).", clientNumber, r.playerId == mainId ? "main" : "helper"); stdout.flush();
reply = JsonReply(0, 0);
}
else
{
static struct Result { int points, x, y; }
Result bestResult;
foreach (int y; H.iota.parallel)
{
Result bestRowResult;
foreach (int x; 0..W)
{
if (forecast[0][y][x])
continue;
static Forecast newForecast;
simulatePlace(forecast, newForecast, x, y, r.playerId);
//auto r = count(newForecast[$-1]);
int m = 0, t = 0;
foreach (ref newBoard; newForecast)
{
auto c = count(newBoard, mainId);
t += c;
m = max(m, c);
}
auto r = t;
if (m >= 1000)
r += 100000;
//auto r = newForecast[].map!count.reduce!"a+b"();
if (bestRowResult.points < r)
bestRowResult = Result(r, x, y);
}
synchronized
if (bestResult.points < bestRowResult.points)
bestResult = bestRowResult;
}
//if (bestResult.x == 0 && bestResult.y == 0)
// continue; // failsafe
static Forecast bestForecast;
simulatePlace(forecast, bestForecast, bestResult.x, bestResult.y, r.playerId);
forecast = bestForecast; // for next client
uint[] bestCounts = bestForecast[].map!(b => count(b, mainId)).array();
writefln("%2d, %2d : [%(%3d, %)] (%d)", bestResult.x, bestResult.y, bestCounts, bestResult.points);
saveForecast(forecast, "my-%d".format(clientNumber), now);
writefln("Sending reply to client %d (%s)...", clientNumber, r.playerId == mainId ? "main" : "helper"); stdout.flush();
reply = JsonReply(bestResult.x, bestResult.y);
}
auto response = new HttpResponseEx;
conn.sendResponse(response.serveJson(reply));
writeln("Sent reply: ", reply.toJson());
};
s.listen(55555);
socketManager.loop();
}
import std.algorithm;
import std.array;
import std.exception;
import std.stdio;
import win32.winbase;
import win32.winuser;
import ae.sys.windows.input;
import ae.utils.graphics.color;
import ae.utils.graphics.gdi;
import common;
uint convertColor(BGRX c)
{
return (c.r * 0x10000) | (c.g * 0x100) | (c.b);
}
auto capture()
{
enum WH = 2048;
auto canvas = GDICanvas!BGRX(WH, WH);
auto ddc = GetDC(null);
canvas.BitBlt(0, 0, WH, WH, ddc, 0, 0, SRCCOPY);
ReleaseDC(null, ddc);
return canvas;
}
int x0, y0;
void calibrate()
{
auto canvas = capture();
BGRX white = BGRX(255, 255, 255);
BGRX black = BGRX(0, 0, 0);
BGRX[] searchPattern = white ~ [black].replicate(W*S + 1) ~ white;
auto pixelArr = cast(uint[])canvas.pixels[0..canvas.w*canvas.h];
foreach (ref c; pixelArr)
c &= 0x00FFFFFF;
auto patternArr = cast(uint[])searchPattern;
auto p = pixelArr.countUntil(patternArr);
enforce(p >= 0, "Can't find game");
x0 = p % canvas.w + 1;
y0 = p / canvas.w;
//writeln(x0, " ", y0);
}
void waitTurn(int t=25)
{
auto ddc = GetDC(null);
scope(exit) ReleaseDC(null, ddc);
writeln(" Waiting for nonblank..."); stdout.flush();
while ((ddc.GetPixel(CX-t, CY) & 0xFFFFFF) == 0xFFFFFF) Sleep(10);
writeln(" Waiting for blank..."); stdout.flush();
while ((ddc.GetPixel(CX-t, CY) & 0xFFFFFF) != 0xFFFFFF) Sleep(10);
writeln(" Waiting for nonblank..."); stdout.flush();
while ((ddc.GetPixel(CX-t, CY) & 0xFFFFFF) == 0xFFFFFF) Sleep(10);
}
void readBoard(ref Board board, out uint myColor)
{
auto canvas = capture();
foreach (y; 0..H)
foreach (x; 0..W)
{
auto n = convertColor(canvas[X0 + x*S + 1, Y0 + y*S + 1]);
if (n == 0xFFFFFF)
n = 0;
board[y][x] = n;
}
myColor = convertColor(canvas[CX, CY]);
}
enum S = 10;
//enum X0 = 62;
//enum Y0 = 152;
@property int X0() { return x0; }
@property int Y0() { return y0; }
@property int CX() { return (X0 + (X0+W*S)) / 2; }
@property int CY() { return Y0 - 8; }
void clickCell(int x, int y)
{
click(X0 + x*S + 5, Y0 + y*S + 5);
}
void click(int x, int y)
{
SetCursorPos(x, y);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP , 0, 0, 0, 0);
}
int refreshCounter;
enum REFRESH_INTERVAL = 12;
bool canPlace()
{
int x = 0, y = 0;
SetCursorPos(X0 + x*S + 5, Y0 + y*S + 5);
Sleep(50);
auto ddc = GetDC(null);
scope(exit) ReleaseDC(null, ddc);
bool result = ddc.GetPixel(X0 + x*S + 1, Y0 + y*S + 1) != ddc.GetPixel(X0 + x*S + 5, Y0 + y*S + 5);
SetCursorPos(CX, CY);
return result;
}
unittest
{
calibrate();
Board b; uint myColor;
readBoard(b, myColor);
assert(canPlace());
}
void submit()
{
click(CX, Y0 + H*S + 25);
if (refreshCounter++ % REFRESH_INTERVAL == 0)
{
Sleep(500); // Let the packet go through
press(VK_F5);
Sleep(500); // Wait for page to load
}
}
import common;
enum PORT = 55555;
struct ClientPacket
{
Board board;
uint myColor;
}
struct ServerPacket
{
int x, y;
}
import std.algorithm;
import std.array;
import std.conv;
import std.datetime;
import std.parallelism;
import std.range;
import std.socket;
import std.stdio;
import std.string;
import common;
import net;
enum MAX_CLIENTS_PER_TURN = 1;
void main()
{
auto l = new TcpSocket();
l.bind(getAddress("0.0.0.0", PORT)[0]);
l.listen(50);
uint mainColor = File("mycolor.txt").readln().strip().to!uint(16);
SysTime firstPacketTime;
Forecast forecast;
uint clientNumber;
while (true)
try
{
writeln("Waiting..."); stdout.flush();
auto s = l.accept();
scope(exit) s.close();
scope(exit) clientNumber++;
writeln("Receiving..."); stdout.flush();
ClientPacket p;
auto bytes = s.receive((&p)[0..1]);
enforce(bytes == p.sizeof, "Too little data received");
auto now = Clock.currTime();
if (firstPacketTime < now - 4.seconds)
{
printBoard(p.board);
auto t = Clock.currTime();
writeln("Thinking..."); stdout.flush();
createForecast(p.board, forecast);
saveForecast(forecast, "game", t);
uint[] counts = forecast[].map!(b => count(b, mainColor)).array();
writefln("Current: [%(%3d, %)]", counts);
firstPacketTime = now;
clientNumber = 0;
}
ServerPacket sp;
if (clientNumber >= MAX_CLIENTS_PER_TURN)
{
writefln("Sending EMPTY reply to client %d (%s).", clientNumber, p.myColor == mainColor ? "main" : "helper"); stdout.flush();
sp = ServerPacket(0, 0);
}
else
{
static struct Result { int points, x, y; }
Result bestResult;
foreach (int y; H.iota.parallel)
{
Result bestRowResult;
foreach (int x; 0..W)
{
if (forecast[0][y][x])
continue;
static Forecast newForecast;
simulatePlace(forecast, newForecast, x, y, p.myColor);
//auto r = count(newForecast[$-1]);
int r;
foreach (ref newBoard; newForecast)
r += count(newBoard, mainColor);
//auto r = newForecast[].map!count.reduce!"a+b"();
if (bestRowResult.points < r)
bestRowResult = Result(r, x, y);
}
synchronized
if (bestResult.points < bestRowResult.points)
bestResult = bestRowResult;
}
//if (bestResult.x == 0 && bestResult.y == 0)
// continue; // failsafe
static Forecast bestForecast;
simulatePlace(forecast, bestForecast, bestResult.x, bestResult.y, p.myColor);
forecast = bestForecast; // for next client
uint[] bestCounts = bestForecast[].map!(b => count(b, mainColor)).array();
writefln("%2d, %2d : [%(%3d, %)] (%d)", bestResult.x, bestResult.y, bestCounts, bestResult.points);
saveForecast(forecast, "my-%d".format(clientNumber), now);
writefln("Sending reply to client %d (%s)...", clientNumber, p.myColor == mainColor ? "main" : "helper"); stdout.flush();
sp = ServerPacket(bestResult.x, bestResult.y);
}
bytes = s.send((&sp)[0..1]);
enforce(bytes == sp.sizeof, "Too little data sent");
s.shutdown(SocketShutdown.BOTH);
}
catch (Exception e)
writeln(e);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment