main.vala 5.42 KB
Newer Older
1 2 3 4 5
/*
 * A sample bot.
 */


6
public class Bot : OVCCClient.Client
7
{
8 9
  private MainLoop      loop      = null;
  private OVCC.SigQueue sigqueue  = new OVCC.SigQueue ();
10
  
11
  public async bool join (OVCCClient.Server server)
12
    throws Error
13
  {
Colomban Wendling's avatar
Colomban Wendling committed
14
    uint player_suffix = 7;
15

16
    /* connect to the server */
17
    yield bind_to (server);
18 19 20

    /* login to the server, choosing an available nickname */
    debug ("Trying to login...");
Colomban Wendling's avatar
Colomban Wendling committed
21
    while (true) {
22
      try {
23
        yield login ("""Clever bot %03u""".printf (player_suffix));
24
        break;
25
      } catch (OVCCClient.ServerError.NICKNAME_IN_USE e1) {
26
        player_suffix++;
27
      } catch (OVCCClient.ServerError.MISSING_AUTHENTICATION e2) {
28
        leave ();
29 30
        throw e2; /* avoid infinite loop */
      } catch (Error e3) {
31
        leave ();
32
        throw e3;
33 34
      }
    }
35 36
    debug ("Logged in with player_suffix = %u", player_suffix);

37
    /* join any open table */
38
    debug ("Trying to join a table...");
39
    try {
40
      yield join_table (-1);
41
    } catch (Error e4) {
42
      leave ();
43
      throw e4;
44 45
    }
    debug ("Joined");
46

47
    /* react on game state changes */
48
    sigqueue.add (game, game.notify["state"].connect ((s, p) => {
Colomban Wendling's avatar
Colomban Wendling committed
49
      switch (((OVCC.Game)s).state) {
50 51 52
        case OVCC.GameState.STARTED:
          debug ("Game started!");
          break;
53
        case OVCC.GameState.FINISHED:
54 55 56 57 58
          try {
            leave ();
          } catch (Error e) {
            warning ("Could not leave: %s", e.message);
          }
59 60 61
          debug ("We're done, bye!");
          break;
        case OVCC.GameState.ABORTED:
62 63 64 65 66
          try {
            leave ();
          } catch (Error e) {
            warning ("Could not leave: %s", e.message);
          }
67 68 69
          debug ("Abnormal game termination!");
          break;
      }
70
    }));
71
    /* we should place a tile? OK, why not */
72
    sigqueue.add (this, place_tile.connect ((tile) => {
73
      debug ("Seems we should place a tile...");
74
      game.board.foreach ((b, p, t) => {
75 76 77 78 79 80 81 82 83 84 85
        for (var i = 0; i < 4; i++) {
          var npos = p;
          
          switch (i) {
            case 0: npos.y--; break; /* top */
            case 1: npos.x++; break; /* right */
            case 2: npos.y++; break; /* bottom */
            case 3: npos.x--; break; /* left */
          }
          for (var j = 0; j < 4; j++) {
            /* FIXME: this should probably be asynchronous... */
86
            if (player.place_tile (npos)) {
Jonathan Michalon's avatar
Jonathan Michalon committed
87 88
              debug ("Placed tile ID %u at %d %d angle %u", tile.id,
                     npos.x, npos.y, tile.rotation);
89 90 91 92 93 94 95 96
              return false;
            } else {
              tile.rotate (1);
            }
          }
        }
        return true;
      });
97
    }));
98
    /* we should place a pawn? let's do so */
Colomban Wendling's avatar
Colomban Wendling committed
99
    sigqueue.add (this, place_pawn.connect ((pos) => {
100
      debug ("We're asked to place a pawn!");
Colomban Wendling's avatar
Colomban Wendling committed
101 102 103 104 105
      var tile = game.board.get_tile (pos);
      if (tile == null) {
        critical ("We were asked to place a pawn somewhere there is no tile");
        return;
      }
106
      foreach (var o in tile.objects) {
Colomban Wendling's avatar
Colomban Wendling committed
107 108 109 110
        if (player.place_pawn (OVCC.PawnKind.NORMAL, o, pos)) {
          debug ("Placed pawn at %d %d", pos.x, pos.y);
          break;
        }
111 112 113
        /* we guess all pawns can go anywhere another can -- which isn't true
         * using some extensions, but it doesn't matter that much. */
        /* FIXME: this should probably also be asynchronous... */
114 115 116
//         if (game.place_pawn (player.pawns.nth_data (0), o)) {
//           break;
//         }
117
      }
118
      game.turn_finished ();
119
    }));
120

121

122
    return true;
123
  }
124

125 126 127 128 129
  public void play ()
    throws OVCC.GameError
  {
    debug ("Requesting game start");
    try {
130
      game.start();
131
    } catch (OVCC.GameError.STARTED e) {
132
      warning ("Cannot start game: %s", e.message);
133 134 135
    }
  }

136
  public new void leave ()
137
    throws OVCCClient.ServerError
138
  {
139 140
    sigqueue.remove_all ();
    
141
    base.leave ();
142 143
    loop.quit ();
  }
144 145 146 147 148
  
  public Bot (MainLoop l)
  {
    loop = l;
  }
149 150
}

151 152 153 154 155 156

#if HAVE_POSIX
private static void signal_handler (int sig)
{
  debug ("Caught signal %d, exiting", sig);
  try {
157
    bot.leave ();
158
  } catch (Error e) {
159
    warning ("Error leaving from server: %s", e.message);
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  }
  Posix.exit (2);
}

private static void setup_signal_handlers ()
{
  Posix.sigaction_t s = {};
  s.sa_handler = signal_handler;
  Posix.sigemptyset (s.sa_mask);
  s.sa_flags = 0;
  
  Posix.sigaction (Posix.SIGQUIT, s, null);
  Posix.sigaction (Posix.SIGTERM, s, null);
  Posix.sigaction (Posix.SIGINT, s, null);
}
#endif


Colomban Wendling's avatar
Colomban Wendling committed
178
Bot bot = null;
179

180
public int main (string[] args)
181
{
182 183 184 185 186 187 188 189 190 191
  var     host = "localhost";
  uint16  port = 0xdead;
  
  if (args.length > 1) {
    host = args[1];
  }
  if (args.length > 2) {
    port = (uint16)int.parse (args[2]);
  }
  
Colomban Wendling's avatar
Colomban Wendling committed
192 193
  var loop = new MainLoop ();
  var server = new OVCCClient.Server (host, port);
194 195 196 197 198
  bot = new Bot (loop);
  
#if HAVE_POSIX
  setup_signal_handlers ();
#endif
199 200 201 202 203 204 205 206 207 208 209 210 211

  bot.join.begin (server, (o, r) => {
    try {
      bot.join.end (r);
      /* wait to let others join */
      Timeout.add_seconds (5, () => {
        if (bot.game.state != OVCC.GameState.STARTED) {
          debug ("let the show begin!");
          try {
            bot.play ();
          } catch (Error e) {
            warning ("Failed to start playing: %s", e.message);
          }
212
        }
213 214 215 216 217 218 219 220
        return false;
      });
    } catch (Error e) {
      warning ("Failed to join on the server: %s", e.message);
      loop.quit ();
    }
  });
  loop.run ();
221 222

  return 0;
223
}