Avoiding portals on route to destination

Wrote new code? Fixed a bug? Want to discuss technical stuff? Feel free to post it here.

Moderator: Moderators

Bibian
Perl Monk
Perl Monk
Posts: 416
Joined: 04 Apr 2008, 03:08

Avoiding portals on route to destination

#1 Post by Bibian »

We've prolly all been there, kore is going somewhere and then it walks into a portal, sure it walks out. But kore wants to walk across the cell that is covered by the portal because it doesnt know howto route around it. bots can get stuck for HOURS this way. We should do something about this.

I made a small start to detect what portals are actually close to you

Code: Select all

sub processPortalAvoid {
	for (my $i = 0; $i < @portalsID; $i++) {
		next if $portalsID[$i] eq "";
		my $portal = $portals{$portalsID[$i]};
		
		if (blockDistance($char->{pos},$portal->{pos}) < 6) {
			message("Attemption to avoid portal on route to our destination.\n");
		}
	}
}
This would go into CoreLogic.pm i would say
Few things need to be considerd, like we dont wanna avoid the portal we're walking to, nor do we want to avoid a portal too soon or get stuck trying to avoid 1 or more portals.
Also, how do we know where to walk to, to avoid the portal? sure we can use isWalkable() but we have to make sure we don't route back and cause kore to get stuck in a loop anyway.

The best way would be to somehow modify the map data on the fly and tell kore those portal cells are unwalkable and should be avoided, a new route (in-map movement) should then be calculated and it should, in theory, avoid the portal. But to be honest i have no idea howto modify the map data like that on the fly. since we have to undo this after we've avoided the portal. also we shouldnt do this to the target portal (if any)

Idea's? suggestions? intelligent replies only!

If you cant read that code i pasted, dont reply...
ezza
Developers
Developers
Posts: 109
Joined: 04 Apr 2008, 09:50

Re: Avoiding portals on route to destination

#2 Post by ezza »

Ermm.. i got an idea but its not so clever becoz I dont know how to write plugins. I just can illustrate the logical route into macro plugins.. now here is the idea(dont laugh :roll: )

Image

Note:
1. Centre coordinate of portal is (x y)
2. All the ABCD route is a tangent to the circle line (centre coordinate= (px, py)): $x = sqr(6**2 - ($y - py)**2) + px
3. The Diametre of the circle is 12 blocks
4. We need a) portal coordinate (x y), b) the target destination (x y)

In Theory:
1. The macro starts when we enter the yellow spot.
2. Macro getCoordinates will set A, B, C, D spot based on the +-6 blocks from x and y (square)
3. Macro bestDistance will determine which spot to choose (the nearest), so that we wont drop into the portal zone
4. Macro find3Distance is the main logic to solve the puzzle.

Ex: Target Location - Dark Green Spot. Let say we are in pink spot, step 3 above will pick spot D as the new spot to stand. Then step 4 will choose 3 nearest spots from A,B,C,D that is close to spot D (the spot we are standing now). So, the best 3 spots is A, D, C and the bestDistance now will choose C as our new spot.
Then culculate again which is the nearest spot from D, C, B and the result is for sure B (goto B). Then culculate again from C, B, A which is the nearest spot... now it is B spot is the nearest. At this point, if the nearest spot is equal to our current post... just continue the journey... it is safe now!

Route: Pink(Start) -> D -> C -> B -> Dark Green(End)

Code: Select all

if (blockDistance($char->{pos},$portal->{pos}) < 6) {
    my $target = "x y";     #the coordinate you wanna go in "x y" format
    Plugins::callHook('portal_avoid', {px => $portal->{'pos'}{'x'}, py => $portal->{'pos'}{'y'}, target => $target});
}

Code: Select all

automacro portalRouteAvoid {
	hook portal_avoid
	eval AI::inQueue("route")
	save px
	save py
	save target
	exclusive 1
	call avoid
}

macro avoid {
	$target = $.hooksave2
	
	call getCoordinates
	call bestDistance

	#go to nearest spot from our char 1st

  :start
	do move $coor
	pause 2
	if ($.pos = $coor) goto ok     
	#actually ($.pos = $coor) if statement is not nessessary coz OK will auto check if we really in $coor
	goto start

  :ok
	call find3Distance
	call bestDistance
	
	if ($.pos = $coor) goto start
	#($.pos = $coor) if statement is strictly nessessary 
  :end
	do move $target
}

macro find3Distance {
# Listing all the 3 best/nearest coordinates (A>B>C>D) and its distance to the $target loc.
# Its like return $_coordinates for sub find3Distance($_A, $_B, $_C, $_D,$_coor) in normal plugins
	do eval if ($_coor eq $_A) {@_c3 = ($_D, $_A, $_B)} elsif ($_coor eq $_B) {@_c3 = ($_A, $_B, $_C)} elsif ($_coor eq $_C) {@_c3 = ($_B, $_C, $_D)} elsif ($_coor eq $_D) {@_c3 = ($_C, $_D, $_A)} my @lines;foreach (@_c3) {my @_i = split(/ /, $_); my %_line; $_line{x} = abs($_target[0] - $_i[0]);$_line{y} = abs($_target[1] - $_i[1]); my $_d = sprintf("%.1f", sqrt($_line{x} ** 2 + $_line{y} ** 2));push @lines, $_i[0]." ". $_i[1] .", ". $_d;} $_coordinates = join("\n", @lines);
}

macro bestDistance {
# Choose the closest distance in $_coordinates and return the position value $coor (in macro var)
# Its like return $_coor (the best spot) for bestDistance($_coordinates) like using sub in normal plugins
	do eval my $_dist;my $_dist1;my @_line = split(/\n/,$_coordinates); foreach (@_line) {($_dist) = "$_" =~ /, (.*)/; if (!defined $_dist1) {$_dist1 = $_dist; ($_coor) = "$_" =~ /(.*),/;} elsif ($_dist < $_dist1) {$_dist1 = $_dist;($_coor) = "$_" =~ /(.*),/} } $::Macro::Data::varStack{coor} = $_coor; $::Macro::Data::varStack{dist} = $_dist1;
}

macro getCoordinates {
# Set the 4 coordinates A,B,C,D shown in the illustration.
	do eval @_target = split(/ /, $::Macro::Data::varStack{target}); ($_portalX, $_portalY) = ($::Macro::Data::varStack{'.hooksave0'}, $::Macro::Data::varStack{'.hooksave1'});$_A = ($_portalX - 6) . " " . ($_portalY + 6);$_B = ($_portalX + 6) . " " . ($_portalY + 6);$_C = ($_portalX + 6) . " " . ($_portalY - 6);$_D = ($_portalX - 6) . " " . ($_portalY - 6);@_c = ($_A, $_B, $_C, $_D);my @lines;foreach (@_c) {my @_i = split(/ /, $_); my %_line; $_line{x} = abs($::char->{'pos'}{'x'} - $_i[0]);$_line{y} = abs($::char->{'pos'}{'y'} - $_i[1]); my $_d = sprintf("%.1f", sqrt($_line{x} ** 2 + $_line{y} ** 2));push @lines, $_i[0]." ". $_i[1] .", ". $_d;} $_coordinates = join("\n", @lines);
}
macro find3Distance perl:

Code: Select all

if ($_coor eq $_A) {
	@_c3 = ($_D, $_A, $_B)
} elsif ($_coor eq $_B) {
	@_c3 = ($_A, $_B, $_C)
} elsif ($_coor eq $_C) {
	@_c3 = ($_B, $_C, $_D)
} elsif ($_coor eq $_D) {
	@_c3 = ($_C, $_D, $_A)
}

my @lines;
foreach (@_c3) {
	my @_i = split(/ /, $_);
	my %_line;
	$_line{x} = abs($_target[0] - $_i[0]);
	$_line{y} = abs($_target[1] - $_i[1]);
	my $_d = sprintf("%.1f", sqrt($_line{x} ** 2 + $_line{y} ** 2));
	push @lines, $_i[0]." ". $_i[1] .", ". $_d;
}

$_coordinates = join("\n", @lines);
macro bestDistance perl:

Code: Select all

my $_dist;my $_dist1;
my @_line = split(/\n/,$_coordinates);
foreach (@_line) {
	($_dist) = "$_" =~ /, (.*)/;
	if (!defined $_dist1) {
		$_dist1 = $_dist; ($_coor) = "$_" =~ /(.*),/;
	} elsif ($_dist < $_dist1) {
		$_dist1 = $_dist;($_coor) = "$_" =~ /(.*),/
	}
} 

$::Macro::Data::varStack{coor} = $_coor;
$::Macro::Data::varStack{dist} = $_dist1;
macro getCoordinates perl:

Code: Select all

@_target = split(/ /, $::Macro::Data::varStack{target});
($_portalX, $_portalY) = ($::Macro::Data::varStack{'.hooksave0'}, $::Macro::Data::varStack{'.hooksave1'});
$_A = ($_portalX - 6) . " " . ($_portalY + 6);
$_B = ($_portalX + 6) . " " . ($_portalY + 6);
$_C = ($_portalX + 6) . " " . ($_portalY - 6);
$_D = ($_portalX - 6) . " " . ($_portalY - 6);
@_c = ($_A, $_B, $_C, $_D);

my @lines;
foreach (@_c) {
 	my @_i = split(/ /, $_);
 	my %_line;
	$_line{x} = abs($::char->{'pos'}{'x'} - $_i[0]);
	$_line{y} = abs($::char->{'pos'}{'y'} - $_i[1]);
	my $_d = sprintf("%.1f", sqrt($_line{x} ** 2 + $_line{y} ** 2));push @lines, $_i[0]." ". $_i[1] .", ". $_d;
}

$_coordinates = join("\n", @lines);

Basically I just use distance as the main issue to calculate the route... it works in theory and with several test. But the test that i've done is not a portal ... I just take a random spot in a map assuming it is a portal :lol: . Then use a move command to let the bot across that spot and the result is impressive. But the main prob is I'm using a macro, so definitely not as good as a normal plugins outcome.

Well this is just an idea, if you think it is possible to coding it into normal plugins... you got my bless.. and if you dont... just skip this post .
sli
Perl Monk
Perl Monk
Posts: 810
Joined: 04 Apr 2008, 17:26
Noob?: No

Re: Avoiding portals on route to destination

#3 Post by sli »

I prefer the 9 lines of Perl.
cs : ee : realist
ezza
Developers
Developers
Posts: 109
Joined: 04 Apr 2008, 09:50

Re: Avoiding portals on route to destination

#4 Post by ezza »

sli wrote:I prefer the 9 lines of Perl.

Its not that I'm 100% dont know how to write plugins... I can write it into normal plugins if I want to. Actually, I'm just being lazy to write the header of the plugins... use this, use that, export this, import that. The macro plugins seem very friendly to me and I love it very much. If you prefer the 9 lines of the Perl which that means you dont like the 1 line Perl... as I said before "just skip my post" damn it! I got an idea here and pls dont argue about the coding style... just take the idea regarding which way point to use :roll: .
Darki
Been there done that!
Been there done that!
Posts: 143
Joined: 25 Oct 2008, 08:14
Noob?: No
Location: Spain, Madrid

Re: Avoiding portals on route to destination

#5 Post by Darki »

Ezza, I see your macro method very good, but maybe I have some kinda advice on it.

You say, first it'd go to the D spot, then chose another, and all to round the portal. Well, I was thinking that actually there's no need to go to the first spot.
For example, in your picture. You're in the, let's call it "area D", and you wanna go to the green spot. In your process, you'd go first to D spot, then C, then B.

Well, from the position you are, you wouldn't go into the portal even if you don't pass first through D, the straight route from the initial position to C is clear. Then, if the place where you are don't need to go into the yellow area again, so you'd make the bot go to 3 spots when what it really needs is to go to C spot and from it is possible to continue the route withpout "danger".

Maybe you should only calculate which is the closer spot to the are you are in the beggining, then if you have a "clear path" from there go ahead.

Maybe you though about this before, I don't know. Just suggesting. :oops:
ImageImageImage
ImageImageImage
ImageImageImage
ezza
Developers
Developers
Posts: 109
Joined: 04 Apr 2008, 09:50

Re: Avoiding portals on route to destination

#6 Post by ezza »

That is hard to play with a linear equivalent with the circle equivalent. The method that you use is same like what Bibian/dev might thinking at first... no wonder it stuck. The yellow area,Pink spot and Dark Green spot were just an illustration and probably not the actual size or in a perfect angle like you've seen. The portal area is not a big one like the illustration actually, if you go straight from danger spot to C.. you might fell into it. The idea is actually move along the square line A>B>C>D so that it wont/never fall into the hole. It took the D spot at 1st becoz it force to revert back the route direction from entering the portal.. like oopppsss, pheww very close :).



p.s: Anyway thanks for the feedback... atleast you understand what i'm saying :)

The hard way is to check whether move-along-vector (linear) wont clash with the circle area:
1. Linear: y = mx + c #A coor = 1, B coor = 2, the m = (y2-y1)/(x2-x1)
2. Circle: $x = sqr(36 - ($y - py)**2) + px #px = portal x, py = portal y
xiaoTing
Noob
Noob
Posts: 9
Joined: 24 Dec 2009, 10:48
Noob?: No

Re: Avoiding portals on route to destination

#7 Post by xiaoTing »

this code good, but some map if x+6 will be a wall block, because ytd i try on pay_fild08 from payon go out, den it cannot calculate x+6, so i think the x and y must be random number and check $field->isWalkable and also checkLineWalkable @@, and mandragora map more harder to check, because the x,y can be 12cell =.=", so if want walk away from portal maybe we do run out from portal 15~20cell

and one more thing is that, blockDistance($pos->{pos_to},$portal->{pos})

when we walking want to check the blockdistance between player and portal, it check too slowly, i trying that, type moving to portal and msg show me distance,
it wont show me, 10,9,8,7,6,5, it show me 10, later 3, but already go in portal jor =.=

Code: Select all

move 170 378
Calculating random route to: Prontera Field(prt_fild08): 170, 378
Portal Exist : prt_fild08 -> prontera (170, 378) - (0)
10 < 10.
10 < 10.
10 < 10.
10 < 10.
10 < 10.
10 < 10.
4 < 10.
Attemption to avoid portal on route to our destination(prt_fild08, 179, 365).
the blockdistance only can check while you stop moving wor, like that cannot use blockdistance oh

i think the best way maybe is saw portal straight walk far away until cannot see portal?

avoid portal also need to be no laggy, else when bot walk << it cannot direct move >> or stop, got delay when you move <<