2015-04-24 2 views
2

Я пытаюсь переместить объект в матрице (массив с [x, y]) с использованием алгоритма рисования линии, чтобы помочь вам понять, что я имею в виду. пытаюсь сделать объект двигаться так:Попытка перемещения объекта в матрице с использованием алгоритма рисования линии

enter image description here

Но вместо того, чтобы идти „в линию“, это выглядит следующим образом:

enter image description here

я открыл еще один вопрос об этой проблеме здесь , и ты мне сказал мне e алгоритм рисования линии, который я сделал, но я все еще не могу заставить его двигаться в этом порядке.

Немного о коде (я даю вам «фон», поэтому вы не будете путать): переменная Location содержит местоположение на матрице, оно имеет x и y, к которым можно получить доступ, например это:

Location loc = new Location(x,y);//Declaring a new location 
int row = loc.Row;//Gets the x value (Row) 
int col = loc.Col;//Gets the y value (Column) 

Direction переменная содержит направление, есть 5 направлений:

Direction.NORTH; 
Direction.SOUTH; 
Direction.EAST; 
Direction.WEST; 
Direction.NOTHING; //This direction means to stay at the same place, or not move 

Я думаю, это очевидно, что каждый из них означает.

Команда game.Destination(myPirate, direction); вычисляет, где объект заканчивается на следующем повороте (возвращает местоположение).

Теперь вот код, который я получил:

public static Direction NextDirection(Game game,Pirate myPirate,Location EndLocation) 
    { 
     List<Direction> westEast = new List<Direction>() { Direction.EAST, Direction.WEST }; 
     List<Direction> northSouth = new List<Direction>() { Direction.NORTH, Direction.SOUTH }; 
     int startX = myPirate.Loc.Row; 
     int startY = myPirate.Loc.Col; 
     int endX = EndLocation.Row; 
     int endY = EndLocation.Col; 
     if (startX == endX && startY == endY) return Direction.NOTHING; //If its alredy on spot return the location of the pirate; 
     int dx = endX - startX; 
     int dy = endY - startY; 
     if (dx == 0) //The X of the end is the same as the x of the start, need to move only on the y axis; 
     { 
      return MyBot.GetBestDirection(game, myPirate, EndLocation); 
     } 
     if (dy==0) //The Y of the end is the same as the y of the start, need to move only on the x axis; 
     { 
      return MyBot.GetBestDirection(game, myPirate, EndLocation); 
     } 
     int slope = dy/dx; 
     Location destination; 
     double distance = MyBot.Distance(myPirate.Loc, EndLocation); 
     if (slope > 1 || slope < -1) 
     { 
      double distance2; 
      foreach (Direction dir in northSouth) //In here the algoritem decides whats the best direction (north or south); 
      { 
       destination = game.Destination(myPirate, dir); 
       distance2 = MyBot.Distance(destination, EndLocation); 
       if (distance2 < distance) return dir; 
      } 
      game.Debug("Couldnt find a good direction, going by the default dirction algorithem."); 
      return MyBot.GetBestDirection(game, myPirate, EndLocation); 
     } 
     else 
     { 
      double distance2; 
      foreach (Direction dir in westEast)//In here the algoritem decides whats the best direction (west or east); 
      { 
       destination = game.Destination(myPirate, dir); 
       distance2 = MyBot.Distance(destination, EndLocation); 
       if (distance2 < distance) return dir; 
      } 
      game.Debug("Couldnt find a good direction, going by the default dirction algorithem."); 
      return MyBot.GetBestDirection(game, myPirate, EndLocation); 
     } 
    } 

На некоторых участках в коде выше я также с использованием деталей из MyBot класса, вот эти части:

public static Direction GetBestDirection(Game game, Pirate myPirate, Location loc)//ADD: If the destination is not passable get another direction; 
    { 
     double distance = Distance(myPirate.Loc, loc); 
     List<Direction> allDirections = new List<Direction>() { Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, Direction.NOTHING }; 
     Location destination; 
     foreach (Direction dir in allDirections) 
     { 
      destination = game.Destination(myPirate, dir); 
      double distance2 = Distance(destination, loc); 
      if (distance2 < distance && game.IsPassable(destination)) return dir; 
     } 
     return Direction.NOTHING; 
    } 

«Объект», о котором я вам говорил, называется кодом myPirate, и он может перемещаться только в одном направлении за каждый ход. код запускается за каждый ход до тех пор, пока он не достигнет цели.

Как я могу заставить эту программу работать правильно? Что не так с моим кодом?

+0

Вы программируете какой-то робот? Затем вам нужно сначала построить путь, а затем попытаться следовать ему. Например. вы можете определить строку как 'y = kx + b' или как' x + = dx' и 'y + = dy' (до вас), затем на каждой итерации построения пути (поиск координат следующей ячейки, ток, увеличиваясь короче, чтобы двигаться: 'x' или' y'), где вы должны идти (N, S, E, W) и делать шаг. – Sinatr

+0

'int slope = dy/dx;' и '(slope> 1 || slope <-1)' подразумевает, что наклон должен быть 2 или более, чтобы идти на север или на юг. Это градиент более 66%, в противном случае он будет горизонтальным. Даже если вы только что разработали касательный квадрант и следовали за тем, что вы получите более постепенную линию. Чтобы получить нужную строку, вам нужно место начала. Затем следующий квадрат, из которого когда-либо проходит линия с исходного места –

+0

@Sinatr, это не работает, код запускается 1 раз за ход, для exapmle: поверните 1: мой бот играет, затем код останавливается и бот 2, код запускается и останавливается. вся переменная вырывается из памяти, а в свою очередь, она начинается, поэтому я не думаю, что ваш метод будет работать. –

ответ

2

Вы должны вычислить наклон как поплавок или двойной, а не как int. Когда вы используете целочисленное деление, 1/2 равно 0, и, конечно, когда наклон равен 0, вы двигаетесь вправо. Это означает, что если вы переходите от (0,0) до (20,10), вам придется начинать с 10 (1,0) шагов, если вы используете целочисленное деление, и это не лучшее поведение.

Если вы установили фиксированный порог для наклона (с плавающей запятой), например, если наклон меньше 1,0, тогда идите вправо, тогда вы не будете следовать за строкой близко, потому что вы будете двигаться должным образом, пока не получите до точки, где наклон больше порога. Поэтому не используйте фиксированный порог.

Быстрый и грязный метод - рандомизировать порог так, чтобы он заставлял вас двигаться в нужном направлении в среднем. Предположим, что dx> 0 и dy> 0. Вы можете справиться с другими квадрантами по симметрии. Чтобы перемещаться в нужном направлении в среднем, вы можете выбрать случайное целое число из [0, dx + dy-1]. Если он меньше, чем dx, сделайте шаг в направлении x. Если он больше или равен dx, сделайте шаг в направлении y. Эквивалентно, выберите случайный двойник в [0,1], а если он меньше, чем dx/(dx + dy), сделайте шаг в направлении x, иначе сделайте шаг в направлении y.

Если вам не нравится рандомизация, вы можете derandomize это. Вместо того, чтобы выбирать фиксированный порог, вы можете выбрать псевдослучайную функцию (dx, dy, x, y). Например, вы можете сравнить dx/(double) (dx + dy) с (2^((dx + 3 * dy)% 28) mod 29) /29.0. Это устанавливает пороговое значение от 1/29 до 28/29 примерно единообразным образом.


Редактировать: Вот несколько непроверенных кодов.

// assume dx>0, dy>0 
int linearMod28 = (dx + 3*dy) % 28; // 0 through 27 
int pseudorandomMod29 = (1 << linearMod28) % 29; // 1 through 28 
double threshold = pseudorandomMod29/29.0; // 1/29 through 28/29 
if (dx/(double)(dx+dy) < threshold) 
    // take a step in the x direction 
else 
    // take a step in the y direction 
+0

Я не понимал, что вы имели в виду в последних 4 строках. не могли бы вы показать мне пример кода, что вы имели в виду? (что-то маленькое) –

+0

СПАСИБО !!! это первое, что действительно сработало! но я не понял 2 вещи, почему% 28 и% 29? я имею в виду, почему эти цифры, а не 52 или 36? –

+1

Я использовал небольшую теорию чисел. Поскольку 29 является простым, а один из примитивных корней равен 2, то степени 2 охватывают все возможности mod 29, кроме 0, повторяя каждый 28. Итак, 2^0 mod 29 = 1, 2^1 mod 29 = 2 , 2^2 mod 29 = 4, ... 2^27 mod 29 = 15, 2^28 mod 29 = 1. Силы 12 не были бы хорошим выбором, так как это только ударило бы несколько возможностей, прежде чем повторять, так как 12^4 mod 29 = 1. Так как полномочия 2 повторяются каждые 28, вам нужно только отслеживать модель экспоненты 28, и сокращение до числа от 0 до 27 означает, что вы можете вычислить 2^k, используя оператор сдвига. –

 Смежные вопросы

  • Нет связанных вопросов^_^