Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Minimax implementation #171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 27, 2020
Merged

Minimax implementation #171

merged 4 commits into from
Apr 27, 2020

Conversation

krzysztof-grzybek
Copy link
Contributor

Fixes #167

Hi Minko,
As I started implementing, I turned out that this algorithm can't be tested without any game. It just needs some game rules to decide which move will be the best.

To fix that, I implemented a simple tic tac toe game.

Another weird looking thing might be the fact, that algorithm function receives 3 function arguments. This is needed because of the same reasons.

I realize that this might be odd. If You think that it doesn't fit this repo, that's fine.

@mgechev
Copy link
Owner

mgechev commented Apr 22, 2020

@krzysztof-grzybek looks good! I'll add a reminder for myself to take a look at the PR in the next few days.

const board = state.board;
return {
board: [
...board.slice(0, move.y),
Copy link
Owner

@mgechev mgechev Apr 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit hard to read. Something like this for updating the board should be easier to understand:

const newBoard = state.board.map(row => row.slice());
newBoard[move.x][move.y] = state.turn;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever! Fixed.

* @return {{score: Number, move: *}} which contains the minimum coins from the given
* list, required for the change.
*/
function minimax(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some parameters which don't change over time:

  • getPossibleNextStatesFn
  • isGameOverFn
  • getScoreFn

We can have a higher-order (builder) function, which accepts them and returns a new function, which does the rest:

const minimaxBuilder = (getPossibleNextStatesFn, isGameOverFn, getScoreFn) => {
  const minimax = (state, maximize, depth, alpha, beta) => {
    // ...
  };
  return minimax;
};

This way we'll change the public API a bit:

const minimax = minimaxBuilder(...);
const result = minimax(...);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea! Fixed.


alpha = Math.max(alpha, result.score);

if (alpha >= beta) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used for an optimization so we stop the loop earlier?

Copy link
Owner

@mgechev mgechev Apr 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we stop when alpha === beta can't we miss later cases when alpha is larger than beta, which will lead to a better outcome?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, it's an optimization called "Alpha-beta pruning".
That's not the case. If alpha is larger then beta, then we know that this whole leaf won't be chosen anyway. I couldn't explain it better than 20 seconds of this video.

@@ -0,0 +1,170 @@
var minimax = require('../../src/others/minimax.js').minimax;

describe('Minimax with tic tac toe', function () {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fantastic example! As you suggested in your comment, it's leaning a bit towards an integration test.

I think, having a simpler game is fine as well. This way we won't need that much logic to setup our tests and they'll be less error prone. Consider a game where each next step is a binary decision, and the leafs of the binary tree determine which player is the winner.

I really like this example, so I'd love to keep it, and also add another test group which tests the minimax example with a simpler binary game.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you like it!
Sounds reasonable. I'm not sure if I follow the idea of the simpler game. What do you mean by the leafs of the binary tree determine which player is the winner? Should I create some binary tree with one "winning leaf"?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't have to be a real game, it can be any game. My proposal is for something like this:

     o
   /    \
  o      o
 /  \   /  \
1   -1 1   -1

If we get 1 player "A" wins, otherwise, if we get -1 player "B" wins. It's pretty much pre-defined, depends on who would start first. It'll be easier to reason about IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I got it. Indeed, it's much simpler.


beta = Math.min(beta, result.score);

if (beta <= alpha) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Owner

@mgechev mgechev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left few comments. Great work!

krzysztof-grzybek and others added 2 commits April 25, 2020 14:34
@krzysztof-grzybek krzysztof-grzybek force-pushed the minimax branch 2 times, most recently from 00f0d27 to c995e08 Compare April 26, 2020 13:25
@krzysztof-grzybek
Copy link
Contributor Author

I fixed all the issues.

@mgechev mgechev merged commit 01caa0d into mgechev:master Apr 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Minimax algorithm implementation
2 participants