1 module vindinium.comms; 2 3 /** 4 * Server communications module 5 */ 6 7 private { 8 import vindinium; 9 import stdx.data.json; 10 11 import std.net.curl; 12 import std.string; 13 import std.stdio; 14 import std.exception; 15 } 16 17 enum Flags { 18 Get = 0x1, 19 Set = 0x2, 20 Both = 0x3 21 } 22 23 struct Vindinium { 24 /// Game modes 25 enum Mode { 26 Training, 27 Arena 28 } 29 30 /// The AI's private API key 31 string key; 32 33 /// Server to play the game on 34 const string server; 35 36 /// Mode that the hero is playing in 37 Mode mode; 38 39 /// Number of turns to play the game 40 uint turns; 41 42 /// Name of the map to play: "m{1..6}" 43 string map; 44 45 // Connection shared between game instances 46 private HTTP conn; 47 48 this(string key, string server, Mode mode, uint turns, string map) { 49 this.conn = HTTP(); 50 this.key = key; 51 this.server = server; 52 this.mode = mode; 53 this.turns = turns; 54 this.map = map; 55 56 conn.addRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 57 conn.setUserAgent("Vindinium-D-Client/0.0.1"); 58 } 59 60 VindiniumGame connect() { 61 string uri; 62 final switch(mode) 63 with(Mode) { 64 case Training: 65 uri = server ~ "/api/training"; 66 break; 67 68 case Arena: 69 uri = server ~ "/api/arena"; 70 break; 71 } 72 73 string post_data = format("key=%s&turns=%s&map=%s", key, turns, map); 74 string response = post(uri, post_data, conn).assumeUnique; 75 76 return VindiniumGame(conn, key, response); 77 } 78 } 79 80 struct VindiniumGame { 81 82 /// Commands that the hero can be issued 83 enum Command { 84 Stay, 85 North, 86 South, 87 East, 88 West 89 } 90 91 private { 92 HTTP conn; 93 string key; 94 GameResponse *gr; 95 } 96 97 package 98 this(ref HTTP conn, string key, string initial_game) { 99 this.conn = conn; 100 this.key = key; 101 this.gr = new GameResponse(); 102 103 parse_response(initial_game); 104 } 105 106 // delegate to gameresponse 107 string play_url() @property { return gr.play_url; } 108 string view_url() @property { return gr.view_url; } 109 bool finished() @property { return gr.game.finished; } 110 uint turn() @property { return gr.game.turn; } 111 112 auto state() @property const { return gr; } 113 114 void send_command(Command cmd) 115 in { assert(!finished); } 116 body { 117 string cmd_str; 118 final switch(cmd) 119 with(Command) { 120 case Stay: cmd_str = "Stay"; break; 121 case North: cmd_str = "North"; break; 122 case South: cmd_str = "South"; break; 123 case East: cmd_str = "East"; break; 124 case West: cmd_str = "West"; break; 125 } 126 127 auto post_data = format("key=%s&dir=%s", key, cmd_str); 128 string response = post(play_url, post_data, conn).assumeUnique; 129 130 // TODO: merge changes instead of overwriting the game response 131 parse_response(response); 132 } 133 134 private void parse_response(string resp) { 135 auto json = parseJSONValue(resp); 136 gr.update_from_json(json); 137 } 138 }