Page 1 of 5

AI Question: get event name

Posted: 12 May 2010 12:32
by Lord Aro
on my AI that i'm (very slowly) making i have used the code from Rondje (and simpleai) to build the company's HQ

Code: Select all

function AroAI::BuildHQ() //from Rondje
{
if(AIMap.IsValidTile(AICompany.GetCompanyHQ(AICompany.COMPANY_SELF))) return;//from simpleai

// Find biggest town for HQ
local towns = AITownList();
towns.Valuate(AITown.GetPopulation);
towns.Sort(AIAbstractList.SORT_BY_VALUE, false);
local town = towns.Begin();

// Find empty 2x2 square as close to town centre as possible
local maxRange = Sqrt(AITown.GetPopulation(town)/100) + 5; //TODO check value correctness
local HQArea = AITileList();
HQArea.AddRectangle(AITown.GetLocation(town) - AIMap.GetTileIndex(maxRange, maxRange), 
AITown.GetLocation(town) + AIMap.GetTileIndex(maxRange, maxRange));
HQArea.Valuate(AITile.IsBuildableRectangle, 2, 2);
HQArea.KeepValue(1);
HQArea.Valuate(AIMap.DistanceManhattan, AITown.GetLocation(town))
HQArea.Sort(AIList.SORT_BY_VALUE, true);
for (local tile = HQArea.Begin(); HQArea.IsEnd(); tile = HQArea.Next())
{
if (AICompany.BuildCompanyHQ(tile)) 
	{AISign.BuildSign(tile, "AroAI HQ");
		return;
	}
}
the offending area is the:

Code: Select all

for (local tile = HQArea.Begin(); HQArea.IsEnd(); tile = HQArea.Next())
specifically the

Code: Select all

HQArea.IsEnd()
i have already changed it from

Code: Select all

HQArea.HasNext()
as that has been changed

the trouble is that whenever my ai runs now, it always fails to build an HQ
any comments?
i'm a real beginner at this, but i am learning, so please be patient :bow:

hope this makes some sort of sense,

EDITS: topic name change

Re: converting HasNext() to trunk

Posted: 12 May 2010 16:18
by Michiel
I think IsEnd() has the inverse meaning of HasNext(), so you'll need a "not" in the condition:

Code: Select all

for (local tile = HQArea.Begin(); !HQArea.IsEnd(); tile = HQArea.Next())

Re: converting HasNext() to trunk

Posted: 12 May 2010 20:20
by Zuu
Or you can use a foreach-loop.

Code: Select all

foreach (tile, _ in HQArea)

Mind the underscore (_). If you omit ", _", then you'll loop over all the values associated with the tiles, not the tiles themself.

Re: Lord Aro's coding problems

Posted: 13 May 2010 18:19
by Lord Aro
thanks chaps :roll:
i used Michiel's because it was easiest, although i should know that
you're still both awesome :bow:

Next Problem:
i want my ai to do something on a certain date - e.g. new years day
my current code is something like:

Code: Select all

...
if (AIDate.GetMonth==1);
if (AIDate.GetDayOfMonth==1);
{AILog.Info("Happy New Year!");}
...

Re: Lord Aro's coding problems

Posted: 13 May 2010 19:21
by Zuu
Don't put a semicolon after a if, for or while statement unless you know what you are doing. They are in most cases evil!

An if statement will execute the next line of code or block if the condition is true. A semicolon after the ending bracket will create a statement that do nothing. That results in the block of code after your if-statement always being executed.

This is ok:

Code: Select all

if (a == b)
{
  do_something();
}
This is also ok:

Code: Select all

if (a == b)
  do_something();
And this is ok:

Code: Select all

if (a == b) do_something();

This is how your code looks. It is valid code, but the do_something function will always get called even if a is not equal to b. This because of the empty statement at the same row as your if statement.

Code: Select all

if (a == b);
  do_something();

This is how I would re-write your code:

Code: Select all

if (AIDate.GetMonth() == 1 && AIDate.GetDayOfMonth() == 1) {
  AILog.Info("Happy New Year!");
}
While re-writing your code I also noticed that you forgot the empty brackets after GetMonth and GetDayOfMonth. In contrast to Delphi, VB(A), Ruby and some other languages, you must always include the brackets after the function name of the function that you want to call, even if you don't send any parameters. Otherwise you don't call the function.


Another problem with your code is that unless you do that check several times a day, you will have a chance of not finding out that there is a new year. The opposite could also become a problem. If you make that check more than once a day, then you will do your actions several times that day.

Re: Lord Aro's coding problems

Posted: 14 May 2010 10:16
by Lord Aro
thanks zuu :bow:
i really should make sure of silly mistakes like missing () out before i post :rolleyes:
i was thinking of having a looping function, not unlike the while(true) bit in Start()
i'll see if that works or whether it uses up too many opcodes (or whatever, im not sure what im talking about really)

more silly and basic problems coming soon! :lol:

Re: Lord Aro's coding problems

Posted: 14 May 2010 15:50
by Lord Aro
problem: your script doesn't work! :(

debug=

Code: Select all

dbg: [ai] [1] [S] Your script made an error: wrong number of parameters
dbg: [ai] [1] [S] 
dbg: [ai] [1] [S] *FUNCTION [Start()] AroAI_RC1/main.nut line [22]
dbg: [ai] [1] [S] 
dbg: [ai] [1] [S] [types] INSTANCE
dbg: [ai] [1] [S] [this] INSTANCE
dbg: [ai] The AI died unexpectedly.
line 22 on my script=

Code: Select all

if (AIDate.GetMonth() == 1 && AIDate.GetDayOfMonth() == 1) {
:? :bow: etc. :lol:

Re: Lord Aro's coding problems

Posted: 14 May 2010 15:54
by Yexo
See the docs: http://noai.openttd.org/docs/trunk/classAIDate.html

Both GetMonth() and GetDayOfMonth() expect a date as parameter.

Re: Lord Aro's coding problems

Posted: 23 Jun 2010 12:17
by Lord Aro

Code: Select all

Debugs.Info("Your Version is " + ((version & (15 << 28)) >> 28) + "." + ((version & (15 << 24)) >> 24) + " Build " + ((version & (15 << 20)) >> 20) + "" + (((version & (1 << 19)) >> 19)?" stable release, ":" r") + ((version & ((1 << 18) - 1))));
i have copied this code from Chopper - i've changed the words a bit, but it's essentially the same
the main problem is that i'm not sure what it does, if someone could explain in words what it's doing, that would be much appreciated :roll:
i would like it to eventually display the version number, e.g.

Code: Select all

Your Version is r20000
[or]
Your Version is 1.02
[or even]
Your Version is r20000 ez r45
is that last one possible?
is there an esay way to get whatever the name-version of the current openttd playing? we can find out prety easily (look at title bar)

Re: Lord Aro's coding problems

Posted: 23 Jun 2010 12:37
by planetmaker
Lord Aro wrote:

Code: Select all

Debugs.Info("Your Version is " + ((version & (15 << 28)) >> 28) + "." + ((version & (15 << 24)) >> 24) + " Build " +
 ((version & (15 << 20)) >> 20) + "" + (((version & (1 << 19)) >> 19)?" stable release, ":" r") + ((version & ((1 << 18) - 1))));
The code pasted will give you either "1.0 Build 2 stable release 20000" or "1.1 Build 0 r20009" for the current stable and somewhat current nightly respectively. If you replace the " Build " by a "." then you'll get a format more well known ;-)

Re: Getting openttd version number

Posted: 23 Jun 2010 15:40
by Zuu
You might also want to checkout AILib.Common which has a function for getting the OpenTTD version:

Code: Select all

    /**
     * Get current OpenTTD version.
     * @return A table with separate fields for each version part:
     * - Major: the major version
     * - Minor: the minor version
     * - Build: the build
     * - IsRelease: is this an stable release
     * - Revision: the svn revision of this build
     */
    static function GetVersion()
( Copied from http://noai.openttd.org/svn/lib-common/trunk/main.nut )

Re: Getting openttd version number

Posted: 24 Jun 2010 05:16
by Lord Aro
thanks for that, i'll have a look at it
out of interest, what does either of them display if playing something such as cargodist?
can you possibly get it to display cargodist?

Re: Getting openttd version number

Posted: 10 Jul 2010 19:16
by Lord Aro
next question:

how to get a list of towns within 50-ish tiles?
something to do with AIAbstractList i know

Re: get list of towns within certain distance of town or other

Posted: 10 Jul 2010 19:22
by Kogut
your_valuated_town_list.KeepBelowValue(50);

Re: get list of towns within certain distance of town or other

Posted: 11 Jul 2010 05:12
by Lord Aro
Kogut wrote:your_valuated_town_list.KeepBelowValue(50);
yes but what's: your_valuated_town_list?

Re: get list of towns within certain distance of town or other

Posted: 11 Jul 2010 08:24
by Zuu
Take a look here: http://wiki.openttd.org/AI:Lists

(also it is a good idea to read through all the NoAI-pages in the wiki as they contain useful information)

Re: get list of towns within certain distance of town or other

Posted: 12 Jul 2010 18:13
by Lord Aro
1. ok, here's my code for my busroutebuilder

Code: Select all

import("pathfinder.road", "RoadPathFinder", 3);

class builder
 {
  constructor()
  {
  }
  town_list = 0;
 }

function builder::BuildBusRoute()
 {
  Debugs.Info("Planning on building bus route");
  AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD);
  town_list = AITownList();
  town_list.Valuate(AITown.GetPopulation());
  town_list.Sort(AIAbstractList.SORT_BY_VALUE, false);

  local town_a = town_list.Begin();
  local town_b = town_list.Next()
  if(GetDistanceManhattanToTile(town_a,GetTile(town_list.Next())) > 50)
  {
   town_list.RemoveValue(town_b);
    return;
  }
  else
  {
   *build bus route* //this definitely works
  }
it comes up with the error:

Code: Select all

Your script made an error: the index 'town_list' does not exist
it also points to line 13, but thats obvious due to that being the first place 'town_list' is mentioned


2. Also, could someone explain to me what the point of Stop(); and the constructor bit of the class is, becasue i don't know :]

Re: get list of towns within certain distance of town or other

Posted: 12 Jul 2010 19:27
by Morloth
1) I think the answer to this question is partially explained by your second question regarding the use of the contructor. I expect that you call the function like so:

Code: Select all

builder.BuildBusRoute();
which will not work. Squirrel is an object oriented language which means that every class like yours above are a blueprint. In order to use them you'll have to make an explicit instantiation of it like so:

Code: Select all

local bus_builder = builder();
When an instantiation is created the constructor is called. This is usually used to prepare the instantiation for usage. In your case you could - for example - construct the town_list. In brief this is the proper use of the above class:

Code: Select all

local bus_builder = builder();
bus_builder.BuildBusRoute();
Alternatively you could also make your function static which means it can be called without having to instantiate the class, but that's probably not what you want in this case.

Hope this helps,
Bram

Re: get list of towns within certain distance of town or other

Posted: 12 Jul 2010 19:34
by Kogut
bad

Code: Select all

class builder
 {
  constructor()
  {
  }
  town_list = 0; //you mess with undeclared variable!
 }
good

Code: Select all

class builder
 {
town_list = null;
  constructor()
  {
  }
  town_list = 0;
 }

Re: get list of towns within certain distance of town or other

Posted: 12 Jul 2010 21:33
by Zuu
Kogut wrote: good

Code: Select all

class builder
 {
town_list = null;
  constructor()
  {
  }
  town_list = 0;
 }
better

Code: Select all

class builder
 {
town_list = null;
  constructor()
  {
    town_list = 0;
  }
 }
Do the initialization inside the constructor body. The "town_list = null;" is good to define the variable but you need to clear it inside the constructor to make sure it get cleared for each instance that is created of this class.

If you only create one builder, then you probably won't note any difference, but if you create many, then it becomes important to do the initialization properly in the constructor.