Friday JS: a game of 0 lines JS and CSS
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 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 there is a transition 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.
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:
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:
Actually, my code is a bit more complicated, I’m out of habit, I deployed recursion into a loop, and instead of references to other states in
Then we generate an HTML page from each game state object. Walking through the object
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:
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 the githab: you can see the entire code there (link is on the title 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 nevertheless I courageously endured to the end
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 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 there is a transition 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 digression
Написав предыдущую строчку, я вдруг задумался, не является ли выражение «JS-скрипт» тавтологией, как «CD-диск» или «VIP-персона». С одной стороны, вроде как является. С другой, JS — это всё-таки не аббревиатура, а сокращение несколько иной природы. Однако пост всё-таки не о филологии, потому лирическое отступление заканчивается и начинается лирическая атака.
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
current status field, 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’m out of habit, I deployed recursion into a loop, and instead of references to other states in
moves
, they store their string keys 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
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 the githab: you can see the entire code there (link is on the title 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 nevertheless I courageously endured to the end
git add
.