2

I'm trying to move an object in a matrix (an array with [x,y]) using a line drawing algorithm, to help you understand what I mean I'm trying to make an object move like this:

enter image description here

But instead of going "in line" it goes like this:

enter image description here

I opened another question about this problem here, and you told me to use a line drawing algorithm, which I did, but I still can't make it move in that order.

A little bit about the code (I'm giving you some 'background' so you won't be confused): The Location variable contains a location on the matrix, it has x and y, which can be accessed like this:

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)

The Direction variable contains a direction, there are 5 directions:

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

I think it's obvious what each of them means.

The command game.Destination(myPirate, direction); calculates where the object ends up on the next turn(returns a location).

Now here is the code that I got:

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);
        }
    }

On some parts in the code above I'm also using parts from the MyBot class, here are these parts:

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;
    }

The 'object' I told you about is called myPirate in the code, and it can only move in one direction each turn. the code run again in each turn until it gets to the target.

How can I make this program work right? What is wrong with my code?

4

1 回答 1

2

您应该将斜率计算为浮点数或双精度数,而不是整数。当您使用整数除法时,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]中选择一个随机double,如果它低于dx/(dx+dy),则在x方向上走一步,否则在y方向上走一步。

如果你不喜欢随机化,那么你可以去随机化它。您可以选择 (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
于 2015-04-24T16:58:51.347 回答