Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Assets.Scripts.DataStructures;
- using UnityEngine;
- using System.Linq;
- using System;
- using System.Collections.Generic;
- using System.IO;
- namespace Assets.Scripts.SampleMind {
- public class RandomMind : AbstractPathMind {
- //Si ya está generado el .txt con las tablas, poner este valor a true evitará generar las tablas Q y R de nuevo.
- bool tablaCreada = false;
- //Valores de alpha y gamma usados en la generación de la tabla Q.
- float alpha = 0.3f;
- float gamma = 0.8f;
- //Inicialización de tablas Q y R que se van a volcar en los .txt.
- double[,] R = new double[112, 112];
- double[,] Q = new double[112, 4];
- //Flag para que solo sea lean los .txt una vez.
- bool flagRead = false;
- //Valores que controlan la generación de la tabla Q.
- int iterations = 1000;
- int maxPasos = 250;
- //Inicalización de la tabla Q tras leer el .txt.
- double[,] QTable = new double[112, 4];
- public override void Repath() {
- }
- public override Locomotion.MoveDirection GetNextMove(BoardInfo boardInfo, CellInfo currentPos, CellInfo[] goals) {
- //Evita crear las tablas más de una vez.
- if (!tablaCreada) {
- CreateTables(boardInfo, currentPos, goals[0]);
- tablaCreada = true;
- }
- //Evita leer las tablas más de una vez.
- if (!flagRead) {
- ReadTables(QTable);
- flagRead = true;
- }
- //Elige el movimiento en función del valor de Q más alto.
- double[] possibleQ = { QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 0], QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 1], QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 2], QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 3] };
- Array.Sort(possibleQ);
- for (int i = 3; i >= 0; i--) {
- if (possibleQ[i] == QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 0]) {
- if (boardInfo.CellInfos[currentPos.ColumnId, currentPos.RowId + 1].Walkable) {
- return Locomotion.MoveDirection.Up;
- }
- } else if (possibleQ[i] == QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 1]) {
- if (boardInfo.CellInfos[currentPos.ColumnId + 1, currentPos.RowId].Walkable) {
- return Locomotion.MoveDirection.Right;
- }
- } else if (possibleQ[i] == QTable[currentPos.ColumnId + currentPos.RowId * boardInfo.NumColumns, 2]) {
- if (boardInfo.CellInfos[currentPos.ColumnId, currentPos.RowId - 1].Walkable) {
- return Locomotion.MoveDirection.Down;
- }
- } else {
- if (boardInfo.CellInfos[currentPos.ColumnId - 1, currentPos.RowId].Walkable) {
- return Locomotion.MoveDirection.Left;
- }
- }
- }
- return Locomotion.MoveDirection.None;
- }
- private void CreateTables(BoardInfo board, CellInfo currentPos, CellInfo goal) {
- //Inicializa las tablas a los valores por defecto, Q a 0, R a -1.
- Array.Clear(Q, 0, Q.Length);
- for (int i = 0; i < board.NumColumns * board.NumRows; i++) {
- for (int j = 0; j < board.NumColumns * board.NumRows; j++) {
- R[i, j] = -1;
- }
- }
- CellInfo pos = currentPos;
- CellInfo[] vecinos;
- //Rellena los valores de R que son 0 y 100.
- for (int i = 0; i < board.NumColumns * board.NumRows; i++) {
- vecinos = pos.WalkableNeighbours(board);
- for (int j = 0; j < 4; j++) {
- if (vecinos[j] != null) {
- if (vecinos[j] == goal) {
- R[i, vecinos[j].ColumnId + vecinos[j].RowId * board.NumColumns] = 100;
- } else {
- R[i, vecinos[j].ColumnId + vecinos[j].RowId * board.NumColumns] = 0;
- }
- }
- }
- if (i < (board.NumColumns * board.NumRows - 1)) {
- do {
- if (pos.ColumnId < (board.NumColumns - 1)) {
- pos = board.CellInfos[pos.ColumnId + 1, pos.RowId];
- } else {
- pos = board.CellInfos[0, pos.RowId + 1];
- }
- if (!pos.Walkable) {
- i++;
- }
- } while (!pos.Walkable && i < (board.NumColumns * board.NumRows - 1));
- }
- }
- int auxPos, auxSig;
- CellInfo sig;
- int rand;
- //Rellena la tabla Q.
- for (int i = 0; i < iterations; i++) {
- //Asegura que la posición inicial de la simulación sea una celda caminable.
- do {
- pos = board.CellInfos[UnityEngine.Random.Range(0, board.NumColumns), UnityEngine.Random.Range(0, board.NumRows)];
- } while (!pos.Walkable);
- //Simula de forma aleatoria los pasos hacia la meta. Si lleva *maxPasos* pasos sin dar con la meta, se salta a la siguiente simulación.
- for (int j = 0; j < maxPasos; j++) {
- //Si llega a la meta, se acaba esta simulación.
- if (pos == goal) {
- break;
- }
- //Cogemos los vecinos a los que puede moverse para elegir el siguiente movimiento.
- vecinos = pos.WalkableNeighbours(board);
- do {
- rand = UnityEngine.Random.Range(0, 4);
- sig = vecinos[rand];
- } while (sig == null);
- //Actualiza la posición.
- auxPos = pos.ColumnId + pos.RowId * board.NumColumns;
- auxSig = sig.ColumnId + sig.RowId * board.NumColumns;
- //Actualizamos el valor de Q según la función de QLearning.
- double[] QPrima = { Q[auxSig, 0], Q[auxSig, 1], Q[auxSig, 2], Q[auxSig, 3] };
- double QMax = QPrima.Max();
- Q[auxPos, rand] = Q[auxPos, rand] * (1 - alpha) + alpha * (R[auxPos, auxSig] + gamma * QMax);
- pos = sig;
- }
- }
- //Escribe en R.txt en el escritorio la tabla R.
- StreamWriter outputFile = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "R.txt"));
- string fila;
- for (int i = 0; i < board.NumColumns * board.NumRows; i++) {
- fila = "";
- for (int j = 0; j < board.NumColumns * board.NumRows; j++) {
- fila += R[i, j] + " ";
- }
- outputFile.WriteLine(fila);
- }
- outputFile.Close();
- //Escribe en Q.txt en el escritorio la tabla Q.
- outputFile = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Q.txt"));
- for (int i = 0; i < board.NumColumns * board.NumRows; i++) {
- fila = Q[i, 0] + " " + Q[i, 1] + " " + Q[i, 2] + " " + Q[i, 3];
- outputFile.WriteLine(fila);
- }
- outputFile.Close();
- }
- //Método que lee la tabla Q desde el archivo Q.txt.
- private double[,] ReadTables(double[,] QTable) {
- StreamReader file = new StreamReader(@"C:/Users/" + Environment.UserName + "/Desktop/Q.txt");
- string line;
- int i = 0, j = 0;
- while ((line = file.ReadLine()) != null) {
- foreach (string input in line.Split(' ')) {
- QTable[i, j] = double.Parse(input);
- j++;
- }
- j = 0;
- i++;
- }
- return QTable;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement