特定の迷路を解決したい場合は、BadHorseの答えが適しています。あなたは単にあなたのビット文字列を迷路を通してエージェントを導くための一連の正確な指示として解釈します。この場合、適合度はビット文字列の合計ではなく(質問で述べたように)、エージェントが問題の解決にどれだけ成功したかを測定するメトリックです。たとえば、フィットネスは「20個の命令を処理した後の迷路の端から直線の距離」として定義される場合があります。
したがって、各個人を評価するときは、ビット文字列から最初の20個の命令を処理し、その適合性を計算し、クロスオーバー/ミューテーションを実行して、次世代の個人を作成することを許可します。
迷路を解決するエージェントを開発したい場合は、一連の命令ではなく、ビット文字列内にルールをエンコードする必要があります。壁がロボットのすぐ後ろ、前、左、右のいずれにあるかに基づいてルールを定義できます。例えば
FBLR Action
0000 Move Forward
0001 Move Forward
0010 Turn Right
etc
これにより、16個のアクションで構成されるビット文字列が得られます。各アクションは2ビットとしてエンコードされます(00 =前方に移動、01 =右に回転、10 =左に回転、11 =後方に移動)。エージェントを評価するときは、単に現在の状態を判断し、ビット文字列をルックアップテーブルとして使用して、エージェントがどのように応答するかを判断します。次に、これを特定の回数繰り返します。その後、その適合性を評価します。
このエンコーディングが与えられると、エージェントは人間が通常使用する「左側の壁を継続的に追跡する」というルールを評価できます。明らかに、迷路が完全に接続されていない場合、このアプローチは失敗します。この場合、ルールベースのアプローチにより多くの状態をエンコードする必要があります(たとえば、エージェントが「古い地面」を越えた場合、異なる応答をする可能性があります)。
お役に立てば幸いです。
編集
最新の編集に応じて:
壁の隣にあるかどうかを検出するエージェント「センサー」をエンコードしたという事実は、ビット文字列(あなたの遺伝子)とは関係ありません。おそらく、私の例と少し混乱しています。遺伝子は、センサーの状態ではなく、アクション(前進など)のみをエンコードします。
したがって、センサー読み取り値の特定の組み合わせを指定して、ビット文字列の関連部分を検索するコードを作成する必要があります。例えば
/**
* Enumeration describing the four available actions to the agent
* and methods for decoding a given action from the "bit" string
* (actually represented using booleans).
*/
public enum Action {
MOVE_FORWARD, REVERSE, TURN_LEFT, TURN_RIGHT
Action decodeAction(boolean b1, boolean b2) {
Action ret;
if (b1) {
ret = b2 ? Action.MOVE_FORWARD : Action.TURN_LEFT;
} else {
ret = b2 ? Action.TURN_RIGHT : Action.REVERSE;
}
return ret;
}
}
/**
* Class encapsulating the 32-bit "bit string" represented using booleans.
* Given the state of the four agent inputs the gene will provide a specific
* action for the agent to perform.
*/
public class Gene {
private final boolean[] values = new boolean[32];
public Action getActionForSensorInputs(boolean wallInFront,
boolean wallBehind, boolean wallToLeft, boolean wallToRight) {
int i=0;
// Encode the four sensor inputs as a single integer value by
// bitwise-ORing each sensor value with a power of 2.
// The encoded value will be in the range [0, 15].
if (wallToRight) {
i |= 0x01;
}
if (wallToLeft) {
i |= 0x02;
}
if (wallBehind) {
i |= 0x04;
}
if (wallInFront) {
i |= 0x08;
}
// The look-up index is i * 2 because each action is encoded as 2
// booleans.
int index = i * 2;
// Retrieve the two action bits from the bit string.
boolean b1 = this.values[index];
boolean b2 = this.values[index + 1];
// Finally decode the action to perform.
return Action.decodeAction(b1, b2);
}
// TODO: Add method to support crossover and mutation with other Genes.
}
この単純な定義を前提としてGene
、このクラスを実装内に埋め込みAgent
、現在の遺伝子が「インストールされている」場合にエージェントがどのように機能するかを記録できます。例えば
private enum Direction { NORTH, SOUTH, EAST, WEST };
public class Agent {
private final Geneva gene;
private final int x; // x position in maze;
private final int y; // y position in maze;
private Direction currentDirection;
public double evaluate() {
double fitness;
// Perform up to 20 actions and then evaluate fitness.
for (int i=0; i<20; ++i) {
// TODO Determine sensor inputs.
Action action = gene.getActionForSensorInputs(...);
// TODO: Now apply action to update agent's state.
// If agent has reached goal exit loop and return fitness 1.0 (max fitness).
// If agent has exited the maze then exit loop and return 0.0 (min fitness).
}
// Calculate fitness after 100 steps taken. For example could be
// calculated as sqrt((goal.x - x) ^ 2 + (goal.y - y) ^ 2).
return fitness;
}
}