NoAI Branch - An AI Framework

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Locked
User avatar
GeekToo
Tycoon
Tycoon
Posts: 961
Joined: 03 Jun 2007 22:22

Re: NoAI Branch - An AI Framework

Post by GeekToo »

kuifware wrote: BuildRoad and BuildRoadFull require that start != end, so you can't build individual road segments on one tile (without also building on neighbouring tiles as well).
True, but it also does not make sense to build a road that does not connect to a neighbour since it will never be used.
kuifware wrote:
  • When you want to connect a road depot or station, you need to build a road segment which will be replaced by the depot/station. A slight waste of money.
I see your point, I would have to check whether this is true in execute mode. In test mode it probably wastes money, because no changes are made to the map in testmode, so the full cost will be counted. In execute mode the changes are made, I don't know if a full tile is charged in that situation. If it is, a small gain in cost is possible, but it would be a rather insignificant one.
kuifware wrote:
  • More interesting is the possibility to use BuildRoadSegments in AITestMode. It makes it much easier to estimate the costs of a road path. (Using BuildRoad in AITestMode won't allow you to do that because then you'd typically double-count the cost of clearing the tiles and the costs of building foundations. Workarounds for this are less efficient and prone to bugs.)
In my first efforts I did use the testmode, but did find out that it is rather useless in predicting whether a tile can be built or not: no changes are made to the map, so a piece of road that can be built in testmode, can be not buildable in execute mode, because the route did create a foundation in the previous tile, making all your efforts in planning the route ( cost ) useless. Because there is also no function to retrieve the roadbits that are already present on a tile, there is no easy way around this. So, until there is a function to query the road segments of a tile that you requested, I switched to another strategy: before building, loan the maximum amount you can get, and start doing the real thing. When money does not suffice, stop building, and wait until it does and continue. If it suffices, pay back the loan after building.
kuifware wrote: If you want to know how much funds your competitor can raise, you need to know its BankBalance and MaxLoanAmount - its LoanAmount.
But, unless you want to buy out, like mentioned above, why would you want to know that? I.e. in what way would that influence the behaviour of your AI? Imo, most AIs that are currently built are still struggling with vehicle management, path finding etc. Buying out other companies is at another strategic level, that, at least my AI is not ready for yet. I'm not saying it's an invalid request, I just would like to understand the thought behind it.
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

Building a single road segment would be useful for having a dead end to reverse in. I can imagine it also is good for test building and stuff.

I also updated the "FAQ" wiki page: http://wiki.openttd.org/index.php/AI:Need_To_Know
Finaldeath
TrueBrain
OpenTTD Developer
OpenTTD Developer
Posts: 1370
Joined: 31 May 2004 09:21

Re: NoAI Branch - An AI Framework

Post by TrueBrain »

I ask you all to be very careful in your additions to the wiki. Today I spend a great deal of my time on removing and correcting wrong and untrue entries created there. Please verify things by either asking it here, or better, by asking it in our IRC channel #openttd.noai. Many things in the API are there for a reason, and many things are pointed out in this thread. To summarize some of the most important things I removed/changed on the wiki:

Never believe a CargoID stands for something. If you make your AI to use CargoID '0' hardcoded, I can promise you it won't work with a very simple NewGRF. Use the API query function to find a cargo you like, based on profit, freight, ... In general, avoid as much hardcoded values as possible. They are bad, and NewGRFs can make sure your AI no longer works. You kind of want to avoid that ;)

Pressing Reload AI in the AI Debug Window kills the company the AI was controlling, removing all property, and starting a new company controlled by the same script the old company was. At this stage the script is reloaded from disk. So it is enough to make changes to your AI, and hit Reload AI. No need to start a new map or anything silly like that.

The wiki reflects the latest state of the NoAI branch, not some long long long lost version :)

Avoid using 'print'. Use AILog::Info or AILog::Warning, or when you really want to: AILog::Error. 'print' will be removed at some point (although currently it is hardcoded in Squirrel).

Nevertheless, I thank you all for your contributions to the wiki, and to the NoAI branch :) Keep up the good work!
The only thing necessary for the triumph of evil is for good men to do nothing.
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

GeekToo wrote:
kuifware wrote: If you want to know how much funds your competitor can raise, you need to know its BankBalance and MaxLoanAmount - its LoanAmount.
But, unless you want to buy out, like mentioned above, why would you want to know that? I.e. in what way would that influence the behaviour of your AI? Imo, most AIs that are currently built are still struggling with vehicle management, path finding etc. Buying out other companies is at another strategic level, that, at least my AI is not ready for yet. I'm not saying it's an invalid request, I just would like to understand the thought behind it.
Suppose you want to compete with some competitor for some industries' cargo. Which competitor would you choose? Do you want to knock out a small opponent or do you want to reduce the power of your biggest competitor? Certainly you want to take into account the cash (and loan) situation of your competitors to determine who is weak and who is strong.

But my preference is to have HasRoadSegments first of course :wink:

Bug report: I noticed that in the latest SVN revision (r13197-noai) you can crash OpenTTD by starting an AI, issuing the restart command in the in-game console and starting an AI again:
---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Assertion failed!

Program: C:\Games\OpenTTDNoAI\openttd.exe
File: /compile_farm/openttd/noai/compile.../ai_threads.cpp
Line: 370

Expression: thr == NULL

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts

(Press Retry to debug the application - JIT must be enabled)
---------------------------
Abort Retry Ignore
---------------------------
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

I think it's useful to have those numbers Truelight...at least for beginners.

You have, after all, "hardcoded" it into the default WrightAI. For beginners, it's a big "need to know" bit of info which is hidden in some source header file. With no knowledge of it, and without looking rather deeply at how on earth it is meant to work, it looks impossible from the outset to know what types of cargo can be used - eg, for simple bus routes.

Who knows how you'd determine how to even start a bus route without the knowledge that 0 was passengers when searching for a good station location. ;)

If the API documentation was improved, both to include some information on what on earth a "cargoID" represents (an integer right? oh, wait, no, an indexed-0 integer... ;) ), it'd be much more clear. Same goes with some others I was tempted to add info on :D The WrightAI would also have to be changed to include explicit notes that it will break, like you said, when the GRF files change.

I also think it'll be a long while before you ever get non-hardcoded cargo feeder industries. The Arid and Arctic climates are, from my limited experience, full of these, even for passenger growth. I guess it'll be a case of building up a super array of the "routes" of cargo, and what stations are used for the road vehicles, and lots of other stuff :) - however, much too much for a beginner.

I admit some of the other errors however. I should have tested the debug kill, my AI didn't create much so I didn't notice, heh (I might have just tested it with my non-building test AI actually). I put print there as it is used in the example so I put it there with a note, rather then explicitly saying it shouldn't be used ;)

Finally; why did you remove the "developer 2" stuff? I mean, is that fixed or something? It's the only way to see compiling errors currently I think? (the "hack" with sq.exe didn't work for me, there was no command line output even when the files had an error). The -d parameter also does need to be put twice in windows, since I suspect you're a Linux user, to have both the AI debug and the separate command line window in Windows - otherwise, well, it's a rather useless addition to just use -d by itself. I'll check these out tomorrow if you don't know.

I'll update the wiki more in the future, but obviously I can't know exactly what is intended versus what is implemented (like the "developer 2" stuff), and I did ask on IRC some questions, you were there ;)
Finaldeath
TrueBrain
OpenTTD Developer
OpenTTD Developer
Posts: 1370
Joined: 31 May 2004 09:21

Re: NoAI Branch - An AI Framework

Post by TrueBrain »

Finaldeath wrote:I think it's useful to have those numbers Truelight...at least for beginners.

You have, after all, "hardcoded" it into the default WrightAI. For beginners, it's a big "need to know" bit of info which is hidden in some source header file. With no knowledge of it, and without looking rather deeply at how on earth it is meant to work, it looks impossible from the outset to know what types of cargo can be used - eg, for simple bus routes.

Who knows how you'd determine how to even start a bus route without the knowledge that 0 was passengers when searching for a good station location. ;)

If the API documentation was improved, both to include some information on what on earth a "cargoID" represents (an integer right? oh, wait, no, an indexed-0 integer... ;) ), it'd be much more clear. Same goes with some others I was tempted to add info on :D The WrightAI would also have to be changed to include explicit notes that it will break, like you said, when the GRF files change.

(...)
WrightAI should never contained the hardcoded value. This indeed is bad, and a clear bug. It is corrected as we speak. Also, I finally found the time to add a more explaining text at the cargo section on the wiki, as clearly you missed the point of usage ;) I hope this clears it up a bit, and shows you there is no need to do any weird stuff, or complex functions, or what ever. Finding a good cargo is very straight forward. People just need to forget to silly idea to control what cargo the AI will pick. Let the most profitable cargo win, not the cargo you think is best. It really makes your AI more powerful :)
The only thing necessary for the triumph of evil is for good men to do nothing.
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

Thanks a lot, that will help anyone wanting to start :)

The main time you might want specifically passengers, although mail works to a degree but is much slower, is to grow a town for future big airports and to accept goods and suchlike, but there might be other times. Might need to have some kind of list filter on "What grows towns" (and that might mean it returns goods on Arid / Arctic maps?). edit: - this will be added to the "TODO" list it seems :)
Finaldeath
User avatar
GeekToo
Tycoon
Tycoon
Posts: 961
Joined: 03 Jun 2007 22:22

Re: NoAI Branch - An AI Framework

Post by GeekToo »

TrueLight,

Considering this ( imo correct ) note on the api-doc

GetCargoLabel ( CargoID cargo_type ) [static]

Note:
Never use this to check if it is a certain cargo. NewGRF can redefine all of the names.


I think your solution in WrightAI:

Code: Select all

for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
			if (AICargo.GetCargoLabel(i) == "PASS") {
				this.passenger_cargo_id = i;
			}
		}

is not less of a bug than comparing against the 0 value. I tried to solve this (that is, finding passenger cargo id ) by checking with the IsFreight function.But that does also return false on mail cargo( and mail trucks cannot go to busstations). So maybe the IsFreight function can return true for mail, then there is a real solution.

So far the nagging. I'd also like to compliment you with the development of this branch. Last night I put up a battle between WrightAI and my bus loving AI (working name Convoy ), on a flat scenario ( wright couldn't find a spot for anairport in the test scenario ).
I expected it to be boring, to just watch 2 AIs battling, but it was a very exciting fight, with no definitive winner after 5 years. I had a lot of fun watching the fight, and it gave me inspiration for A LOT of things I still have to improve.

Thanks for making this experience possible !
TrueBrain
OpenTTD Developer
OpenTTD Developer
Posts: 1370
Joined: 31 May 2004 09:21

Re: NoAI Branch - An AI Framework

Post by TrueBrain »

GeekToo wrote: (..)

So far the nagging. I'd also like to compliment you with the development of this branch. Last night I put up a battle between WrightAI and my bus loving AI (working name Convoy ), on a flat scenario ( wright couldn't find a spot for anairport in the test scenario ).
I expected it to be boring, to just watch 2 AIs battling, but it was a very exciting fight, with no definitive winner after 5 years. I had a lot of fun watching the fight, and it gave me inspiration for A LOT of things I still have to improve.

Thanks for making this experience possible !
*snif* it has been a while since someone said such nice words .. I am all emotional now .. thank you GeekToo! *snif*

Now show us your AI and let us enjoy the moment too :)
GeekToo wrote:TrueLight,

Considering this ( imo correct ) note on the api-doc

GetCargoLabel ( CargoID cargo_type ) [static]

Note:
Never use this to check if it is a certain cargo. NewGRF can redefine all of the names.


I think your solution in WrightAI:

Code: Select all

for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
			if (AICargo.GetCargoLabel(i) == "PASS") {
				this.passenger_cargo_id = i;
			}
		}

is not less of a bug than comparing against the 0 value. I tried to solve this (that is, finding passenger cargo id ) by checking with the IsFreight function.But that does also return false on mail cargo( and mail trucks cannot go to busstations). So maybe the IsFreight function can return true for mail, then there is a real solution.
First off, Rubidium did the commit (mwhahaha). Second, they told me NewGRF defined in their specification that the label PASS should be used for passengers, always and always. But that I stated in the wiki :) Of course this won't work for tourist, and I don't know what more. So yeah, you are completely right, and I don't like it either, but there seems to be no other way. Mail is the most logic cargo of moving around (as it really makes more profit per cargo-unit)... but planes that only do mail is just silly :) I guess a typical problem of balancing.. but again: you are absolutely 100% correct :) At least looking for PASS is less error-prune than looking for '0' ;)

Oh, and IsFreight means that the cargo goes to or from an industry, nothing else. So Mail can never be a Freight... sad sad world :) (how else would you find out what you have to move from town to town ;)).
The only thing necessary for the triumph of evil is for good men to do nothing.
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

Once I've implemented some stuff, knowing the segregation between buses and trucks being the station type, and once I learn more about the NewGRF stuff probably a solution function can be found to sort it better. I've got to think on this myself, since it's a valid point, and I am sure there is a solution somewhere.

At least == "PASS" is good enough for now. Better then 0 anyway.
Finaldeath
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

TrueLight wrote: Oh, and IsFreight means that the cargo goes to or from an industry, nothing else. So Mail can never be a Freight... sad sad world :) (how else would you find out what you have to move from town to town ;)).
Thanks for clarifying this. But oil rigs also produce/accept passengers. It appears the is_freight flag is used only for 'heavy freight trains' and something with liveries in the OpenTTD source code. Perhaps a clarification of the is_freight flag can be added to the API docs :).

On the other hand, in roadveh_cmd.cpp I see some occurrences of

Code: Select all

RoadStopType type = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
Some suggestions for the API:
  • AICargo.GetCargoClasses(cargoID) + adding an enumeration for the CC_* constants (from newgrf_cargo.h). AFAIK this is NewGRF-safe and is the way OpenTTD deals with trucks/busses internally.
  • AICargo.GetRoadStopType(cargoID)
TrueBrain
OpenTTD Developer
OpenTTD Developer
Posts: 1370
Joined: 31 May 2004 09:21

Re: NoAI Branch - An AI Framework

Post by TrueBrain »

kuifware wrote: On the other hand, in roadveh_cmd.cpp I see some occurrences of

Code: Select all

RoadStopType type = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
Some suggestions for the API:
  • AICargo.GetCargoClasses(cargoID) + adding an enumeration for the CC_* constants (from newgrf_cargo.h). AFAIK this is NewGRF-safe and is the way OpenTTD deals with trucks/busses internally.
  • AICargo.GetRoadStopType(cargoID)
Brilliant! I just added code for that in the API. Now lets all use AICargo.HasCargoClass() to find what ever type of cargo you are looking for :) Tnx a bunch kuifware, glad someone knows NewGRFs better than I do :) Hehe!

For GetRoadStopType there is no need for a function. If the cargo is in cargo class PASSENGERS, you need a bus-station, else a truck station. Easy as pie.
The only thing necessary for the triumph of evil is for good men to do nothing.
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

Great stuff :)
Finaldeath
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

TrueLight wrote:Brilliant! I just added code for that in the API. Now lets all use AICargo.HasCargoClass() to find what ever type of cargo you are looking for :) Tnx a bunch kuifware, glad someone knows NewGRFs better than I do :) Hehe!
Thanks for adding it. When I was looking at the source code I just happened to stumble onto the cargo classes member accidentally. After some grep's on the source code I found out that it was exactly what we needed :)
User avatar
GeekToo
Tycoon
Tycoon
Posts: 961
Joined: 03 Jun 2007 22:22

Re: NoAI Branch - An AI Framework

Post by GeekToo »

TrueLight wrote:[
Now show us your AI and let us enjoy the moment too :)
OK, here it is: Convoy (the bus loving AI)

Features:
-Uses buses only
-Pathfinding is 'curvy', straight roads would be better performancewise, but I don't like having only straight roads
-Completely written in Squirrel, no patches

Installation:
-Compatible with r13219 (thanks for solving the passenger class problem)
-Since this week it is possible to use the tarloader to load the AI, so installation is extremely easy:
copy the tar to the bin/ai directory ( no need to untar ). Ready!
-Start openttd.
-To set up a battle load a scenario, or a new game ( if you're battling with Wright, choose a very flat map )
-Press the ` key (left of 1), and enter start_ai WrightAI <enter>, start_ai Convoy <enter>
-Press the ` again to close the console

Have fun !


I've chosen an iterative approach: first create a working AI that is playable, although many parts are not optimal.
So there's a rather long todo list still, but the AI should already be nice to compete against.

ToDo:
-Improve pathfinder: A* is not completely implemented, shorter routes on the openlist are disregarded
-Improve pathfinding on slopes, sometimes connections on slopes are failing
-Improve town coverage, only one station per town is build, add intratown lines
-Optimize time performance
-Line building: currently only unused towns are connected, which is ok for the first few years, but after that, no unused towns can be found, and connections between lines must be added
- more comments, use some requires
-etc etc

Goals:
-My goal is not to create the best performing AI financially (I'm not taking part in any challenge), but to create an AI that human players like to play against. So remarks about the gameplay are welcome.
-Second goal: To improve my Object Oriention skills. I am pretty experienced in plain C programming, but in OO programming I consider myself a novice. So any comments on how to improve the OO design would be highly appreciated, I might learn a thing or two. And the best way to learn is to start doing it.

Licence:
Don't know much about that, GNU GPL is fine I think. Meaning: feel free to use or modify any of my code ( a link would be nice ), or better, improve and republish it. I think it is be possible to create a nice AI by the OTTD community, using the best open source practices.
I thank TrueLight and Zuu: I re-used some functions of Wright and Clueless ( if that's a problem, I'll rewrite them, and yeah, I know, I should have asked beforehand :mrgreen: )
Attachments
Convoy.tar
(30 KiB) Downloaded 162 times
Convoy.tar
Convoy v1.1
(40 KiB) Downloaded 147 times
Last edited by GeekToo on 25 May 2008 21:37, edited 1 time in total.
Finaldeath
Engineer
Engineer
Posts: 72
Joined: 09 Apr 2006 23:49
Location: UK
Contact:

Re: NoAI Branch - An AI Framework

Post by Finaldeath »

Put it on fast forward - I like the idea of building forwards and putting a depot in each town ;) It just for some reason only used 3 of it's built routes and swarmed them with buses, which is a bit odd, when it had 100,000 in the bank (with still a 510,000 loan that is)

In any case, nice work :D
Finaldeath
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

Nice to see your AI!
GeekToo wrote: Licence:
Don't know much about that, GNU GPL is fine I think. Meaning: feel free to use or modify any of my code ( a link would be nice ), or better, improve and republish it. I think it is be possible to create a nice AI by the OTTD community, using the best open source practices.
I thank TrueLight and Zuu: I re-used some functions of Wright and Clueless ( if that's a problem, I'll rewrite them, and yeah, I know, I should have asked beforehand :mrgreen: )
That puts up a general question about licenses: doesn't the fact that OpenTTD is licensed under the GPL imply that our AIs must be released under the GPL?

Please note that the GPL forces that derivative works are also released under the GPL (or at least the license should not impose "further restrictions on the rights granted by the GPL"); this is called copyleft. Since WrightAI is GPL, your code should now be as well ;) (unless you rewrite the code that you borrowed from it).

There are also other open source licenses that do not impose copyleft and that are compatible with the GPL, such as the modified BSD and Expat (MIT) licenses. See http://www.fsf.org/licensing/licenses/.
Rubidium
OpenTTD Developer
OpenTTD Developer
Posts: 3815
Joined: 09 Feb 2006 19:15

Re: NoAI Branch - An AI Framework

Post by Rubidium »

kuifware wrote:That puts up a general question about licenses: doesn't the fact that OpenTTD is licensed under the GPL imply that our AIs must be released under the GPL?
Technically all AIs made using the NoAI framework are GPL [1]. You are however not required to release your AI [2]. When you disclose your AI to someone else that person is allowed to redistribute it, but the person is also allowed to not redistribute [3].

1. http://www.gnu.org/licenses/gpl-faq.html#OOPLang
2. http://www.gnu.org/licenses/gpl-faq.htm ... stedPublic
3. http://www.gnu.org/licenses/gpl-faq.htm ... emandACopy

But I am not a lawyer, so when you need absolute certainty you need to talk to a real lawyer.
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

Rubidium wrote: Technically all AIs made using the NoAI framework are GPL [1]. You are however not required to release your AI [2]. When you disclose your AI to someone else that person is allowed to redistribute it, but the person is also allowed to not redistribute [3].
But I am not a lawyer, so when you need absolute certainty you need to talk to a real lawyer.
Thanks for clarifying this. the When I release my AI to the public, I will do it according to the GPL conditions. (I do participate in the TJIP Challenge and now I know it is not in conflict with the GPL to keep my code private.)
kuifware
Engineer
Engineer
Posts: 26
Joined: 17 May 2008 21:10

Re: NoAI Branch - An AI Framework

Post by kuifware »

Are const and enum statements supported in Squirrel code? The Squirrel language manual describes these statements, but OpenTTD gives me a compile error ('Your script made an error: end of statement expected (; or lf)').

I am aware that consts and enums are handled at compile time in Squirrel, so it wouldn't work very well in conjunction with the require function.
Locked

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 43 guests