Space Invaders Automation

Problem #378

Tags: games lua special c-1

This task has a Challenge attached.
You may View Stats or read a Help on Challenges.

No translations... yet
Write the code to control cannon, then press the button below


This problem is the sequel to Space Invaders so you are recommended to spend 10 minutes on solving that one first.

Manually operating the cannon as in that first version, may be funny, but definitely is not convenient. And we are programmers after all! Let's write the code for the "autocannon" which will:

This again needs to be written particularly in Lua, but again very small code may be enough to achieve good results. Remember our Lua Quickstart Guide is at hand.

Technical Details

The cannon control program (which you are going to invent) is executed many times, say, 40 times per second. It should use io.read('*n') statements to read input consisting of several numeric values. Here is the format:

<angle> <reloading>
<numaliens> <x1> <y1> <x2> <y2> ...
<statevars> <v1> <v2> ...

Here angle is the current direction of the cannon in mrad (milliradians - popular unit in artillery), 0 for straight upwards, negative when inclined left and positive when inclined right (so full sweep is -1570 ... 1570).

Then reloading hints when the cannon will be able to shoot again. After each shot it needs 500 milliseconds to reload (or perhaps recharge, since it is laser). This value decreases on each next call and when it is 0 the weapon is again ready to fire.

Next line gives number of alien starships visible, after which corresponding amount of pairs of coordinates follow. Y means height (above the level where cannon sits) while X could be negative or positive depending whether it is to the left or to the right of the cannon. In other words it is typical cartesian coordinate grid with origin at the cannon's rotation point.

The third line allows you to pass some custom values between the calls, let's speak of this later.

So the example input could be like this:

-1004 149
3 -35 308 -77 173 189 83
0 

Which means cannon is currently looks about 1 radian (57 degrees) left from the vertical, it needs yet 149 ms to complete reloading. There are 3 aliens, two closer to the left and one somewhat further to the right. There are 0 state variables passed.

Your output should be a single line with the following fields, space-separated:

It is obvious the cannon couldn't rotate indefinitely fast. It's mechanical limits allow turning speed up to 1000 mrad / sec in both directions. This means if you tell it to turn 50 mrad but only 20 milliseconds have passed since previous call, it will only turn 20 mrad.

It is ok to pass fire=1 asking to shoot even while reloading is still non-zero. The cannon simply won't shoot, but it won't result in error.

State variables may contain, for example, direction you are currently turning your cannon (if it need to persist for several calls) or the specific coordinate (e.g. X) of some target you are currently following.

Example of the command string output could be like this:

cmd -15 1 -1 -237

It tells to try turning 15 mrad left, then shoot (if possible) - and also passes couple of values -1 and -237 as state variables (supposedly current rotation direction and some currently chosen target).

Note about the timing. It is not actually necessary for you to know exact values for these delays. When checking your code they are always 25 ms between calls. In browser animation it generally may be 15 ... 50 ms depending on hardware, software, phase of the moon etc. Again, it only affects rotation limit - while speeds of shots flying and alien descend are fixed, so you can estimate deflection (correction for target's coordinate change while shot can reach it) experimentally.

Simple Code Examples

The first example do not use any state variables and simply tries to turn the cannon to the side where there are more aliens descending:

angle, tts = io.read('*n', '*n')
aliens = io.read('*n')
dir = 0
for i = 1, aliens do
    x, y = io.read('*n', '*n')
    if x < 0 then dir = dir - 1 end
    if x > 0 then dir = dir + 1 end
end
da = 0
if dir > 0 and angle < 1000 then da = 10 end
if dir < 0 and angle > -1000 then da = -10 end
print('cmd', da, 1)

The second example simply "sweeps" the barrel forth and back, firing when it is loaded. It users a single state variable to remember current sweep direction, but otherwise performs worse than the first one.

angle, reloading = io.read('*n', '*n')
aliens = io.read('*n')
for i = 1,aliens do x,y = io.read('*n', '*n') end
varnum = io.read('*n')
if varnum > 0 then dir = io.read('*n') else dir = 1 end
if angle > 1000 then dir = -1 end
if angle < -1000 then dir = 1 end
print('cmd', (dir * 20), (reloading > 0 and 0 or 1), dir)

Of course we need to read values for aliens even though we don't use it. Note that we need to check if actually state variable exists in the input (it is not the case on the first call).

The Goal

Create control program which can defend against alien invasion at least for 60 seconds, allowing less than 5 ships to reach the ground. Score is proportional to how long you stand until 5 ships landed (with 600 second limit to avoid endless game).

You need to login to get test data and submit solution.