Problem #378
Tags:
games
lua
special
c-1
This task has a Challenge attached.
You may
View Stats
or read a Help on Challenges.
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.
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:
cmd
literal, so the control system extracts this line from general input and interprets as commanddA
- how much to change angle, say -10
or +20
, again in mrad
, subject to limitation described belowfire
- either 1
- to shoot if possible (or not if 0
)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.
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).
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).