Plan and done for February-19-2018
What will I learn today?
FreeCodeCamp projects: TicTacToe - start coding.
Done
TicTacToe app
Challenges
- How to implement game engine - what is the algorithm inside it?
- What is a winning in terms of algorithmical calculation - how to calculate that I have winning condition on the board?
- How to find which player's turn next?
- What is 'empty' value in an Array generated by
new Array(number)? - After implementation of minimax I've found myself with an utility value but without moves - how could I add to minimax return any sugestions on the next move?
- How to pass a parameter to an event callback function?
- How to make the engine work in async with UI and prevent itching in a player interaction with the game?
- How to restart the game after we've got either winning or draw conditions?
Solutions
-
Algo - minimax as it described in the Wiki page. Another explanations are at Youtube - academic, less formal.
-
SO gives the algorithm to estimate an answer. I have alternative approach - find masks which represent winning, transform board into binary representation and apply mask to it. If result is the same as mask applied - here's winning position. The question: what is efficiency for each approach? For SO algo the complexity is O(n), n - is dimension of the board. For my approach - O(n^2 + n).
-
I can track the current player or just get it from the board state. I'll use reduce for it:
array.reduce((res,elm) => elm ? res + 1 : res,0). -
Unbelievably long search why my
toStringdidn't work the right way - it just silently swallowed empty values. Here is a good snippet to detect empty values in Array. -
I shouldn't - I've implemented the separate chooseMove() function where I initialize all available moves with their utility values and than I just choose the best or any depending whether utility equal for multiple values or not.
-
We can either bind this with additional paramenter to the function - take a look here. I've tried to use an arrow function as a callback, but it prevents me from removing listener down the road. Final approach is to make cells distinguishable by
idand communicate through the DOM:boardCells.forEach((cell, ndx) => cell.addEventListener('click', e => this.handleBoardClick(e, ndx)), );
-
The broad article states that there are two available options: split intensive function into pieces and run every along with browser animation frames routine or use WebWorkers. As the MDN article says:
The worker thread can perform tasks without interfering with the user interface.
I should try the approach, but later, when all bugs will be fixed and the game will be ready. And I've found another option - Web Animation API.
-
I've implemented it as reinitialization of the whole application - the same routine which is called once an app starts. But here I've encountered another problem - multiple event handler calls and it escalates with each actual trigger. Looks like I add more and more identical handlers with each restart.
I've solved it by light reengineering the code: I don't need to reinitialize the whole app on reset, just draw the clear board and add all event listeners;