Mars Lander - Puzzle discussion

Can someone help me figure out how to determine the coordinates for the landing pad…?

I got it! Thanks!!

1 Like

Finally solved last episode as well, using sklearn.optimize in Python3 to minimizing a scoring function

The scoring function takes into account:

  • Distance from landing pad (taking wall into consideration)
  • Speed, and angle of arrival
  • Used fuel.

Still not super happy with my solution: converging is so slow I can’t run it in on Coding Game limit of 100ms (writing the simulator in Python might not have been the best idea).

I ended up running it on my computer, and copy pasting the list of moves into the editor (which oddly works, because the terrain must be the same between tests and validation).

The breakthough between “this is never converging to anything useful” and “hey this might work” was when updating the distance calculation from a “straight line” to a “let’s not ignore the walls” in the scoring function
It made everything converge much much faster (cf screenshot).

image

2 Likes

Hi!

Where did you get the last level you’are showing on the screenshots?
I only had two of them in the “very hard” training.

I did not find anything on tech.io.
Did you build it by hand to test your solution?

1 Like

Hi,

These are the coordinates for the test:

"Stalagtite upward start": [
            "15",
            "0 2500", "100 200", "500 150",
            "1000 2000", "2000 2000", // Landing area
            "2010 1500", "2200 800", "2500 200",
            "6899 300", "6999 2500", "4100 2600",
            "4200 1000", "3500 800", "3100 1100",
            "3400 2900",

            // Lander config
            "6500 1300 0 50 1750 0 0"
]

This is the tech.io tutorial:
https://www.codingame.com/playgrounds/334/genetic-algorithms/what-now

This is their github repository:

I wrote in more detail for my solution in a blog post:

Cheers :slight_smile:

2 Likes

Hi everybody,
Level 1, Java - I’m trying to figure out how the actual Y is computed. The vertical speed in each round is the speed from previous round minus gravity (3.711) plus power (that’s correct, read numbers match). With this I would expect that Y is the Y from the previous round plus speed. But that’s somehow wrong.

For example, with no power, the speed after the first round is -3.711 (rounded to -4, matches the read value). And I expect Y to be 2496.289 (2500 + (-3.711)) and rounded to 2496. But the read value is 2498. What am I missing?

I have tried to divide the speed by 2, subtract 1/(round number) and few other adjustments, but my computations never match the Y given by the line reading.

3 Likes

The 3.711 is acceleration. At the start of the turn you are at 0, at the end you are at -3.711. During the turn you slowly change from one speed to the other. Your speed for the turn will be velocity + (acceleration/2), which gives 2500 + (0 + (-3.711/2)) = 2498.1445. Unfortunately the server only sends you the integer part so if you need an accurate position / velocity you need to track it yourself and ignore the server.

7 Likes

Awesome series. But why so few tests? I substituted my primitive inefficient algorithm from the 2nd to the 3rd episode, and received a 250XP freebie for passing the “half” of tests without any complicated mathematics :confused:

1 Like

I uses a physics approach as well, and I used EXCEL as a visualization tool for my algorithm which served me extremely well for quick tests :wink:

Critical for this algorithm is to know by when (how many seconds left) the lander will reach Ylanding based on current Yspeed and by when it will reach Xlanding based on current Xspeed. As both velocities vY and vX are limited, I also needed to calculate how many seconds to brake in X-direction to stay within landing limits of -20…20m/s and what this braking would do to the velocity in Y-direction.
To make it easier for me, I only allowed the most efficient rotate angles (45°, 0°, -45°) and built in an optimizer to find the best possible spot to land on within allowed X landing range.

The algorithm has just two outputs: modeFlagX and modeFlagY. modeFlagY is only set in case current vY is nearing maximum allowable Y-velocity based on time needed to reach destined X position and maximum Yspeed for landing (-40).
modeFlagX is just requesting the lander to accelerate, brake, or no change of direction needed based on target X. It will only allow to brake/accelerate if modeFlagY is NOT requesting to thrust upwards.

The algo for Level 2 DOES NOT NEED a pathfinding function yet, I will develop this for level3 later on.

I’ll post some snapshots once the forum lets me :wink:

3 Likes

@RoboStac’s post solved this for me. In my opinion, this behavior should have been better documented.

My new, working, state update looks like this:

thr = radians(thetan)
co = cos(thr)
si = -sin(thr)
vxn = clamp(vx+powern*si, -500, 500)
vyn = clamp(vy+powern*co+g, -500, 500)
xn = x+vx+0.5*powern*si
yn = y+vy+0.5*(powern*co+g)
fueln = fuel-powern
3 Likes

Hi, I’m trying to solve episode 2 in JavaScript. But I’m kind of lost. I know The landing spot has two Y points equals. But, Do I have to find it before I start printing values, or I have to look for a spot as the shuttle goes throw.
How can I get this value. I don’t know how can I compare Y in Xinitial and Y in Xfinal (X + wide).

1 Like

Hi why won´t this work??

    // game loop
    while (true)
    {
        inputs = Console.ReadLine().Split(' ');
        int X = int.Parse(inputs[0]);
        int Y = int.Parse(inputs[1]);
        int hSpeed = int.Parse(inputs[2]); // the horizontal speed (in m/s), can be negative.
        int vSpeed = int.Parse(inputs[3]); // the vertical speed (in m/s), can be negative.
        int fuel = int.Parse(inputs[4]); // the quantity of remaining fuel in liters.
        int rotate = int.Parse(inputs[5]); // the rotation angle in degrees (-90 to 90).
        int power = int.Parse(inputs[6]); // the thrust power (0 to 4).
         
        // Write an action using Console.WriteLine()
        // To debug: Console.Error.WriteLine("Debug messages...");
        
        if (vSpeed < -38)
        {
            power = 3;
        }    
        else 
        {
            power = 0;
        }    
        


        // 2 integers: rotate power. rotate is the desired rotation angle (should be 0 for level 1), power is the desired thrust power (0 to 4).
        Console.WriteLine("0 power");
    }
}

}

1 Like

Define what “work” should do.

In your code, you modify the variable power but don’t use it afterwards.

1 Like

Hi, has anyone tried to solve this problem in Scala? I don’t know how codingames generates the code - and how it is vetted - but I’m under the impression the default Scala code is erroneous and I haven’t managed to make it run for me. Without adding any conditions there are three errors for me. The first one seemed to be a simple spelling mistake. The two other ones however I haven’t managed to solve. If anyone could give a helping hand, it’d be greatly appreciated.

2 Likes

you are right … there is a problem with the stub …

differents cases for the same variable

val surfaceN
until surfacen

problem with variable “X” and “Y” … works with “x” and “y” …
looks like scala does not like variables name beginning by uppercase (but i am not a scala expert)

2 Likes

There are errors in the script for Scala. This is the correction to get it to compile

import math._
import scala.util._
import scala.io.StdIn._

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
object Player extends App {
    val surfaceN = readLine.toInt // the number of points used to draw the surface of Mars.
    for(i <- 0 until surfaceN) {
        // landX: X coordinate of a surface point. (0 to 6999)
        // landY: Y coordinate of a surface point. By linking all the points together in a sequential fashion, you form the surface of Mars.
        val Array(landX, landY) = (readLine split " ").map (_.toInt)
    }

    // game loop
    while(true) {
        // hSpeed: the horizontal speed (in m/s), can be negative.
        // vSpeed: the vertical speed (in m/s), can be negative.
        // fuel: the quantity of remaining fuel in liters.
        // rotate: the rotation angle in degrees (-90 to 90).
        // power: the thrust power (0 to 4).
        val Array(landX, landY, hSpeed, vSpeed, fuel, rotate, power) = (readLine split " ").map (_.toInt)
        
        // Write an action using println
        // To debug: Console.err.println("Debug messages...")
        

        // 2 integers: rotate power. rotate is the desired rotation angle (should be 0 for level 1), power is the desired thrust power (0 to 4).
        //println("0 3")

    }
}
2 Likes

Thank you for your help. Since I believe the landing coordinates are supposed to be different from the actual coordinates I chose the solution above, changing X and Y to x and y.

I’m pretty sure I tried changing the variable names to ‘a’ and ‘b’, but I thought it didn’t help.
Edit : just tried it again, and I must just have been confused, changing it to whatever lower case character works.

1 Like

Thanks for this 0.5 trick !

I have spent hours banging my head over my desk because the physics I had learn at high school were not working here. I agree with you : the specification does not explain it clearly. Unless it was a trap…

But I still do not catch everything… For instance, why didn’t you write

vxn = clamp(vx+0.5*powern*si, -500, 500)
vyn = clamp(vy+0.5*(powern*co+g), -500, 500)
xn = x+vxn
yn = y+vyn
1 Like

The velocity must be updated with the full power, not the half power. The 0.5 trick is to add the “direct” influence of the power on the position. Compare with the formula for constant acceleration:

s = s0 + v0*t + 0.5*a*t^2

Consider the case where t is 1:

s = s0 + v0 + 0.5*a

and apply this multiple times for different a:

s(n+1) = s(n) + v(n) + 0.5*a(n+1)

(-ish)

The speed update formula, on the other hand, is v = v0 + a*t, which simplifies to v = v0 + a for the t=1 case, or v(n+1) = v(n) + 0.5*a(n+1) for the iterative case.

1 Like

Maybe somebody will help, who is trying to use genetic algorythm, but could not pass test because of time limit. Try to rotate not by every degree, but by 2 (4,8) degrees, this decreases the number of populations to find the solution.

2 Likes

Same here when using Rust.

Running the solution locally with the cargo build --release flag runs 24 times faster.

[No full solution please.]

1 Like