Nanoships Strike Force oneYear 2357.. The battle for the Belt seamed over. The Federation of Free Nations had lost. But a breakthrough in nanotechnology made the conventional Warships vulnarable. The future of space war begins...Sofisticated autonomous nanoship factories produce and maintaine clouds of nanoships. Theese can attack defend and harvest resources.

In early 2016 I started (the attempt) to code a midage battle simulation (@RockTheSchock: Do you remember? :-) ) This is the latest test run, where you can see 1600 warriors armed with halberds (white pixels) fighting against 300 warriors armed with muskets (green pixels) on a randomly sized battlefield (every red pixel is a dead or incapacitated warrior). Every warrior is an autonomous acting object ("Type tKrieger", searching the nearest enemy, moving towards him and beginning to fight as soon as he gets into the reach of the weapon). Is that enough to call it "AI"?

This project stuck when I realised that the same framework could be used to code one of my favoured propositions: A flight operator simulation. It's nearly done now, the only thing yet missing is the speech of the radio communication.

BasicCoder2 wrote: From what I could see nano45 was just another shoot up game. There was nothing there to capture my interest.

paul doe replied: What would capture your interest then, concretely? Flashy/stylized graphics? Fast gameplay? It would be nice to know what everyone thinks about this, so we can evolve a design.

I added #lang "fblite" to NanoHost.bas as you suggested and it ran ok so I have some idea now of the game in question. So I assume here anyone can add their own AI driven spaceship to test in combat? That might be an interesting programming problem.

What would capture my interest? In truth I never purchased the C64 or PC to play games. However I did recognize the programming skill and creativity that went into making these games. Also writing simple games is probably an easy fun way to learn the basics of a programming language for those people without a deep mathematical background. So programming a game is of more interest than actually playing one.

When I did have a go at some of the games I usually became bored long before I could ever learn the key controls to play fast enough not to end up losing. On the Amiga I think the FA/18 Interceptor was the most interesting game as I had found learning to fly under the Golden Gate Bridge and then over Alcatraz was fun and then learning to land on the air craft carrier without coming to grief. I thought it would be fun to be able to write such 3d simulations.

With the nanoShips game I think it could be enhanced if the AI had to deal with more than one other ship, asteroid storms or maybe gravity curving the path of a missile. The tank game would have had buildings to use as a tactical advantage, maybe trees to hide behind or even smoke screens. I see in one game you could drop landmines behind in the hope the enemy would drive over one.

RockTheSchock wrote:Nanoships Strike Force oneYear 2357.. The battle for the Belt seamed over. The Federation of Free Nations had lost. But a breakthrough in nanotechnology made the conventional Warships vulnarable. The future of space war begins...Sofisticated autonomous nanoship factories produce and maintaine clouds of nanoships. Theese can attack defend and harvest resources.

Nice name, I added it to the random generator =DI love this premise, it's pretty cool and sparks some very interesting ideas! By all means, continue =D

grindstone wrote:Just as a supply of ideas:

Nice. I don't understand german, unfortunately, but the code is pretty clear.

grindstone wrote:This project stuck when I realised that the same framework could be used to code one of my favoured propositions: A flight operator simulation. It's nearly done now, the only thing yet missing is the speech of the radio communication.

Would love to see it. Once this framework is in a usable state, we can start to explore other ideas too =D

BasicCoder2 wrote:I added #lang "fblite" to NanoHost.bas as you suggested and it ran ok so I have some idea now of the game in question. So I assume here anyone can add their own AI driven spaceship to test in combat? That might be an interesting programming problem.

Yep, that was the original idea. As coderJeff stated early, the idea was good but the implementation was brittle, so he wants to (essentially) write a more robust and flexible one.

BasicCoder2 wrote:What would capture my interest? In truth I never purchased the C64 or PC to play games. However I did recognize the programming skill and creativity that went into making these games. Also writing simple games is probably an easy fun way to learn the basics of a programming language for those people without a deep mathematical background. So programming a game is of more interest than actually playing one.

Indeed. I think that most of us started programming because we played some cool games, and then learned that you could do it, too! As for the fun factor, I think that we'll be able to accomodate everyone =D

BasicCoder2 wrote:When I did have a go at some of the games I usually became bored long before I could ever learn the key controls to play fast enough not to end up losing.

Do you like RPGs? Or roguelikes? Perhaps something with a slower pace. Of course, programming the AIs is a fun experience, too (if you're that kind of geek =D)

BasicCoder2 wrote:With the nanoShips game I think it could be enhanced if the AI had to deal with more than one other ship, asteroid storms or maybe gravity curving the path of a missile. The tank game would have had buildings to use as a tactical advantage, maybe trees to hide behind or even smoke screens. I see in one game you could drop landmines behind in the hope the enemy would drive over one.

Yes, multiple AIs fighting against each other is contemplated in the design (will be more of an 'arena' than a 'duel'). The asteroid storms and gravity curving were interesting ideas. Duly archived. Keep them coming =D

You already can, except of the speech it works fine (and yet stole several hours of my lifetime from me when I play... ehm, tested it, it's an excellent concentration exercise :-D ). Just download the archive, unzip it and compile the source. (Btw: This source is in english)

Brief instruction:

- To launch a plane, click at one of the yellow entries of the list on the right (wait for the radio communication to be done, it is shown at the bottom of the screen. After the pilot has confirmed the order, the plane icon appears on the runway).- To turn, touch the plane icon and click left for turning left or click right for turning right, once for every 45 degrees.- The tag of the plane shows the destination, the actual altitude and the actual speed. If you touch it with the cursor, it displays the target altitude/speed, left click to increase, right click to decrease.- The tag can be moved around the plane icon with the mouse wheel. - The plane has to leave the screen at the exit point of the destination slot at an altitude of 5000 feet, a speed <= 400 knots and heading perpendicular to the screen border.- Press "P" to pause the game.- Press the space bar to end the game. The actual situation is stored in a file,so you can resume it at the next start of the prog.

Indeed, I read once that they are only allowed 3 conflicts per year. Now that's what I'd call taxing =D Looks really nice, and had a good time playing it. I observed however that the game keeps counting conflicts once two planes are set to a collision route (I couldn't resist >=D), so I had like 30 conflicts accounted for a single route LOL

paul doe wrote:so I had like 30 conflicts accounted for a single route LOL

The game counts the time of conflict, and you'll be fired (meaning: "Game over") if you've gathered 60 seconds. The same happens if you gather 100 minutes of delay, cause a crash or a bad exit.

With the applied framework (an array of objects, where the array itself is a static member of the Type) the object mutated from a warrior to a plane, so it shouldn't be too hard to make it a space ship or a tank. My thoughts are, that a main program could provide one or multiple types of machines (space ships, tanks, racing cars, whatever we will choose) with a number of determined features (propulsion, weaponry, manoeuvrability, range etc.) and a pilot/driver implemented as a plugin or (better IMHO) a control interface similar to the UCI - protocol, so from the view of the machine it doesn't matter if the pilot/driver is a bot or a human (or even a combination of both).

paul doe wrote:so I had like 30 conflicts accounted for a single route LOL

The game counts the time of conflict, and you'll be fired (meaning: "Game over") if you've gathered 60 seconds. The same happens if you gather 100 minutes of delay, cause a crash or a bad exit.

Ah, that explains a lot =D

grindstone wrote:My thoughts are, that a main program could provide one or multiple types of machines (space ships, tanks, racing cars, whatever we will choose) with a number of determined features (propulsion, weaponry, manoeuvrability, range etc.) and a pilot/driver implemented as a plugin or (better IMHO) a control interface similar to the UCI - protocol, so from the view of the machine it doesn't matter if the pilot/driver is a bot or a human (or even a combination of both).

BINGO. That's exactly the purpose of the Model-View-Controller architecture: decoupling of components, so you can transparently integrate them, and the underlying code doesn't need to know (nor care) which one is providing the functionality. This is usually implemented using an observer pattern.

As for what you call 'features', I have a couple of similar ideas in a similar vein: you design a ship (or use an existing one), then code its AI, and then put it to fight against other AIs. Naturally, you can also control the ship yourself, and the same goes for any other ship in the arena, so you see that the architecture scales well for a multiplayer arena (if/when we decide to go for it).

'' We need this to forward reference the Observer interfacetype _Observer as Observer'' Null for objects#define NIL cptr( any ptr, 0 )

/' Context interface

This interface defines the context for the notification, that is, the parameters for the message sent to the listener. It empty because it will vary with each individual context (which, in turn, depend on the interests of each observer). The default constructor is declared protected: to avoid direct instantiation of this class.'/type Context extends Object public: declare virtual destructor()

protected: declare constructor()end type

constructor Context()end constructor

destructor Context()end destructor

/' Subject interface

This interface defines the 'subject' of the pattern, that is, the object that acts as the message dispatch service. Observers subscribe to receive notifications from him.'/type Subject extends Object public: declare virtual destructor()

This is the interface that defines the 'observers' of the pattern. They subscribe to receive notifications from a 'subject' when needed.'/type Observer extends Object public: declare virtual destructor()

declare abstract sub receiveMessage( _ byref as Context )

protected: declare constructor()end type

constructor Observer()end constructor

destructor Observer()end destructor

/' A concrete implementation of a context. In this case, all it does is store a key pressed.'/type KeyboardContext extends Context public: declare constructor( _ byval as ulong ) declare destructor() override

whichKey as ulong

private: declare constructor()end type

constructor KeyboardContext()end constructor

constructor KeyboardContext( _ byval aKey as ulong )

whichKey = aKeyend constructor

destructor KeyboardContext()end destructor

/' A concrete implementation of a subject. In this case, this is a simple keyboard handler that will send a message informing the subscribed observers of which key has been pressed. Here, there's support for a single observer, but this can be easily changed to support more than one observer per subject (by maintaining a list of observers).'/type KeyboardSubject extends Subject public: declare constructor() declare destructor() override

/' And this is a concrete implementation of an observer. Here, it simply listens to messages forwarded by its subject, and prints some text when it receives one.'/type KeyboardObserver extends Observer public: declare constructor() declare destructor() override

Really? I revised and corrected it; I stated that it used a pull model whereas it uses a push model, actually. See if it's clearer now (the code was old, sorry).

badidea wrote:I tried to visualize it with UML. Which I have never used before and know nothing about. Probably some 'message' arrows or something missing.

Indeed, you're missing the dependency of the subject and the observer (implemented here as a weak pointer). Allow me to explain in a nutshell how the code works:

'Context', 'Subject' and 'Observer' are the interfaces for all three classes that intervene in the pattern, and KeyboardContext, KeyboardSubject and KeyboardObserver are the concrete implementations of those interfaces. Here, 'context' refers to the information that the KeyboardSubject class forwards to the KeyboardObserver class so it can update its state or perform an action. This is the actual message. In the new implementation I changed the name of the 'notify()' method from the KeyboardSubject class to 'sendMessage()', and the 'update()' method of the KeyboardObserver to 'receiveMessage()' to better reflect this fact.

The KeyboardObserver class has to subscribe to receive messages from the KeyboardSubject (I changed the name of the 'attach()' method to 'subscribe()' to clarify). So, in the main loop, we call the 'update()' method from the KeyboardSubject class to poll the keyboard and send a message informing the KeyboardObserver class when a key has been pressed. The KeyboardSubject also passes an instance of the KeyboardContext class to the KeyboardObserver that contains information relevant to the message in question, in this case, which key has been pressed.

What this accomplish is decoupling the senders of messages (the subjects) from the receivers of those messages (the observers), since the coupling is abstract and minimal; compare this with temporal coupling, which is what happens when you call the methods directly. Also, the subject can dispatch the message to any number of subscribers (broadcasting) without needing to know which ones are registered (it only knows how many observers subscribed; it doesn't care who they are as long as they conform to the observer's interface).

If this doesn't clarify it a little, tell me and I'll draw a class diagram for the pattern.

One of the great interests of this method (or the similar "Abstract Factory pattern") is precisely to be able to work by abstraction, that is to say with typed base lists of derived objects.For example in your case:- a Subject Ptr array containing pointers to different derived object from Subject,- an Observer Ptr array containing pointers to different derived object from Observer.

'' We need this to forward reference the Observer interfacetype _Observer as Observer'' Null for objects#define NIL cptr( any ptr, 0 )

/' Context interface

This interface defines the context for the notification, that is, the parameters for the message sent to the listener. It empty because it will vary with each individual context (which, in turn, depend on the interests of each observer). The default constructor is declared protected: to avoid direct instantiation of this class.'/type Context extends Object public: declare virtual destructor()

protected: declare constructor()end type

constructor Context()end constructor

destructor Context()end destructor

/' Subject interface

This interface defines the 'subject' of the pattern, that is, the object that acts as the message dispatch service. Observers subscribe to receive notifications from him.'/type Subject extends Object public: declare virtual destructor()

This is the interface that defines the 'observers' of the pattern. They subscribe to receive notifications from a 'subject' when needed.'/type Observer extends Object public: declare virtual destructor()

declare abstract sub receiveMessage( _ byref as Context )

protected: declare constructor()end type

constructor Observer()end constructor

destructor Observer()end destructor

/' A concrete implementation of a context. In this case, all it does is store a key pressed.'/type KeyboardContext extends Context public: declare constructor( _ byval as ulong ) declare destructor() override

whichKey as ulong

private: declare constructor()end type

constructor KeyboardContext()end constructor

constructor KeyboardContext( _ byval aKey as ulong )

whichKey = aKeyend constructor

destructor KeyboardContext()end destructor

/' A concrete implementation of a subject. In this case, this is a simple keyboard handler that will send a message informing the subscribed observers of which key has been pressed. Here, there's support for a single observer, but this can be easily changed to support more than one observer per subject (by maintaining a list of observers).'/type KeyboardSubject extends Subject public: declare constructor() declare destructor() override

/' And this is a concrete implementation of an observer. Here, it simply listens to messages forwarded by its subject, and prints some text when it receives one.'/type KeyboardObserver extends Observer public: declare constructor() declare destructor() override