Game design
When designing the game, our main goal was to prepare a fun entertainment for programmers, as well as to do something interesting as a part of the work in our company. So far, we had not had any competences in creating games, which is why it stroke us a significant challenge. In the first place, we focused on what this game really was. After coming up with the initial plan, we stepped up to the plate.
As a part of the work on the game, we decided to take a hackathon and split into groups performing specific tasks. With such an 8-hour work division, we were able to realize the appearance of opponents in the game, the entire layout, and the foundation of both tasks and APIs of the entire system. During the next stage, we gathered for 4-hour meetings once a month due to which we managed to finish the game in 3 meetings.
Implementation
As we specialize in RubyOnRails, we chose the technology as the leading one. However, the game was not meant to be textual and therefore the approach to it was reflected in the SPA type application. As part of the task, we worked on a well-known pipeline of assets from rails (in 2016 there was nothing better in principle) and the entire javascript based on our proprietary code with the help of TypeScript. In the application, there was a standard division of responsibilities: Rails as an asset and API source, javascript and related as interaction with the user. Here, however, it functioned as a hybrid and some views were simply rendered from rails while some of the others – from JS.
Typescript
It was our first experiment in this field. These were times when people believed in CoffeScript success. Using of TypeScript required introduction of a typescript-rails gem. Unfortunately, this was not the final, as typescript, being statically typed language, also required this from the libraries attached by default to rails.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/jquery.d.ts (especially when using the embedded asset management system with rails).
Cody as a game required a lot of dynamics on the browser side, as well as the modification of DOM’s tree. Using TypeScript instead of vanilla javascript was a huge leap in the quality of code, the very presence of classes and encapsulation was very tempting for us.
API and SPA
In 2019, SPA applications are managed by using the magnificent React or Vue libraries. However, in 2015, we did it in a different way. The previously mentioned typescript was helpful in the implementation of the game, while jQuery revoked all the work related to the xml http request. Now we can use fetch, whilst back in those days `$ .ajax` was all that was needed for the job. Take a look at our client api!
If it was api then you had to solve the authentication problem somehow, didn’t you? Well, that’s right. But in that case, we went after (is it possible to write here – we used the band?!) the band and in the rails session we created cookie_key and afterwards saved it in the database. Hence we knew that everything was more than fine.
https://github.com/codesthq/cody_the_game/search?q=cookie_key&unscoped_q=cookie_key
The game status was stored in the database and information about how many users had points were coming from the database (is it the very same database? Can we just change it by a pronoun?). ACID always comes in handy when there is no caching on the system side;)
In case of the spa, it is the best without reloading the page. We have solved it classically and the html anchor was the best solution without expanding unnecessary dependencies. Because who would use turbolinks?
SnapSVG
If we design a game, it must be released only with great graphics and animations. Back then we spent many hours wondering how to meet those demands in our application. On one hand, the canvas can do miracles, on the other, in a clean html is much easier to catch up with and everyone knows it. After a painstaking search for the best solution, we figured out that the combination of these two solutions is svg. It allows you to easily present graphics in a vector, it is written in the markup language and, what is the most important, it can be modified on the fly. Importantly, there is a library for svg files that works similarly to jQuery and allows operations on the image in a unified manner. This is: http://snapsvg.io, we have very nice memories of that particular solution usage.
An example of how we used snap.svg you can find below:
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/intro.js.ts
The haml file itself with the graphic skeleton:
https://github.com/codesthq/cody_the_game/blob/master/app/views/game/show.html.haml
As you can see, it’s almost like a normal DOM tree and a regular rails app!
TrustedSandbox
Well, finally we had API, Graphics, SPA. But what about the implementation of solutions sent by the users?
The first thing that comes to mind is the eval method, but we are not crazy;) Back in 2016, the docker was on the rise, so it felt like a natural choice. The containers themselves did not guarantee complete isolation and protection, which is why we used a ready solution in the Ruby called https://github.com/vaharoni/trusted-sandbox. It allowed to better protect the code before leaving the sandbox and in a standardized manner configure the operating system requirements. It was very important to properly limit the code execution time, the memory needed to operate and the CPU cycles. Our configuration is available below
https://github.com/codesthq/cody_the_game/blob/master/config/trusted_sandbox.yml.example
Of course, the same trusted sandbox did not guarantee anything, which is why we came up with a special website to run the code.
https://github.com/codesthq/cody_the_game/blob/master/app/services/task_runner/base_task.rb
Each of the tasks had its own test case, which allowed us to verify the correctness of the implemented solution. This was done by injecting the user code into the test case so that everything was run in isolation.
https://github.com/codesthq/cody_the_game/blob/master/app/challenges/challenge/case.rb
Of course, this action cost quite a lot of time and, while collecting the responses, we could not afford to run the sandbox, so we only saved the code in the database, creating a submission and then, using long pooling, we asked the endpoint to obtain the code status. This allowed us to relieve the application server and verify the data appropriately. Of course, we also had to protect ourselves against “crashing the script” and therefore we limited the number of server queries using the ttl variable, which can be seen below.
Summary of competition
Until September 2011, the game statistics were as follows:
– numbers of sessions: 1945 – sent tasks: 4476 – sent correct answers: 1624 – finished the game: 31
As you can see, the biggest stairs started in task # 2 because it was no longer an ordinary hello world example.
Read also:
A quick dive into Ruby 2.6. What is new?