private void ExpansionConDiagonales(Baldosa actual) { for (var i = -1; i <= 1; i++) { if (actual.Posicion.X + i >= 0 && actual.Posicion.X + i < Mapa.GetLength(0)) { for (var j = -1; j <= 1; j++) { if (actual.Posicion.Y + j >= 0 && actual.Posicion.Y + j < Mapa.GetLength(1)) { if (Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Accesible) { if (!(Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Valor == (float)TiposBaldosa.Rio && !Nadar)) { if (!(Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Valor == (float)TiposBaldosa.Montaña && !Escalar)) { CostesYTratarNodos(actual, i, j); } } } } } } } }
private void NuevoTablero() { MainThread.BeginInvokeOnMainThread(() => { Grid.Children.Clear(); _inicio = null; _fin = null; _enEjecucion = false; _terminado = false; for (var i = 0; i < _size.Y; i++) { for (var j = 0; j < _size.X; j++) { var coordenadas = new Coordenadas(j, _size.Y - (i + 1)); var celda = new Celda() { WidthRequest = 5.0, HeightRequest = 5.0, BackgroundColor = (Color)Application.Current.Resources["AltColor"], Coordenadas = coordenadas, Aspect = Aspect.AspectFit }; celda.Clicked += Baldosa_Clicked; _mapa[coordenadas.X, coordenadas.Y] = new Baldosa(coordenadas, celda); Grid.Children.Add(celda, j, i); } } }); }
/// <summary> /// Calcula con el algoritmo A* el camino entre el inicio y la meta en el mapa proporcionado /// </summary> /// <param name="inicio">Coordenada de inicio</param> /// <param name="meta">Coordenada de llegada</param> /// <param name="movimientoDiagonal">Indica si se permite el movimiento lateral</param> /// <param name="movimientoOrtogonal"></param> /// <param name="mapa">Mapa en el que se ejecuta el algoritmo</param> /// <param name="wayPoints">Puntos intermedios por los que hay que pasar en orden</param> /// <returns>Objeto Resultado con el camino y el coste.</returns> public static AEstrellaResultado CalculoAEstrella(Baldosa inicio, Baldosa meta, bool movimientoDiagonal, bool movimientoOrtogonal, Baldosa[,] mapa, params Baldosa[] wayPoints) { var resultado = new AEstrellaResultado(new List <Baldosa>(), 0); var puntos = new Baldosa[wayPoints.Length + 2]; var i = 0; puntos[i++] = inicio; for (; i <= wayPoints.Length; i++) { puntos[i] = wayPoints[i - 1]; } puntos[i] = meta; i = 1; for (; i < puntos.Length; i++) { var aEstrella = new AEstrella(puntos[i - 1], puntos[i], movimientoDiagonal, movimientoOrtogonal, mapa); var parcial = aEstrella.Algoritmo(); if (parcial.Camino == null) { return(new AEstrellaResultado(mapa, null, 0.0)); } resultado.Coste += parcial.Coste; resultado.Camino.AddRange(parcial.Camino); aEstrella.LimpiarListas(resultado.Camino); } return(resultado); }
/// <summary> /// Calcula con el algoritmo A* el camino entre el inicio y la meta en el mapa proporcionado /// </summary> /// <param name="inicio">Coordenada de inicio</param> /// <param name="meta">Coordenada de llegada</param> /// <param name="movimientoDiagonal">Indica si se permite el movimiento lateral</param> /// <param name="movimientoOrtogonal"></param> /// <param name="mapa">Mapa en el que se ejecuta el algoritmo</param> /// <returns>Objeto Resultado con el camino y el coste.</returns> public static AEstrellaResultado CalculoAEstrella(Baldosa inicio, Baldosa meta, bool movimientoDiagonal, bool movimientoOrtogonal, Baldosa[,] mapa) { var aEstrella = new AEstrella(inicio, meta, movimientoDiagonal, movimientoOrtogonal, mapa); return(aEstrella.Algoritmo()); }
/// <summary> /// Pasa el nodo a la lista abierta /// </summary> /// <param name="actual">Punto donde está el algoritmo</param> /// <param name="i">Incremento de la coordenada X</param> /// <param name="j">Incremento de la coordenada Y</param> /// <param name="coste">Coste del paso</param> private void NodoAAbierta(Baldosa actual, int i, int j, double coste) { Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Abierto = true; Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].G = Mapa[actual.Posicion.X, actual.Posicion.Y].G + coste; Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].H = Calculo.Distancia(Mapa[actual.Posicion.X + i, actual.Posicion.Y + j], Meta); Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Padre = Mapa[actual.Posicion.X, actual.Posicion.Y]; Abierta.Enqueue(Mapa[actual.Posicion.X + i, actual.Posicion.Y + j], Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].F); }
/// <summary> /// Reorienta el enlace del nodo /// </summary> /// <param name="actual">Punto donde está el algoritmo</param> /// <param name="i">Incremento de la coordenada X</param> /// <param name="j">Incremento de la coordenada Y</param> /// <param name="coste">Coste del paso</param> private void ReorientacionEnlaces(Baldosa actual, int i, int j, double coste) { if (Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].G > Mapa[actual.Posicion.X, actual.Posicion.Y].G + coste) // Si el coste es menor { Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].G = Mapa[actual.Posicion.X, actual.Posicion.Y].G + coste; Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Padre = Mapa[actual.Posicion.X, actual.Posicion.Y]; Abierta.UpdatePriority(Mapa[actual.Posicion.X + i, actual.Posicion.Y + j], Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].F); } }
internal AEstrella(Baldosa inicio, Baldosa meta, bool movimientoDiagonal, bool movimientoOrtogonal, Baldosa[,] mapa) { Inicio = inicio; Meta = meta; Mapa = mapa; Abierta = new FastPriorityQueue <Baldosa>(mapa.Length); Nadar = true; Escalar = true; MovimientoDiagonal = movimientoDiagonal; MovimientoOrtogonal = movimientoOrtogonal; }
/// <summary> /// Genera el camino resultado /// </summary> /// <param name="resultadoAlgoritmo">Punto donde acabael algoritmo</param> /// <param name="resultado">Objeto resultado</param> protected static void TratarCaminoResultado(Baldosa resultadoAlgoritmo, AEstrellaResultado resultado) { Baldosa actual = resultadoAlgoritmo; while (actual != null) { resultado.Camino.Add(actual); actual = actual.Padre; } resultado.Camino.Reverse(); }
private void CostesYTratarNodos(Baldosa actual, int i, int j) { // Calculamos los costes de acceder double coste = Calculo.Distancia(Mapa[actual.Posicion.X, actual.Posicion.Y], Mapa[actual.Posicion.X + i, actual.Posicion.Y + j]); if (Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Abierto == true) // Actualizamos la lista abierta { ReorientacionEnlaces(actual, i, j, coste); } else if (Mapa[actual.Posicion.X + i, actual.Posicion.Y + j].Abierto == null) // Agregamos a la lista abierta { NodoAAbierta(actual, i, j, coste); } }
/// <summary> /// Ejecución del algoritmo /// </summary> /// <returns>Punto del mapa al que se llega</returns> private Baldosa CalculoAlgoritmo() { Baldosa resultado = null; var salir = false; while (!salir) { if (Abierta.Count == 0) { salir = true; } else { var actual = Abierta.Dequeue(); //Cerramos el nodo actual.Abierto = false; MainThread.BeginInvokeOnMainThread(() => { actual.Celda.BackgroundColor = Color.Teal; }); if (actual.Posicion.Equals(Meta.Posicion)) { resultado = Mapa[Meta.Posicion.X, Meta.Posicion.Y]; salir = true; } else { // Expansion del punto actual if (MovimientoDiagonal && MovimientoOrtogonal) { ExpansionConDiagonales(actual); } else { if (MovimientoOrtogonal) { ExpansionOrtogonal(actual); } if (MovimientoDiagonal) { ExpansionDiagonal(actual); } } } } } return(resultado); }
/// <summary> /// Trata y genera la solución del algoritmo /// </summary> /// <param name="resultadoAlgoritmo">Punto del mapa al que se llega</param> /// <returns>Objeto con el camino y el coste asociado</returns> protected AEstrellaResultado ProcesarResultado(Baldosa resultadoAlgoritmo) { AEstrellaResultado resultado; if (resultadoAlgoritmo == null) { resultado = new AEstrellaResultado(Mapa, null, 0.0); } else { resultado = new AEstrellaResultado(Mapa, new List <Baldosa>(), resultadoAlgoritmo.F); TratarCaminoResultado(resultadoAlgoritmo, resultado); } return(resultado); }
private void ExpansionOrtogonal(Baldosa actual) { for (var i = -1; i <= 1; i += 2) { if (actual.Posicion.X + i >= 0 && actual.Posicion.X + i < Mapa.GetLength(0)) { if (Mapa[actual.Posicion.X + i, actual.Posicion.Y].Accesible) { CostesYTratarNodos(actual, i, 0); } } if (actual.Posicion.Y + i >= 0 && actual.Posicion.Y + i < Mapa.GetLength(1)) { if (Mapa[actual.Posicion.X, actual.Posicion.Y + i].Accesible) { CostesYTratarNodos(actual, 0, i); } } } }
private void ExpansionDiagonal(Baldosa actual) { for (int i = -1; i <= 1; i += 2) { if ((actual.Posicion.X + i >= 0 && actual.Posicion.X + i < Mapa.GetLength(0)) && (actual.Posicion.Y + i >= 0 && actual.Posicion.Y + i < Mapa.GetLength(1))) { if (Mapa[actual.Posicion.X + i, actual.Posicion.Y + i].Accesible) { CostesYTratarNodos(actual, 0 + i, 0 + i); } } if ((actual.Posicion.X + i >= 0 && actual.Posicion.X + i < Mapa.GetLength(0)) && (actual.Posicion.Y - i >= 0 && actual.Posicion.Y - i < Mapa.GetLength(1))) { if (Mapa[actual.Posicion.X + i, actual.Posicion.Y - i].Accesible) { CostesYTratarNodos(actual, 0 + i, 0 - i); } } } }
private async Task AsignarTipoBaldosa(Celda celda) { switch (TipoBaldosa.SelectedIndex) { case 0: // Inicio if (_fin != null && celda.Coordenadas.Equals(_fin.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _fin.Celda.Source = ""; }); _fin = null; } if (_inicio != null) { MainThread.BeginInvokeOnMainThread(() => { _inicio.Celda.Source = ""; }); } MainThread.BeginInvokeOnMainThread(() => { celda.Source = "Inicio"; }); _inicio = _mapa[celda.Coordenadas.X, celda.Coordenadas.Y]; _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = true; _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = 0; break; case 1: // Fin if (_inicio != null && celda.Coordenadas.Equals(_inicio.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _inicio.Celda.Source = ""; }); _inicio = null; } if (_fin != null) { MainThread.BeginInvokeOnMainThread(() => { _fin.Celda.Source = ""; }); } MainThread.BeginInvokeOnMainThread(() => { celda.Source = "Fin"; }); _fin = _mapa[celda.Coordenadas.X, celda.Coordenadas.Y]; _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = true; _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = 0; break; case 2: // Perro - No accesible if (_inicio != null && celda.Coordenadas.Equals(_inicio.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _inicio.Celda.Source = ""; }); _inicio = null; } else if (_fin != null && celda.Coordenadas.Equals(_fin.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _fin.Celda.Source = ""; }); _fin = null; } if (_mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible) { MainThread.BeginInvokeOnMainThread(() => { celda.Source = "Perro"; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = false; } else { MainThread.BeginInvokeOnMainThread(() => { celda.Source = ""; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = true; } _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = 0; break; case 3: // Montaña if (_inicio != null && celda.Coordenadas.Equals(_inicio.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _inicio.Celda.Source = ""; }); _inicio = null; } else if (_fin != null && celda.Coordenadas.Equals(_fin.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _fin.Celda.Source = ""; }); _fin = null; } if (_mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor == (double)TiposBaldosa.Montaña) { MainThread.BeginInvokeOnMainThread(() => { celda.Source = ""; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = 0; } else { MainThread.BeginInvokeOnMainThread(() => { celda.Source = "Montana"; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = (double)TiposBaldosa.Montaña; } _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = true; break; case 4: // Río if (_inicio != null && celda.Coordenadas.Equals(_inicio.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _inicio.Celda.Source = ""; }); _inicio = null; } else if (_fin != null && celda.Coordenadas.Equals(_fin.Celda.Coordenadas)) { MainThread.BeginInvokeOnMainThread(() => { _fin.Celda.Source = ""; }); _fin = null; } if (_mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor == (double)TiposBaldosa.Rio) { MainThread.BeginInvokeOnMainThread(() => { celda.Source = ""; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = 0; } else { MainThread.BeginInvokeOnMainThread(() => { celda.Source = "Rio"; }); _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Valor = (double)TiposBaldosa.Rio; } _mapa[celda.Coordenadas.X, celda.Coordenadas.Y].Accesible = true; break; default: await DisplayAlert("Error", "Tipo no implementado, perdone las molestias", "OK"); break; } }
public static double Distancia(Baldosa a, Baldosa b) { return(Math.Sqrt(Math.Pow(a.Posicion.X - b.Posicion.X, 2) + Math.Pow(a.Posicion.Y - b.Posicion.Y, 2))); }