CS4444 Project 1 Report (Group 5)

Hanhua Feng (hanhua@cs.columbia.edu)
Miqdad Mohammed (mm1723@columbia.edu)
Alex Nicksay (adn24@columbia.edu)
David Vespe (djv@columbia.edu)

Strategies

Our group decided to focus on developing constructive strategies, which are enumerated as follows:

The "Cavalry" Players

Early-Game

Basics

As stated above, the strategy of our first player, "Annealing Cavalry", began as a blind strategy, before the anti-chaser strategy was added. It never called functions like allRobots(), colors(), or filled(). Robots always follow fixed trajectories (except for some initial randomness).

As defined by the dictionary program WordWeb 1.63:

Cavalry
  1. Troops trained to fight on horseback.
  2. A highly mobile army unit.

As indicated by the name, the basic idea of the "Cavalry" strategy came from the "Army" strategy. Robots sweep the board with certain distances between them, and after certain steps they move together to enclose areas that they have swept. The following figure illustrates the Cavalry strategy:

In the "Annealing Cavalry", the moves of robots looks like this:

In the "Royal Cavalry", the implementation is more general. The distances between a pair of consecutive robots can be different to each other, which are pre-defined at the begining of this mission. (See the program architecture for missions.) During the game, one or more chased robots may be dropped from the cavalry while other robots can still continue the cavalry mission.

The "Royal Cavalry" switches between two stages: advancing and enclosing. At the advacing stage, all robots keep in a row, sweep the screen in a same pace. At the enclosing stage robots make up a line from the left-most robot to the right-most robot in order to get some scores.

Adaptiveness

The core adaptive quality is determined by a question: How many steps should the cavalry advance between two enclosing stages?

In the "Annealing Cavalry", it is determined by the width between two adjacent robots, which is in turn determined by the board size and the number of robots. However, in "Royal Cavalry", robot movement is more intelligent (i.e. it is more adaptive). At the start of the mission, we pre-define four possible values for the number of advancing steps between two "enclosing" stages:

minimumthe minimum allowed
standardthe number if danger is detected
extendedthe number if there is no apparent danger
maximumthe maximum allowed

Damage detection After advancing for at least the minimum distance, if the program finds the start line or one of the two side lines are damaged by other robots, it switches to the enclosing stage immediately.

Danger detection If the robots have advanced for at least the standard distance, and the program found the start line is in danger, it would be ready to switch to the enclosing stage. Otherwise, the robots must advance for at least the extended distance before considering switching to the enclosing stage. The program checks the location of the nearby robots and their last move, and use an algorithm to compute the "danger" value.

Area Maximization

If the "Royal Cavalry" is ready to switch to the enclosing stage, it might not switch immediately. Instead, it will find a best enclosing line. The current algorithm makes use of the number of black squares in a line. If a line contains no black squares, it could be the best enclosing line. Otherwise, the line's value deteriorates with increasing numbers of black squares.

We are not satified with this algorithm of finding the best enclosing location. There are better algorithms to find the best enclosing location (e.g. calculating gain versus cost or gain versus risk), but we did not have time to implement them.

Damage Repair

Once in the enclosing stage, if the start line or one of the two side lines are damaged, the nearest robots in the cavalry will go back to repair the line, if it can be done in pre-configured steps. The other robots will continue to make the enclosing line without them. Some robots may also abandon the cavalry because they are being chased, and other robots can still finish the mission. (Note: the cavalry will never dismiss robots, though the rect mission may, as seen below.) In order to fill a line with any number of robots, we developed an algorithm to find the optimal solution. The following figure illustrates a scenario in which one robot tries to repair a line while others are enclosing:

Deadlines

In such cooperative strategies, synchronization is a significant problem. Other robots may stay stationary while waiting for one robot to finish its work. In order not to slow down the progress very much, we give deadlines for enclosing or repairing work (as also in other missions and quests). We also planned to give a deadline to the entire cavalry mission so that robots may directly match to the end of the line and enclose there, while the deadline is approaching, though we did not have time to implement that feature.

Tuning Parameters

Given the limited time available for this project, we could not implement everything that we have planned. Therefore, we were not able to tune parameters such as distances, thresholds, and the like.

End-Game

Basics

The end-game strategy in the "Annealing Cavalry" is quite simple: the distance between two adjacent robots will be decremented after a complete scan of the board. After several turns it will completely transform into an "Army" strategy. The "Army" strategy, in turn, is probably one of the best end-game blind strategies, because of its consistency in collecting small squares at the end of the game. The "Army" Strategy is a known quantity, so we will focus on the end-game strategy that the "Royal Cavalry" adopted, "Rectmania".

This was the work done in last 24 hours before due, and we are glad to see it works at least as well as previous end-game strategies. We found that most end-game strategies are comprised of a similar objective: to search for rectangles and to paint them. Thus, it is not surprising that we noted a few of of both this and last year's groups have a similar behavior, although we did not have enough time to analyze those programs to discover the exact differences.

Searching for Rectangles

There are plenty ways to search for available rectangles. Some can be found in the mediator program, in programs from the previous class, and in the players of other groups. We tried to find the best method by concentrating on being as efficient as possible. We divided rectangles into two classes: those that contain black squares and those that do not. Clearly, the former has a higher average profit-to-cost-ratio. Therefore, we first search for the largest rectangles in the first class that can be completed efficiently, and only if we find none, we search for those of the second class. Please consult the algorithm section below for details.

Completing Rectangles

We used an algorithm based on Abhinav's algorithm posted on the web-board. Much is the same, though a few minor details are different. The algorithm is discussed below.

Anti-chaser strategies

Robots in most of the programs will stop moving if they are chased, and "Annealing Cavlary" is no exception. However, in "Royal Cavalry", the robots will move randomly on squares which are neither white nor in their own color.

Our Reasoning

Strategies can always be improved — one can always tune and combine existing strategies, improve the effectiveness of simple or complex strategies, or just gain experience. What one actually does, then, must be based on one's objective. Our goal was always to explore new ideas and methods of implementation. So, we continued to develop the various forms of the "Cavalry" strategy, despite the fact it did not necessarily produce the "best" results. Interestingly, the more-advanced "Royal Cavalry" can lose to the "Annealing Cavalry" because the adaptive qualities hinders the pace of the robots.

Application of Algorithms

Moving to a Specified Cell

When a robot is switching tasks, it might move from one place to the other. However in a rectangular grid, usually we have many paths to do that. So, it is possible to find a path that "destroys" more of the opponent-colored squares than others. This is an optimization problem: the evaluation function being the sum of all benefits that the robot go though a square. In our program the benefit that a robot go through a quare are defined to be the owner's current score of the square's color. If a robot goes through a black square, it gets no profit, and if a robot goes through a square in its own color, it gets only one point of benifit. The algorithm do not necessarily check all possible paths. (The number of paths is exponential to the distance!) It is actually a simple dynamic-programming problem, and can be done in O(b2), where b is the maximum of the differences of x-coordinates and y-coordinates between the current position and the destination position.

Searching for Rectangles Containing No Black Squares

  1. Make a new matrix with the contents of the filled() matrix, in which black squares are represented by true, and others by false.
  2. Dilate the matrix – check every square and its adjacent eight squares. If any one of the nine squares is black, then set the square to black. The outside of the board is considered black, so mark periphery square to be black.
  3. Scan the matrix for a non-black square.
  4. Expand the non-black square to non-black rectangles towards the right and bottom, alternately, until it is not expandable on either direction (i.e., there are black squares). Record this rectangle.
  5. Set the rectangle and its immediate right and bottom line to black. This operation will keep rectangles found from crossing with each other.
  6. Repeat steps 3 to 5 until no non-black square can be found or a maximum number is reached.
  7. Expand the recorded rectangles toward outside (another dilate operation) by one unit, and return this rectangles.

This algorithm is clearly O(n2) where n is the board size.

Searching for Rectangles Containing Black Squares

(Note: For this algorithm, it is important to assume that all black holes are rectangles.

  1. Get the filled() matrix, and invert it (logically "not" every element).
  2. Find all black holes by the previous algorithm and dilate it by one unit.
  3. Check whether these rectangles can be expand towards top or left by one unit. If so, do expansion and black the inner squares of this rectangle.
  4. For each rectangle found, try to expand toward right and bottom, check for the these conditions

Since the number of black holes is usually much less than n2, and with the early termination conditions, its reasonable to estimate the mean running time is within the order of n2.

Completing a Line

The problem of making up a line is generalized. Suppose we have d robots and a line to be painted. Each robot has an insertion point (its current position) and an extraction point (the place to go after the mission). Without loss of generality, we suppose the line is horizontally placed, with two end-points being (x0,y) and (xn,y). We also suppose that each of the robot is responsible for a segment of the line, because, if a robot can do two segments, it can do the minimum super segment of the two segements with the same cost.) It's also reasonable to assume that the nearest square to the robot is in the segement, if the robot actually has a segment to be responsible for. The following figure illustrates this scenario.

Then our algorithm will do:

We found that, if we just use the maximum costs for all robots as the evalution value, the hill-climbing algorithm would easily reach a shoulder point. Then we changed the evaluation function to be in a format of A.B, where A is the previous maximum costs for all robots, and .B is 0.0001 multiplied by the sum of the costs of all robots. This change would not affect the optimal solution of the problem, but it will make hill-climbing much more effective. This kind of problem should be very general in the optimization research, so naturally we guess that it must have been invented and used in many problems.

Completing a Rectangle

This algorithm originated in Abhinav Kamra's post to the class web board. We added a few modifications and implementation details.

  1. Create a priority queue (it has a alternative name of "heap"). This is very important to the efficiency of this algorithm.
  2. For all pairs of (r,s), where r is a robot and s is an unpainted square (Mathematically it is the Cartesian product of the robot vector and square vector), compute the cost (number of steps) that robot r moving from the insertion point to square s then to its extraction point. Ignore already painted squares.
  3. Enqueue all these pairs to the priority queue.
  4. Dequeue the pair which has a minimum cost. (This operation has a running time of O(log m), where m is the number of element in the priority queue.)
  5. Suppose the pair is (r,s), if no square has not been assigned to robot r, assign square s to be the destination square of robot r, and call the robot moving algorithm mentioned before to computer the next move of robot r.
  6. Remove all pairs containing square s from the priority queue.
  7. For each of the remaining square, say s', update the cost of (r,s') in the priority queue to be the cost of (r,s), plus the sum of the manhattan distance between s and s' and the manhattan distance between s' and the extraction point of robot r. According to the triangle principle, this cost increases.
  8. Repeat steps 4-7, until either the queue is empty, or all robots has been assigned a square.
  9. Dismiss from the mission all robots who have not been assigned a square.

The running time of this algorithm is O(dm log(dm)), where d is the number of robots, and m is the number of unpainted squares. In the "Royal Cavalry" the extraction points are not implemented because they are not necessary.

Almost O(bn2) Response Time

All the previous algorithm are expected to be efficient. We think our program has an almost O(bn2) response time, where b is the number of robots, and n is the board size.

Details of Implementation

Programming architecture

We implemented a task model for the "Cavalry" players. Each task can be initialized at any time and ends later, either actively or passively, and robots may be dynamically added or deleted from the task, either actively or passively. There are two kinds of tasks: tasks that can be accomplished by multiple robots, called missions, and tasks that can only be done by one robots, called quests.

The following figure is the state transmition diagram of robots in the "Royal Cavalry" which adopted this task model. We shall not describe this verbosely, please read the comments in the program if one is interested.

Another aspect we want to mention is that we implemented a "re-orientation mechanism". Using this mechanism, the board can be rotated, mirrored left-right, flipped top-bottom, x-y transposed, and transformed by any combinations of these operations (to make a total of eight combinations). Algorithms can be applied the virtual transformed board, so that we can easily implement orienation-sensitive strategy (such as the Cavalry) along any direction.

Program terminology

We used different terms while programming "Royal Cavalry". These terms helped name the classes, and the difference of terminology was seen as a preventative measure to help avoid namespace clashes. They are:

Observations

Here we itemize what we saw when we were debugging and testing our program. Some of these observations may be only related to the mediator program.

Other Approaches and Code

The G5 Package

An initial goal of ours was to build a package of classes that could be easily used (and re-used) in the development of players. The diagram below shows the basic structure of the so-called "G5 Package", excluding sub-classes, in a hierarchical format. The oval shapes represent classes we considered to be "primitive" objects, meaning the building blocks of any program. The rectangle shapes represent classes we consider to be "complex" objects, meaning those that utilized instances of primitives in order to achieve an over-arching goal.

The package did prove to be a boon for development of complicated strategies and players, providing a level of abstraction not found in the game engine's interface. Furthermore, the modularity of the classes made it possible to dynamically and hierarchically combine different strategies, either sequentially or simultaneously. However, in retrospect, the cost (i.e. time spent) of initially developing the package was too high, and prevented us from submitting more of our ideas and players – we just didn't have time to complete the players. Below, we detail some of the work we did that we did not use in final players we submitted.

Task-Based Approach

Basics

A task, for the purpose of the project, is distinct unit of work that will make the player better off score-wise if completed. One or more robots may be assigned to a given task. A task is not necessarily constructive; it may involve trying to prevent another player from getting points. This concept is an extension of last year's group 8's concept of men on mission, where there is one type of task, namely building a rectangle.

Each task has a specific time (measured in turns) to complete, chance of success, and payoff. Thus, once several mutually exclusive potential tasks are found, they can be ranked by a strategy, and the best tasks can be chosen. Some strategies might be more aggressive, trying to achieve riskier tasks with bigger payoffs, whereas others may be more conservative. These preferences may be determined not only by the strategy's innate characteristics, but may also be based on board size and density, as well as relative scores and early behavior of opponents.

The general framework of a task is as follows:

abstract class Task
{
    void move();                 // move member robots

    boolean isFinished();        // is this task complete?
    boolean isHopeless();        // can this task never be completed?
    int expectedPayoff();        // how many points will we get from
                                 // this task
    float chanceOfSuccess();     // how likely are we to complete this task

    void destroy();              // free robots for other tasks
    void addRobot(int robot);    // add specified robot to this task
    void removeRobot(int robot); // add specified robot to this task
}

Types of Tasks