Perhaps many of the old-timers remember the epidemic of articles with headlines like "% something% in 30 JS lines". And also followed the epic post “
Playing 0 lines of code on pure JS ”, after which the epidemic abruptly disappeared. Fully aware that I would never surpass this masterpiece, five years later I decided to drop my five kopecks.
Ladies and gentlemen, your attention is invited to the game "Tic-tac-toe" in zero lines of JS, as well as, in contrast to the game mentioned above, in zero lines of CSS (including inline styles). Only naked HTML, only hardcore.
→
Link to the game')
It looks awkward, but it will work in any browser. Under the cut, I'll tell you why the game without JS was in the “Friday JS” category, as well as other dirty details. However, I will not reveal America to anyone, if you are an experienced coder, you may not even enter under kat
Actually, everything is very stupid. The game consists of almost 6 thousand pages of static HTML, linking to each other. When poking on the cage of the playing field, a transition takes place to the page where the move into this cage has already been made. Obviously, writing 6 pages by hand is a pleasure below average. Therefore (surprise!) Pages are generated by JS scripts using NodeJS.
Lyrical digressionHaving written the previous line, I suddenly wondered if the expression “JS-script” is not a tautology, like “CD-disk” or “VIP-person”. On the one hand, it seems to be. On the other hand, JS is not an abbreviation, but a reduction of a somewhat different nature. However, the post is still not about philology, because the lyrical digression ends and the lyrical attack begins.
First, we build the so-called game tree - a collection of all possible game states and transitions between them. The initial state of the game in my code is as follows:
const initialState = { player: PLAYER_X, field: Array.from(Array(9)).map(() => EMPTY_CELL), moves: {} }
It contains information about whose turn is now and what is the state of the playing field. In the future, it will also contain information about what moves can be made and what states they will lead, as well as some other nice things.
Then we begin, I apologize for the tautology, from the initial state and do the following:
- We check whether the state is terminal (the victory of the crosses, the victory of zeroes, the draw).
- If so, add this information to the state object and end it.
- If not, go through all the cells of the field.
- For each empty square of the field, we create a new state of the game, in which the current player made a move into this cell, and the move went to the next player.
- In the
moves
field of the current state, we add an entry about a possible move. The key in this entry is the cell index, and the value is a reference to the new state. - We repeat this algorithm recursively for all newly appeared states.
Actually, my code is a bit more complicated, I habitually unwrapped the recursion into a loop, and instead of references to other states in
moves
, their string keys are stored in some kind of associative array. But this is all the details.
Then we generate an HTML page from each game state object. Walking through the object of
moves
, we fill in the empty cells of the field with links to pages corresponding to the moves made to these cells. Then we transform the one-dimensional array of the field into a two-dimensional HTML table. We add all sorts of nice little things like instructions that the player goes, and links to the home page - and voila!
In addition to the mode, when both crosses and zeroes are put by a person, in my mega-indie hit there is also an opportunity to play against the iron brain. This is achieved as follows:
- First, recursively (actually not) for each game state the expected result of the game is calculated - the one that will be achieved if both sides play perfectly.
- Then the game tree is modified as follows: instead of the player’s move, we now make two moves at once. The second move - the course of artificial intelligence. In this case, of all the possible answers to the player's turn, the one with the best expected result is selected. Thus, by poking at an empty cell, the player immediately moves to the position where a cross (or zero) appeared in this cell, and a zero (or cross) appeared in some other cell.
- All game positions corresponding to the moves that the AI does not make are ruthlessly discarded.
- Then HTML is generated from the remaining positions into a separate daddy - absolutely similar to the case of two players.
According to similar principles, you can implement any game with a not very big tree. However, if I want to do chess in a similar way, it seems to me that the githab will refuse to host it =)
Speaking of github: you can see the entire code there (the link is on the main page of the game). On this, in general, everything. Goodbye, girls and boys. Until new meetings.
PS Replacing line breaks from Windows-style to Unix-style is a very long time when it comes to 6 thousand files. I regretted that I did not take care of this at the stage of writing the code, but still, I courageously endured to the end of
git add
.