+ return OK;
+}
+
+/**
+ * Calculates the intrinsic strategic worth of a point on the board
+ * @param x the x coordinate of the point
+ * @param y the y coordinate of the point
+ * @returns a value between 0 and 1, with 0 indicating worthless and 1 indicating highly desirable
+ * (NOTE: No points will actually be worth 0)
+ */
+double Forfax::IntrinsicWorth(int x, int y) const
+{
+ static double intrinsicWorth[][10][10] =
+ {
+ //Red
+ {
+ {0.1,0.5,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1},
+ {0.5,0.5,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1},
+ {0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2},
+ {0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3},
+ {0.6,0.6,0.1,0.1,0.65,0.65,0.1,0.1,0.6,0.6},
+ {0.6,0.6,0.1,0.1,0.65,0.65,0.1,0.1,0.6,0.6},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7}
+
+
+ },
+ //Blue
+ {
+ {0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.6,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.6},
+ {0.6,0.6,0.1,0.1,0.65,0.65,0.1,0.1,0.6,0.6},
+ {0.6,0.6,0.1,0.1,0.65,0.65,0.1,0.1,0.6,0.6},
+ {0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3},
+ {0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2},
+ {0.5,0.5,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1},
+ {0.1,0.5,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1}
+ }
+ };
+
+ return intrinsicWorth[(int)(colour)][x][y];
+}
+
+/**
+ * Calculates a score assuming that attacker will beat defender, indicating how much killing that piece is worth
+ * @param attacker the Attacking piece
+ * @param defender the Defending piece
+ * @returns a value between 0 and 1, with 0 indicating worthless and 1 indicating highly desirable
+ */
+double Forfax::VictoryScore(Piece * attacker, Piece * defender) const
+{
+
+ //If defender's rank is known, flags or bombs are worth more than usual
+ if (defender->minRank == defender->maxRank)
+ {
+ if (defender->minRank == Piece::FLAG)
+ return 1;
+ else if (defender->minRank == Piece::BOMB)
+ return 0.9;
+ }
+ //Return average of normalised defender ranks
+ return max<double>(((defender->maxRank / Piece::BOMB) + (defender->minRank / Piece::BOMB))/2, 1);
+}
+
+/**
+ * Calculates a score assuming that attacker will lose to defender, indicating how much learning the rank of that piece is worth
+ * @param attacker the Attacking piece
+ * @param defender the Defending piece
+ * @returns a value between 0 and 1, with 0 indicating worthless and 1 indicating highly desirable
+ */
+double Forfax::DefeatScore(Piece * attacker, Piece * defender) const
+{
+
+ double result = 0;
+ if (defender->minRank == defender->maxRank) //If the defender's rank is known for certain...
+ {
+ if (defender->minRank == Piece::BOMB) //Committing suicide to destroy bombs has a value that decreases with the attacker's rank
+ result = 1 - 0.5*(double)((double)(attacker->minRank) / (double)(Piece::BOMB));
+ else if (defender->minRank == Piece::FLAG)
+ result = 1; //Its impossible to lose to the flag anyway...
+ else
+ {
+ //This is committing suicide on a higher ranked non-bomb enemy piece.
+ //Basically pointless, but the greater the attacker's rank the more pointless!
+ double temp = (double)((double)(attacker->minRank) / (double)(Piece::BOMB));
+ result = 0.01*(1 - temp)*(1 - temp);
+
+
+ }
+ }
+ else //The defender's rank is not known
+ {
+
+ //Score is allocated based on how much knowledge is gained by attacking defender
+ //The more possible ranks for the defender, the greater the score
+ //The score decreases as the rank of the attacker is increased.
+
+ double possibleRanks = 0; double totalRanks = 0; double bonus = 0;
+ for (Piece::Type rank = Piece::NOTHING; rank <= Piece::BOMB; rank = Piece::Type((int)(rank) + 1))
+ {
+ totalRanks += remainingUnits[(int)(defender->colour)][(int)(rank)];
+
+ if (rank >= defender->minRank && rank <= defender->maxRank)
+ {
+ possibleRanks += remainingUnits[(int)(defender->colour)][(int)(rank)];
+ if (rank == Piece::BOMB)
+ bonus += remainingUnits[(int)(defender->colour)][(int)(rank)];
+ if (rank == Piece::FLAG)
+ bonus += 2*remainingUnits[(int)(defender->colour)][(int)(rank)];
+ }
+
+ }
+
+
+ if (totalRanks > 0)
+ {
+ double multiplier = ((double)(Piece::BOMB) - (double)(attacker->minRank)) / (double)(Piece::BOMB);
+ result = (possibleRanks/totalRanks) * multiplier * multiplier;
+ }
+
+ result += bonus / totalRanks;
+
+ if (result > 1)
+ result = 1;
+ }
+
+ if (attacker->minRank == Piece::SPY) //Spies are slightly more valuable than usual since they kill the Marshal
+ result = result / 1.5;
+ return result;
+
+}
+
+/**
+ * Calculates a score indicating the worth of invoking combat in a square
+ * @param x The x coordinate
+ * @param y The y coordinate
+ * @param attacker The piece invoking the combat
+ * @returns A value between 0 in 1, with 0 indicating worthless (or no combat) and 1 indicating highest value
+ */
+double Forfax::CombatScore(int x, int y, Piece * attacker) const
+{
+ Piece * defender = board->Get(x, y);
+ if (defender == NULL)
+ return 0;
+ double combatSuccess = CombatSuccessChance(attacker, defender);
+ return IntrinsicWorth(x, y)*combatSuccess*VictoryScore(attacker, defender) + (1.0 - combatSuccess)*DefeatScore(attacker, defender);
+}
+
+/**
+ * DEBUG - Print the board seen by Forfax to a stream
+ * @param out The stream to print to
+ */
+void Forfax::PrintBoard(ostream & out)
+{
+ for (int y = 0; y < board->Height(); ++y)
+ {
+ for (int x = 0; x < board->Width(); ++x)
+ {
+ Piece * at = board->Get(x, y);
+ if (at == NULL)
+ out << ".";
+ else
+ {
+ if (at->colour == colour)
+ {
+ out << Piece::tokens[(int)(at->minRank)];
+ }
+ else if (at->colour == Piece::Opposite(colour))
+ {
+ out << "#";
+ }
+ else
+ {
+ out << "+";
+ }
+ }
+ }
+ out << "\n";
+ }