Skip to content

Onboarding Solution

alcapwny edited this page Jun 13, 2021 · 8 revisions

Onboarding is the introductory puzzle available on CodinGame. It offers a simple puzzle where, each turn, you must shoot the closest enemy ships flying towards you.

Input Setup

Every turn you will receive two enemy names and their distance to you, all on one line. This puzzle does not provide any global input.

The input received every frame is in this format: enemy1Name enemy1Distance enemy2Name enemy2Distance

The enemy names can be interpreted as strings and the enemy distances can be interpreted as integers.

Input Processing

Follow the puzzle solving steps up to Step 4 of Solving Your First Puzzle. This will assume that you used Onboarding as your puzzle name.

Open OnboardingInputData.cs. You'll notice that two classes have already been created for you:

using CGFCodeGenerator;

[GlobalData]
public class OnboardingGlobalInputData
{

}

[FrameData]
public class OnboardingFrameInputData
{
    
}

Since this puzzle doesn't contain any global data we can just delete OnboadingGlobalInputData.

As mentioned above, we need to process a sequence of a string, integer, string, integer, all on the same line. OnboardingFrameInputData could look like the following:

[FrameData]
public class OnboardingFrameInputData
{
    [GroupWithNext]
    public string m_Enemy1;
    [GroupWithNext]
    public int m_Dist1;
    [GroupWithNext]
    public string m_Enemy2;
    public int m_Dist2;
}

The GroupWithNext attribute needs to be used on a member to indicate that the next member is on the same line. As such we do not need to use the GroupWithNext attribute on the last member.

With OnboardingFrameInputData done, we can now proceed to Step 5 of Solving Your First Puzzle and run the code generation using tools\generate_Code.bat. Since we've only iterated on an existing .cs file we do not need to regenerate the projects. If we had added a new .cs file we would have run tools\generate_ProjectsAndCode.bat instead to first generate the C# projects with the new .cs, run the code generation to generate the .h, .inl and .user.inl, and then regenerate the main CodinGame solution and C++ projects.

Coding the Puzzle Solution

At Step 6 of Solving Your First Puzzle, we now start from a freshly generated puzzle solution skeleton which looks like the following for Onboarding:

#if !defined(CODING_LOCALDEBUGGING)
#pragma GCC optimize "O3,omit-frame-pointer,inline"
#endif

//////////////////////////////////
// System includes

#if !defined(CODING_EXLUDESYSTEMHEADERS)
//#include <iostream>
#else
//CODING_EXLUDESYSTEMHEADERS#include <iostream>
#endif

//////////////////////////////////
// Includes

#include <codingame/defines.h>
#include <codingame/assert.h>
#include <codingame/logging.h>
#include <codingame/game.h>

#include <OnboardingInputData.h>

//////////////////////////////////

int main()
{
    Game game("Onboarding.txt");

    OnboardingGlobalInputData globalData;
    game.SerializeGlobalData(globalData);

    // game loop
    while (Game::RunGameLoop(dataStream))
    {
        OnboardingFrameInputData frameData;
        game.SerializeFrameData(frameData);

        // game loop code
    }

    return 0;
}

Starting from the top, there are a few things to note:

  • The first block is a block that enables different optimizations when the puzzle solution is being compiled on CodinGame. This was found online as a set of options that enables your code to run faster, which can be useful when working on more complex solutions. The define CODING_LOCALDEBUGGING is only defined when working locally.
#if !defined(CODING_LOCALDEBUGGING)
#pragma GCC optimize "O3,omit-frame-pointer,inline"
#endif
//////////////////////////////////
// System includes

#if !defined(CODING_EXLUDESYSTEMHEADERS)
//#include <iostream>
#else
//CODING_EXLUDESYSTEMHEADERS#include <iostream>
#endif
  • This is then followed by the standard includes from the framework and the main function which makes use of the Game object provided by the framework. The Game object can load inputs from a local file when iterating locally and will feed the input for the global data and data every frame.

If we focus back on the solution for Onboarding, we determined above that we don't need to process any global data. As such, we remove the part that processes the global data from the main and it could look like the following:

int main()
{
    Game game("Onboarding.txt");

    // game loop
    while (Game::RunGameLoop(dataStream))
    {
        OnboardingFrameInputData frameData;
        game.SerializeFrameData(frameData);

        // game loop code
    }

    return 0;
}

The next step is to code the solution. Now that we have the input reading and processing done the solution to the Onboarding problem is fairly trivial. We need to look at the input we've received every frame, compare the distances and return the name of the closest enemy. The game loop code can look like the following:

if (frameData.m_Dist1 < frameData.m_Dist2)
{
    std::cout << frameData.m_Enemy1 << std::endl;
}
else
{
    std::cout << frameData.m_Enemy2 << std::endl;
}

With that done, the final solution could look like the following. Note that while only the main function has changed from the puzzle solution skeleton the whole solution is shown here:

#if !defined(CODING_LOCALDEBUGGING)
#pragma GCC optimize "O3,omit-frame-pointer,inline"
#endif

//////////////////////////////////
// System includes

#if !defined(CODING_EXLUDESYSTEMHEADERS)
//#include <iostream>
#else
//CODING_EXLUDESYSTEMHEADERS#include <iostream>
#endif

//////////////////////////////////
// Includes

#include <codingame/defines.h>
#include <codingame/assert.h>
#include <codingame/logging.h>
#include <codingame/game.h>

#include <OnboardingInputData.h>

//////////////////////////////////

int main()
{
    Game game("Onboarding.txt");

    // game loop
    while (game.RunGameLoop())
    {
        OnboardingFrameInputData frameData;
        game.SerializeFrameData(frameData);

        if (frameData.m_Dist1 < frameData.m_Dist2)
        {
            std::cout << frameData.m_Enemy1 << std::endl;
        }
        else
        {
            std::cout << frameData.m_Enemy2 << std::endl;
        }
    }

    return 0;
}

Submitting the Solution to CodinGame

Now that we've coded our solution it is now time to test it. We can now proceed with Steps 7 to 10 of Solving Your First Puzzle to generate the file that contains all the code needed for this solution and run the test case in CodinGame.

If at Step 11 the test case has failed, which we can force by flipping the if condition in the game loop code, we ideally want to debug this locally. To do this we go to the CodinGame IDE's console output window, by default at the bottom left, and copy all the text in the Console output window. We then paste this in the file that was created for this purpose, data\OnboardingLog.txt. We can then run data\OnboardingLogParser.bat which will parse the log file and generate data\Onboarding.txt - the file that is expected to contain the puzzle inputs when debugging locally. We can then debug the puzzle locally within Visual Studio, fix the issue, and follow the Steps 7 to 10 of Solving Your First Puzzle run the test case again. Once all test cases have passed, submit the code to CodinGame!

Congrats, you have just solved your first puzzle using CGF!