MinMax Simple Demonstration for TicTacToe - c++

I have been pulling out my hair trying to figure out how the MinMax algorithm, and hopefully the alpha-beta pruning algorithms work. I'm confused as to the recursion that occurs.
Firstly, does each intermediate board get scored? or only terminal game boards.
Secondly, what exactly is being returned? how does the program know where to place the next move? I see that im supposed to return the board score (in tictactoe, -1,0,1) but how does the program know which move should be played next.
I have tried finding a simple C or c++ program to demonstrate this, but I have not had much luck. I am trying to learn this alogrithms I can create a presentation for the rest of my computer programming class.
Thanks a lot!
V

Only terminal positions (after quiescence search) are scored. Non-terminal positions compare the score returned by a recursive minimax() call to the best score returned so far. In the case of alpha-beta the returned score is also compared to the alpha value.
The point of minimax is producing a score. Your mistake appears to be thinking that the minimax search function needs to return the best move. It can be coded that way, but it might be simpler for you to instead have a top level loop in another function that executes a move, uses minimax() to produce a score and unexecutes the move. Keep track of the move with the best score and return that move when the loop completes or the time to choose a move runs out.

Related

Is this recursive Tower of Hanoi Algorithm a type of uninformed search?

void Form(int N, char pegA, char pegB, char pegC) {
if (N == 1)
cout<<"move top disk on peg "<<pegA<<" to peg"<<pegC<<endl;
else {
Form(N-1, pegA, pegC, pegB);
cout<<"move top disk on peg "<<pegA<<" to peg"<<pegC<<endl;
Form(N-1, pegB, pegA, pegC);
}
}
This is a recursive algorithm for the Tower of Hanoi Game. Can this be a form of depth-first search? If not, what is it? thanks
This isn't a depth-first search, because we know which move to make each time, so there's no choice. You can think about it that way. Nothing more than that.
Look, in the case of Depth first search, what do we do? We go deeper and try to find the correct way to go. But here, can you show me one move that was unnecessary? There isn't any.
So this is a simple recursive approach, where we solve smaller instances of the problem, and then construct the solution for the larger one, simply, from the smaller ones' results. That's it.
This is not a depth first search.
It is a recursive tree traversal... dive?
The logic of which move to make is built into the algorithm, and it cleverly uses recursion to handle each sub-tower transition. There is no searching here.
The algorithm works in the following way
End of recursion:
when there is one disk remaining, move it to the destination peg
this is the end of each sub-tower move
Recursive logic:
move all disks above the one we are interested in to another peg
output the move command for the disk we are interested in
move all the disks we moved before on top of the disk we just moved.
The way it does this, is by the clever (and confusing) manipulation of the peg references. it remaps which are the source and destination pegs when it makes the second recursive call.
Another thing to note:
There is no persistent state in this algorithm. The only state each layer cares about is the state of n and only then if it is 1 or not. On function entry, the state of the current layer (on start peg) and all layers above (also on start peg) is known and the state of any disks below the current is unneeded.
This is why nothing needs to actually be moved; as the state is known, the knowledge about the changes in state can be encoded into the algorithm (and are, by the changed order of the pegs passed into the recursive calls). There is no need to base decisions off the current state, and so no need to effect a state.

How do i shorten the code in Pascal if I have one part repeating in multiple if functions?

i started learning Pascal on my own and i want to create a program where i will calcualte the number of possible moves for a horse to make in 2 moves if i know it's starting possition. So i know how to do it, first i calcualte if it's possible to move on all 8 sides (2 up and 1 left, 2 up and one right, 2 left and one up...) and if it is possible then i do it again for the second move, but then i would have the same code i used to calculate the possible moves the first time repeating for 8 times. Sorry if it's a dumb question, if you can give me some tutorial on this matter, i just started learning, i don't even know if it's possible to do this.
You can create a Function for your calculation. It could return the number of possible moves from a given location.
Something like this:
Function calcMoves(pos : Position) : integer
Begin
...logic...
calcMoves := theNumberOfMovesThatAreLegalFromPos
End
Sorry if the syntax is off, it's been a while since I did stuff in Pascal.
However, the idea is that you can now reuse the calculation.
What might be even better is to have a function that calculates not only the number of allowed moves, but also the position. You will need to return some kind of Array or collection. This way you could call the function once with the starting position as argument and then iterate through all possible positions after that move, using the end position of the first move as start position for the second move. That's what I would do, but I really cannot remember how collections were working in Pascal.

What exactly is a board in the minimax function and how is it implemented?

So I was recently looking at the minimax function which is used in zero sum games. I understood it perfectly, other then how the board is implemented for the actual function:
For example this sample implementation I found has this declaration:
int miniMax(Board eval, int iterations)
My only question is what exactly is Board? Is it a struct, class, array or some other structure? Also how would I implement a sample board for mini-max, like a tic-tac-toe board (As a example)? Couldn't find anything on Wikipedia or Google.
Board is just the current board game. It could be any structure you use to represent the board of the game.
When called first, the minimax function would receive the current board configuration, reached by the different plays made so far (the current state of the game). In the minimax function what you do is modify the board, each modification should represent a possible move according to the game rules. Each of those modified boards should be passed as argument to a new minimax call. Once you reach a certain depth (this is, a number of iterations), you select the best move using an evaluation function to give a score to every modified board and choosing the one with the highest score.
The algorithm you are reading is generic and could work for any game. You might define Board according to convenience, that is, what suits best for the board of the game you want to represent.
For tic-tac-toe, you might want to represent the board with a 3x3 array so you might change Board:
int miniMax(char board[3][3], int iterations)
Or perhaps, you may want to represent your board using 2 bits for each square:
typedef struct {
unsigned square1: 2;
unsigned square2: 2;
unsigned square3: 2;
unsigned square4: 2;
unsigned square5: 2;
unsigned square6: 2;
unsigned square7: 2;
unsigned square8: 2;
unsigned square9: 2;
} Board;
Though, for tic-tac-toe you don't need a lightweight board representation since its maximum depth is just 9. I'm just giving you examples to let you understand it can be any structure you use to represent the board game.
If you are going to deal with minimax function and the game is much more complex than tic-tac-toe, you should seriously consider using alpha-beta pruning which is a big improvement.
EDIT: I think you shouldn't call your board "eval" since that can be confused with the evaluation function which is a totally different thing.
The board, as you write it, is just the common structure that is used an minimax and many other decisional tree algorithms.
It is meant to be the structure that contains the information about a specific state of the game. In the algorithm itself, from a logical point of view, this parameter should be unmodifiable in the sense that you will do moves on the board and generate new board snapshots (so old ones are not modified) while you are going deep in the tree of moves that you are evaluating to find the better strategy.
Indeed it is useful to internally have two elements in the board: the set of rules (that you can apply to effectively modify its state by doing moves) and a state, which will change at every iteration (even if the board itself it's still the same) and that is the object that will be used to evaluate how good a move is for a player (when reaching maximum depth so that you are forced to give an estimate of the goodness of the move just by the state).
So it can be anything, it's just a conceptual parameter. If you really want something more practical I'd imagine it in a way similar to:
class BoardSnapshot {
Board b;
float alpha;
State state;
int evaluate();
}
class Board {
List<Players> players;
List<Rules> rules;
State applyMove(State current, Player player, Rule rule, params ...);
}
So that you initialize it with a BoardSnapshot with no current state and you apply a rule and generate a new state which will be a snapshot of the tree branch currently chosen.

Addressing "procrastination" in minimax

I'm implementing minimax for a small game and am noticing something that I'm calling "procrastination". Boiled down to a very simple example:
In a capture-the-flag game, the flag is one square UP from player A, and player B is 50 spaces away. It's A's turn, and he can search 6 moves ahead. What I'm seeing is that all possible moves have a value of "Win" since A knows he can get to the flag before B even if he doesn't grab it immediately. So if UP is the last move in the ordering, he'll just go LEFT and RIGHT for a while until B is within striking distance and then he has to finally get the flag.
At first the behavior looked like a bug, but stepping through it I convinced myself that each move really is a "Win", but the behavior is not good. I could influence the evaluation by making a flag captured 4 moves from now less valuable than a flag captured now, but I wondered if there was an aspect to the minimax search than I'm missing? Is there the any concept of a high score earlier being most desirable than an equally high score obtained only later?
There's nothing in the minimax search itself that would make winning sooner preferable. Since all terminal positions evaluate to the same score, the algorithm effectively chooses a move at random. Make your evaluation function decrease the winning score slightly for each level deeper in the tree where it is called and minimax will choose to win sooner.

Data structure for a random world

So, I was thinking about making a simple random world generator. This generator would create a starting "cell" that would have between one and four random exits (in the cardinal directions, something like a maze). After deciding those exits, I would generate a new random "cell" at each of those exits, and repeat whenever a player would get near a part of the world that had not yet been generated. This concept would allow a "infinite" world of sorts, all randomly generated; however, I am unsure of how to best represent this internally.
I am using C++ (which doesn't really matter, I could implement any sort of data structure necessary). At first I thought of using a sort of directed graph in which each node would have directed edges to each cell surrounding it, but this probably won't work well if a user finds a spot in the world, backtracks, and comes back to that spot from another direction. The world might do some weird things, such as generate two cells at one location.
Any ideas on what kind of data structure might be the most effective for such a situation? Or am I doing something really dumb with my random world generation?
Any help would be greatly appreciated.
Thanks,
Chris
I recommend you read about graphs. This is exactly an application of random graph generation. Instead of 'cell' and 'exit' you are describing 'node' and 'edge'.
Plus, then you can do things like shortest path analysis, cycle detection and all sorts of other useful graph theory application.
This will help you understand about the nodes and edges:
and here is a finished application of these concepts. I implemented this in a OOP way - each node knew about it's edges to other nodes. A popular alternative is to implement this using an adjacency list. I think the adjacency list concept is basically what user470379 described with his answer. However, his map solution allows for infinite graphs, while a traditional adjacency list does not. I love graph theory, and this is a perfect application of it.
Good luck!
-Brian J. Stianr-
A map< pair<int,int>, cell> would probably work well; the pair would represent the x,y coordinates. If there's not a cell in the map at those coordinates, create a new cell. If you wanted to make it truly infinite, you could replace the ints with an arbitrary length integer class that you would have to provide (such as a bigint)
If the world's cells are arranged in a grid, you can easily give them cartesian coordinates. If you keep a big list of existing cells, then before determining exits from a given cell, you can check that list to see if any of its neighbors already exist. If they do, and you don't want to have 1-way doors (directed graph?) then you'll have to take their exits into account. If you don't mind having chutes in your game, you can still choose exits randomly, just make sure that you link to existing cells if they're there.
Optimization note: checking a hash table to see if it contains a particular key is O(1).
Couldn't you have a hash (or STL set) that stored a collection of all grid coordinates that contain occupied cells?
Then when you are looking at creating a new cell, you can quickly check to see if the candidate cell location is already occupied.
(if you had finite space, you could use a 2d array - I think I saw this in a Byte magazine article back in ~1980-ish, but if I understand correctly, you want a world that could extend indefinitely)