Test at Firefly Studios or a game in an hour / Habr

Test at Firefly Studios or a game in an hour / Habr

A couple of weeks ago, I was approached by the HR of “fireflies” and invited to talk about the position of an AI programmer in their new old game. I was a bit surprised because I know a couple of the guys from the studio and know that they are currently on hiatus. But it’s always interesting to talk to smart people, so I didn’t refuse. The first call from HR was standard, where he was working on what, what games he was playing. I don’t really understand why all this was asked, if all this is on LinkedIn in detail and with dates. Well, it’s okay – you can see that their Eicharian share is to be questioned thirty-three times. Or HR beyond the second page was simply too lazy to read.

They missed the time of the technical interview. At noon on Thursday, an employee of the studio comes to the meeting and starts looking at the resume beyond the second page, where he comes across a screenshot of the open source project StoneKingdoms, in which I have been actively contributing for some time. The project, if anything, has received the blessing of Simon Bradbury himself (the owner of the studio), so there are no problems with the rights to use resources from Stronghold. Questions poured in, and what kind of project is this? and how do you do? and what about lua? and what about the pros? Somewhere in the middle of the conversation, we were joined by another “firefly” developer, with whom my acquaintance began back in 2010, when he helped restore the origins of Caesar III and simply gave advice as a realized game simulation. We still sometimes talk on the forum about remakes of old games.


This person has one peculiarity – if you touch on the projects in which he participated, then for the next half hour everyone will listen to fables and stories about how this project was done. And he tells interestingly and with a fire, it happened that everything did not end for several hours. We specifically discussed the implementation of shadows on the isometric map. You should have seen the look on the interviewer’s face when the joiner greeted me by name and asked how the work on Pharaoh was progressing. And then we listened to the story of how the shadows were implemented in the first Stronghold, the technical issues somehow went to the side. A little later, the conversation generally turned to the discussion of the peculiarities of the arrangement of games in the times of Ancient Rome and the fifth dynasty of Egypt.

About the open source Stronghold: I won’t go there anymore, but if anyone has time, be sure to look, a lot of things have been restored there from the original game (https://gitlab.com/stone-kingdoms/stone-kingdoms)

The stock pile is full. My lord!

And this is the original, as they say – find five differences

The hour that was taken for the interview flew by as if he had never been there. At the end of the conversation, the interviewer jokingly asked if I would agree to the test, I also jokingly agreed. Of course, there was no sense in it, but I was always interested in the various puzzles that studios invent for potential employees. So, during the second hour of social security for live coding, it was necessary to write a game, talking about the decisions made during the creation of the game. But it is not easy to write – a point was taken for each extra line after the 150th, and a point was added for each empty line of code before the 150th. As my friends later said, the record was 85 lines of working arkanoid and readable code. For each additional game feature, such as lives or points, 10 more points are added. For an unreadable or incomprehensible code, points are also deducted, a maximum of 30 points can be deducted.

It was necessary to make a raking arkanoid in an hour.

This is what they say people write in 5 nanoseconds

But don’t think that there are absolutely beasts sitting there – write a game from scratch. Even such a simple one. The framework of the program is already written, you need to outline your logic, and as I said above, try to fit it into 150 lines of code. I’m not a very fast coder, and I often need time to think about a solution, even if it’s obvious or has already been done somewhere in past projects. Therefore, it was really a difficult task for me in terms of keeping up with the time.

#include <SDL.h>

const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;

const int BRICK_WIDTH = 48;
const int BRICK_HEIGHT = 20;

struct Brick{
    SDL_Rect rect;
} ;

struct Ball {
    SDL_Rect rect;
} ;

struct Paddle {
    SDL_Rect rrect;
} ;

struct Game {
    Brick bricks[16][10];
    Ball ball;
    Paddle paddle;
};

int main(int argc, char* args[]) {
    Game game;

    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = SDL_GetWindowSurface(window);

    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
    window = SDL_CreateWindow( "Strongout", 50, 50, 
                              SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
    bool quit = false;
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)){
            if( event.type == SDL_QUIT){
                quit = true;
                break;
            }

            if( event.type == SDL_KEYDOWN ){
            }

            if( event.type == SDL_KEYUP ){
            } 
        }
        SDL_FillRect(screenSurface, NULL, 
                     SDL_MapRGB( screenSurface->format, 0, 0, 0));
        // Your code here
        SDL_UpdateWindowSurface(window);
    }

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

First of all, brick painting was added. Please don’t scold me too much for the code, in the conditions of limited time and the need to debug the functionality, it is very difficult to think about the architecture, so I wrote simply and clumsily, so that it was possible to quickly iterate and debug.

void drawLiveBricks(SDL_Surface* screen, SDL_Window* window, Game &game) {
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 10; j++){
            if (game.bricks[i][j].is_alive) {
                SDL_FillRect(screen, &game.bricks[i][j].rect, 
                             SDL_MapRGB( screen->format, 255, 0, 0));
            }
        }
    }
}

Then it was the turn of the bar and the ball

SDL_FillRect(screenSurface, &game.paddle.rect, SDL_MapRGB( screenSurface->format, 0, 255, 0));
SDL_FillRect(screenSurface, &game.ball.rect, SDL_MapRGB( screenSurface->format, 255, 255, 255));

Now let’s make the bar move when pressing the A/D buttons. Velocity is needed to convey direction to the bar.

struct Paddle {
    SDL_Point velocity;
    SDL_Rect area;

    Paddle() {
        area = {350, 550, 100, 20};
        velocity = {0, 0, 0, 0};
    }

    void move(SDL_Keycode key) {
        if (key == SDLK_a){
            velocity.x = -1;
            if (area.x <= 0) {
                velocity.x = 0;
                area.x = 0;
            }
        }
        if (key == SDLK_d){
            velocity.x = 1;
            if (area.x + area.w >= SCREEN_WIDTH) {
                velocity.x = 0;
                area.x = SCREEN_WIDTH - area.w;
            }
        }
    }

    void update() {
        area.x += velocity.x;
        if (area.x <= 0) {
            area.x = 0;
        }
        if (area.x + area.w >= SCREEN_WIDTH) {
            area.x = SCREEN_WIDTH - area.w;
        }
    }

};

And of course, update the movement of the ball, let our ball look like a square in this approximation. May the gods of good code forgive me, I threw the record of collisions with the walls and the bar directly into the ball update.

    bool update(const Paddle &paddle) {
        if (SDL_GetTicks() % 2 == 1) { return true; }
        velocity.x *= (position.x <= 0 || position.x >= SW.x - position.w) ? -1 : 1;
        velocity.y *= (position.y <= 0) ? -1 : 1;
        if (position.y >= SW.y - position.h) {
            velocity = {0, 0};
            position = {395, 295, 10, 10};
            return false;
        }
        velocity.y *= (position.y == (paddle.y) && (position.x >= paddle.x) && (position.x <= paddle.x + paddle.w)) ? -1 : 1;
        position.x += velocity.x;
        position.y += velocity.y;
        (SDL_Point&)r = (SDL_Point&)position;
        return true;
    }

It remains to break the blocks. I couldn’t think of anything better than just watching the intersection of all the blocks with a ball after the update. Even if the situation turns out that the ball will be inside the block, we still get its breakdown.

        for (int i = 0; i < 160; i++) {
            if (SDL_HasIntersection(&game.ball.r, &game.bricks[i].r) && game.bricks[i].is_alive) {
                game.ball.position.y += 2;
                game.ball.velocity.y *= -1;
                game.bricks[i].is_alive = false;
            }
        }

All this plus debug runs took about 30 minutes, plus I had to comment on my actions, which also turned out to be quite difficult in parallel with writing the code. The result was the following code:

Strongout/146 lines
сonst int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;

const int BRICK_WIDTH = 48;
const int BRICK_HEIGHT = 20;

using p = SDL_Rect; using v = p;

struct Brick {
    p r;
    bool is_alive;
} ;

struct Paddle {
    v velocity = {0, 0, 0, 0};
    p area = {350, 550, 100, 20};

    void move(SDL_Keycode key) {
        if (key == SDLK_a){
            velocity.x = -1;
            if (area.x <= 0) {
                velocity.x = 0;
                area.x = 0;
            }
        }
        if (key == SDLK_d){
            velocity.x = 1;
            if (area.x + area.w >= SCREEN_WIDTH) {
                velocity.x = 0;
                area.x = SCREEN_WIDTH - area.w;
            }
        }
    }

    void update() {
        area.x += velocity.x;
        if (area.x <= 0) {
            area.x = 0;
        }
        if (area.x + area.w >= SCREEN_WIDTH) {
            area.x = SCREEN_WIDTH - area.w;
        }
    }
};

struct Ball {
    v velocity = {0, 0, 0, 0};
    p position = {395, 295, 10, 10};
    p r = position;

    void start(SDL_Keycode key) {
        if (key == SDLK_SPACE && velocity.x == 0 && velocity.y == 0)
            velocity = {1, 1};
    }

    bool update(const Paddle &paddle) {
        if (SDL_GetTicks() % 2 == 0) {
            if (position.x <= 0 || position.x >= SCREEN_WIDTH - position.w) {
                velocity.x *= -1;
            }
            if (position.y <= 0) {
                velocity.y *= -1;
            }

            if (position.y >= SCREEN_HEIGHT - position.h) {
                velocity = {0, 0};
                position = {395, 295, 10, 10};
                return false;
            }
            if (position.y == (paddle.area.y)) {
                if ((position.x >= paddle.area.x) && (position.x <= paddle.area.x + paddle.area.w)) {
                    velocity.y *= -1;
                }
            }

            position.x += velocity.x;
            position.y += velocity.y;
            (SDL_Point&)r = (SDL_Point&)position;
            return true;
        }
    }
};

struct Game {
    std::array<Brick, 16 * 10> bricks;
    Ball ball;
    Paddle paddle;

    Game() {
        for (auto &brick: bricks) {
            int i = std::distance(bricks.data(), &brick);
            brick.r = {1 + ((i % 16) * (BRICK_WIDTH + 2)), 1 + ((i / 16) * (BRICK_HEIGHT + 2)), BRICK_WIDTH, BRICK_HEIGHT};
            brick.is_alive = true;   
        }
    }
};

int main(int argc, char* args[]) {
    Game game;
    bool quit = false;
    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
    window = SDL_CreateWindow("Strongout", 50, 50, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)){
            if( event.type == SDL_QUIT){
                quit = true;
                break;
            }
            if( event.type == SDL_KEYDOWN ){
                game.paddle.move(event.key.keysym.sym);
                game.ball.start(event.key.keysym.sym);
            }
            if( event.type == SDL_KEYUP ){
                game.paddle.velocity.x = 0;
            } 
        }
        if (game.lives > 0) {
            game.paddle.update();
            game.ball.update(game.paddle);
        }
        int numBricks = 160;
        for (int i = 0; i < numBricks; i++) {
            if (SDL_HasIntersection(&game.ball.r, &game.bricks[i].r) && game.bricks[i].is_alive) {
                game.ball.position.y += 2;
                game.ball.velocity.y *= -1;
                game.bricks[i].is_alive = false;
            }
        }
        screenSurface = SDL_GetWindowSurface(window);
        SDL_FillRect(screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0, 0, 0));
        for (auto &brick: game.bricks) {
            if (brick.is_alive) {
                SDL_FillRect(screenSurface, &brick.r, SDL_MapRGB( screenSurface->format, 255, 0, 0));
            }
        }
        SDL_FillRect(screenSurface, &game.paddle.area, SDL_MapRGB( screenSurface->format, 0, 255, 0));
        SDL_FillRect(screenSurface, &game.ball.r, SDL_MapRGB( screenSurface->format, 255, 255, 255));
        SDL_UpdateWindowSurface(window);
    }
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

This is what I managed to squeeze in half an hour

But, as you can see, there will be few points on the Arkanoid scale for the written code. By the way, I noticed that companies have become less willing to give tasks for offline execution, probably this is due to the impossibility of checking whether it will be executed by the grid or if a person will do it himself. Returning to the Arkanoid code, the first thing that came to mind was to clean up all the extra lines and collapse some of the parentheses and functions to get more points.

Strongout/132 lines
сonst int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int BRICK_WIDTH = 48;
const int BRICK_HEIGHT = 20;
using p = SDL_Rect; using v = p;
struct Brick {
    p r;
    bool is_alive;
} ;
struct Paddle {
    v velocity = {0, 0, 0, 0};
    p area = {350, 550, 100, 20};
    void move(SDL_Keycode key) {
        if (key == SDLK_a){
            velocity.x = -1;
            if (area.x <= 0) {
                velocity.x = 0;
                area.x = 0;
            }
        }
        if (key == SDLK_d){
            velocity.x = 1;
            if (area.x + area.w >= SCREEN_WIDTH) {
                velocity.x = 0;
                area.x = SCREEN_WIDTH - area.w;
            }
        }
    }
    void update() {
        area.x += velocity.x;
        if (area.x <= 0) {
            area.x = 0;
        }
        if (area.x + area.w >= SCREEN_WIDTH) {
            area.x = SCREEN_WIDTH - area.w;
        }
    }
};
struct Ball {
    v velocity = {0, 0, 0, 0};
    p position = {395, 295, 10, 10};
    p r = position;
    void start(SDL_Keycode key) {
        if (key == SDLK_SPACE && velocity.x == 0 && velocity.y == 0)
            velocity = {1, 1};
    }
    bool update(const Paddle &paddle) {
        if (SDL_GetTicks() % 2 == 0) {
            if (position.x <= 0 || position.x >= SCREEN_WIDTH - position.w) {
                velocity.x *= -1;
            }
            if (position.y <= 0) {
                velocity.y *= -1;
            }
            if (position.y >= SCREEN_HEIGHT - position.h) {
                velocity = {0, 0};
                position = {395, 295, 10, 10};
                return false;
            }
            if (position.y == (paddle.area.y)) {
                if ((position.x >= paddle.area.x) && (position.x <= paddle.area.x + paddle.area.w)) {
                    velocity.y *= -1;
                }
            }
            position.x += velocity.x;
            position.y += velocity.y;
            (SDL_Point&)r = (SDL_Point&)position;
            return true;
        }
    }
};
struct Game {
    std::array<Brick, 16 * 10> bricks;
    Ball ball;
    Paddle paddle;
    Game() {
        for (auto &brick: bricks) {
            int i = std::distance(bricks.data(), &brick);
            brick.r = {1 + ((i % 16) * (BRICK_WIDTH + 2)), 1 + ((i / 16) * (BRICK_HEIGHT + 2)), BRICK_WIDTH, BRICK_HEIGHT};
            brick.is_alive = true;   
        }
    }
};
int main(int argc, char* args[]) {
    Game game;
    bool quit = false;
    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
    window = SDL_CreateWindow("Strongout", 50, 50, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)){
            if( event.type == SDL_QUIT){
                quit = true;
                break;
            }
            if( event.type == SDL_KEYDOWN ){
                game.paddle.move(event.key.keysym.sym);
                game.ball.start(event.key.keysym.sym);
            }
            if( event.type == SDL_KEYUP ){
                game.paddle.velocity.x = 0;
            } 
        }
        if (game.lives > 0) {
            game.paddle.update();
            game.ball.update(game.paddle);
        }
        int numBricks = 160;
        for (int i = 0; i < numBricks; i++) {
            if (SDL_HasIntersection(&game.ball.r, &game.bricks[i].r) && game.bricks[i].is_alive) {
                game.ball.position.y += 2;
                game.ball.velocity.y *= -1;
                game.bricks[i].is_alive = false;
            }
        }
        screenSurface = SDL_GetWindowSurface(window);
        SDL_FillRect(screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0, 0, 0));
        for (auto &brick: game.bricks) {
            if (brick.is_alive) {
                SDL_FillRect(screenSurface, &brick.r, SDL_MapRGB( screenSurface->format, 255, 0, 0));
            }
        }
        SDL_FillRect(screenSurface, &game.paddle.area, SDL_MapRGB( screenSurface->format, 0, 255, 0));
        SDL_FillRect(screenSurface, &game.ball.r, SDL_MapRGB( screenSurface->format, 255, 255, 255));
        SDL_UpdateWindowSurface(window);
    }
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

The result was 132 lines. There is nothing more to clean, the border is 100 lines further than Edinburgh. Here I understand that it is necessary to either radically collapse the code, which, of course, reduces readability and leads to penalty points, or finish the game with features. In five minutes, it was possible to sketch the reflection of lives for the ball and the logic of their decline, if the ball was under the bar. I wanted to add the display of glasses, but I would have to drag the display of fonts, the task is too much for 10 minutes. As a result, I focused on code minification without particularly caring about readability.

The code is readable, but already closer to a hundred lines. I ask the interlocutor which one he agreed on – it turned out to be 90 lines.

Strongout/100 lines
using p = SDL_Rect; using v = p;
const p SW{800, 600, 48, 20};
struct Brick : public p { bool is_alive = true; };
struct Paddle : public p {
    v velocity = {0, 0, 0, 0};
    void move(SDL_Keycode key) {
        if (key == SDLK_a){
            velocity.x = -1;
            if (x <= 0) { velocity.x = x = 0; }
        }
        if (key == SDLK_d){
            velocity.x = 1;
            if (x + w >= SW.x) {
                velocity.x = 0;
                x = SW.x - w;
            }
        }
    }
    void update() {
        x = std::max(x += velocity.x, 0);
        if (x + w >= SW.x) { x = SW.x- w; }
    }
};
struct Ball {
    v velocity = {0, 0, 0, 0};
    p position = {395, 295, 10, 10};
    p r = position;
    void start(SDL_Keycode key) {
        if (key == SDLK_SPACE && velocity.x == 0 && velocity.y == 0)
            velocity = {1, 1};
    }
    bool update(const Paddle &paddle) {
        if (SDL_GetTicks() % 2 == 1) { return true; }
        velocity.x *= (position.x <= 0 || position.x >= SW.x - position.w) ? -1 : 1;
        velocity.y *= (position.y <= 0) ? -1 : 1;
        if (position.y >= SW.y - position.h) {
            velocity = {0, 0};
            position = {395, 295, 10, 10};
            return false;
        }
        velocity.y *= (position.y == (paddle.y) && (position.x >= paddle.x) && (position.x <= paddle.x + paddle.w)) ? -1 : 1;
        position.x += velocity.x;
        position.y += velocity.y;
        (SDL_Point&)r = (SDL_Point&)position;
        return true;
    }
};
int main(int argc, char* args[]) {
    std::array<Brick, 16 * 10> bricks;
    Ball ball;
    Paddle paddle = {350, 550, 100, 20};
    int lives = 3;
    bool quit = false;
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
    auto window = SDL_CreateWindow("Strongout", 50, 50, SW.x, SW.y, SDL_WINDOW_SHOWN );
    for (auto &brick: bricks) {
        int i = std::distance(bricks.data(), &brick);
        brick = {1 + ((i % 16) * (SW.w + 2)), 1 + ((i / 16) * (SW.h + 2)), SW.w, SW.h};
    }
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)){
            if(event.type == SDL_QUIT){
                quit = true;
                break;
            }
            if(event.type == SDL_KEYDOWN){
                paddle.move(event.key.keysym.sym);
                ball.start(event.key.keysym.sym);
            }
            if (event.type == SDL_KEYUP) { paddle.velocity.x = 0; } 
        }
        if (lives > 0) {
            paddle.update();
            bool alive = ball.update(paddle);
            lives -= alive ? 0 : 1;
        }
        for (auto &brick: bricks) {
            if (SDL_HasIntersection(&ball.r, &brick) && brick.is_alive) {
                ball.position.y += 2;
                ball.velocity.y *= -1;
                brick.is_alive = false;
            }
        }
        auto screenSurface = SDL_GetWindowSurface(window);
        SDL_FillRect(screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0, 0, 0));
        for (auto &brick: bricks) {
            brick.is_alive && SDL_FillRect(screenSurface, &brick, SDL_MapRGB( screenSurface->format, 255, 0, 0));
        }
        SDL_FillRect(screenSurface, &paddle, SDL_MapRGB( screenSurface->format, 0, 255, 0));
        SDL_FillRect(screenSurface, &ball.r, SDL_MapRGB( screenSurface->format, 255, 255, 255));
        for (int i = 0; i < lives; i++) {
            SDL_Rect rrect{5 + (i * 15), (SW.y - 15), 10, 10};
            SDL_FillRect(screenSurface, &rrect, SDL_MapRGB( screenSurface->format, 255, 255, 255));
        }
        SDL_UpdateWindowSurface(window);
    }
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

What am I worse than a hereditary Briton? You can collapse everything, it will be painful to unfold later. I spent the remaining 10 minutes on “art”, the result was the code, the name of the language does not return, but it works. Replaced all possible ifs with ternary and logical AND operations. Collapsed one-line functions into one line. Replaced, where possible, functions, execution operators, and constants with direct values. And “it” was still relatively readable. I broke the British record on the arcanod scale.

Meet Breakfunoid in 32 lines.

using P = SDL_Rect; struct Brick : public P { bool a = true; }; auto FillRect = &SDL_FillRect; auto MapRGB = &SDL_MapRGB;
struct Paddle : public P { P v{0, 0, 0, 0};
    void operator()() { x = std::max(x += v.x, 0); (x + w >= 800) && (x = 800 - w); }
    void operator()(SDL_Keycode k) { (v.x = (k == 97) ? -1 : v.x); (k == 97) && (x <= 0) && (v.x = x = 0); (v.x = k == 100 ? 1 : v.x); (k == 100) && (x + w >= 800) && (x = 800 - w) && (v.x = 0); }
};
struct Ball : public P { P p{395, 295, 10, 10}, v{0, 0, 0, 0};
    void operator()(SDL_Keycode k) { if (k == SDLK_SPACE && v.x == 0 && v.y == 0) { v = {1, 1}; } }
    bool operator()(const Paddle &paddle) { if (!(SDL_GetTicks() % 2)) { return true; }
        v.x *= (p.x <= 0 || p.x >= 800 - p.w) ? -1 : 1; v.y *= (p.y <= 0) ? -1 : 1;
        if (p.y >= 600 - p.h) { v = {0, 0}; p = {395, 295, 10, 10}; return false; }
        v.y *= (p.y == (paddle.y) && (p.x >= paddle.x) && (p.x <= paddle.x + paddle.w)) ? -1 : 1;
        p.x += v.x; p.y += v.y;
        (SDL_Point &)*this = (SDL_Point &)p;
        return true;
    }
};
int main(int, char**) { SDL_Init(0x30);
    Brick bricks[160]; Ball ball{395, 295, 10, 10}; Paddle pad{350, 550, 100, 20}; int lives = 3; SDL_Event e;
    auto window = SDL_CreateWindow("brkt.cpp", 50, 50, 800, 600, 4); auto s = SDL_GetWindowSurface(window);  auto f = s->format; 
    for (int i = 0; i < 160; ++i) { *(bricks+i) = {1 + ((i % 16) * (48 + 2)), 1 + ((i / 16) * (20 + 2)), 48, 20}; }
    while (true) { 
        while (SDL_PollEvent(&e)) { auto t = e.type; auto sym = e.key.keysym.sym;
          switch 
                       case 768: pad(sym); ball(sym); break;
                       case 769: pad.v.x = 0; break; }
        } if (lives > 0) { pad(); lives -= ball(pad) ? 0 : 1; }
        FillRect(s, 0, MapRGB( f, 0, 0, 0)); FillRect(s, &pad, MapRGB( f, 0, -1, 0)); FillRect(s, &ball, MapRGB( f, -1, -1, -1));
        for (auto &br: bricks) { SDL_HasIntersection(&ball, &br) && br.a && (ball.p.y += 2) && (ball.v.y *= -1) && (br.a = 0); br.a && FillRect(s, &br, MapRGB(f, -1, 0, 0)); }
        for (int i = 0; i < lives; i++) { P r{5 + (i * 15), 585, 10, 10}; FillRect(s, &r, MapRGB(f, -1, -1, -1)); }
        SDL_UpdateWindowSurface(window);
    } return 0;
}

As a result, I got 120 points for the number of lines plus 10 for the feature with lives and minus 30 (maximum) for reading the code. I think they will raise the maximum fine for reading it after this incident.

In general, they laughed and parted ways.

But this is not the end of the story, at home I couldn’t let go of the thought that it is possible to roll more. I definitely saw the rendering code on the business card.

Let the Arkanoid code be on the business card. After waiting a little longer for the laptop, something in this style came out. It’s unreadable, impractical, it won’t work, but it’s cool and works.

#include <SDL.h>
#define RE return
#define OO operator
using R=SDL_Rect;using P=SDL_Point;struct B:public R{bool a=1;};auto $= &SDL_FillRect;
using I=int;I i=0;struct Pad:public R{R v{0}; void OO()(){x=std::max(x+=v.x,0);(x+w >=
800)&&(x=800-w);} void OO()(I k){(v.x=(k==97)?-1:v.x);(k==97)&&(x<=0)&&(v.x=x=0);(v.x=
k==100?1:v.x);(k==100)&&(x+w>=800)&&(x=800-w)&&(v.x=0);}};struct BL:public R{R p {395,
295,10,10},v{0};void OO()(I k){if(k==32&&!v.x&&!v.y){v={1,1};}}bool OO()(Pad &pd){if(!
(SDL_GetTicks()%2)){RE 1;}v.x*=(p.x<=0||p.x>=800-p.w)?-1:1;v.y*=(p.y<=0)?-1:1;if(p.y>=
600-p.h){v={0};p={395,295,10,10};RE 0;}v.y *=(p.y==(pd.y)&& (p.x>=pd.x)&&(p.x<=pd.x+pd
.w))?-1:1;p.x+=v.x;p.y+=v.y;(P&)*this=(P&)p;RE 1;}};I main(I,char**){SDL_Init(0x30); B
bricks[160];BL ball{395,295,0xA,10};Pad pad{350,550,100,20};I l=3;SDL_Event e; auto w=
SDL_CreateWindow("brk",50,50,800,600,4);auto s=SDL_GetWindowSurface(w); for(i=0;i<160;
++i){*(bricks+i)={1+((i%16)*50),1+((i/16)*22),48,20};}while(1){while(SDL_PollEvent(&e)
){I s=e.key.keysym.sym;switch(e.type){case 256:return 0;case 768:pad(s);ball(s);break;
case 769:pad.v.x=0;break;}}if(l>0){pad();l-=ball(pad)?0:1;}$(s,0,0xff000000);$(s,&pad,
0xff00ff00); $(s,&ball,0xffffffff); for(auto&br:bricks){SDL_HasIntersection(&ball,&br)
&&br.a&&(ball.p.y+=2)&&(ball.v.y*=-1)&&(br.a=0);br.a &&$(s,&br,0xffff0000);}for(i=0;i<
l;i++){R r{5+(i*15),585,10,10};$(s,&r,-1);}SDL_UpdateWindowSurface(w);} RE 0;}

https://godbolt.org/z/896s6j883

I’m thinking of making one for myself

All the best!

Z.I. I didn’t sign any NDA for the test, and the “fireflies” knew about this task because they handed it out at game conferences, you know why 🙂

Related posts