Strategy for a Nim variation game - StoneGameStrategist - SRM 309 - c++

I'm fairly new to game theory and have understood only normal nim game where you remove stones from piles with no condition and the last player to remove wins. But then I came across a nice problem while reading Game theory tutorial on Topcoder. The gist is as below:
You and a friend are playing a game in which you take turns removing stones from piles. Initially, every pile has at least as many stones as the pile to its left. This property must be maintained throughout the game. On each turn, you remove one or more stones from a single pile. You and your friend alternate turns until it is no longer possible to make a valid move. The last player to have made a move wins the game. Note that if you remove all the stones from a pile, it is still considered a pile.
You are said to have made a "winning move" if after making that move, you can eventually win no matter what your friend does. You are given a int[] piles representing the number of stones in each pile from left to right. It is your turn to move. Find a winning move and return it as a String formatted as "TAKE s STONES FROM PILE k" (quotes for clarity only), where s and k (a 0-based index) are each integers with no leading zeros. If there are multiple winning moves, choose the one that minimizes s. If there is still a tie, choose the one that minimizes k. If no winning move is possible, return the String "YOU LOSE" (quotes for clarity only).
Removal of stones here has a condition such that you need to maintain the overall non-decreasing order, which is becoming a roadblock for me in coming up with a logic. I tried reading the editorial for that, but unfortunately couldn't grasp the idea behind it. Can anyone please explain the solution in a more simple terms?

The editorial does not explain how to solve the original game of Nim, but only provides a link to the Wikipedia page (where the solution can be found).
The editorial just explains how to map the Topcoder problem to that of a regular game of Nim:
First, the game can be transformed into one where the piles have the difference between the original piles (so the 3 6 6 example becomes 3 3 0).
Then the order of the piles is reversed (so the example becomes 0 3 3).
Then a move in this new game becomes a two-step process: remove stones from one pile and add it to the previous one (in the example, the winning move takes 3 from the last and add them to the middle pile, becoming 0 6 0).
Then if you just look at the odd-numbered piles (#1, #3, #5, etc), you get the regular game of Nim, and can apply a documented algorithm on that (so 0 3 3 is the same as a Nim position of 0 3).
The given explanation for that is thus:
any move on an odd-numbered pile becomes just like a move in the normal game of Nim;
any move on an even-numbered pile can be negated by just moving the same number of stones from the receiving odd-numbered pile to the next even-numbered pile (so the same losing position can be imposed again on the player).

Related

Algorithm Design: Best Way to Represent a 2D Grid, with Boundary Digits, in C++?

I like working on algorithms in my spare time to improve my algorithm design skills. I tackle Jane Street's monthly puzzles as my 'monthly challenge'. I've previously developed algorithms to solve their October Puzzle, and have solved their November puzzle by hand.
I solved their November puzzle (Hooks #6) by hand, but only because I'm not sure how to solve it (and future puzzles) that involve a grid with a numbered border, computationally. I'm not sure how I'd go about setting the foundation this type of problem.
For instance, many of their problems involve a 2D grid with numbers on the border of the grid. Furthermore, a recurring theme is that whatever is in the grid must meet multiple conditions that involve looking at that number from different sides of the grid. For example, if I have the following 2 by 2 grid, with 4 numbers outside its boundaries,
_ _
5| | 45
5|_ _| 15
Place four numbers in the grid such that, when you
look at the grid from the left, at least one number
in that row is the border number.
In the case of the top left of the 2 by 2 grid,
looking at it from the left means the number 5 must be in either (0,0) or (0,1).
In addition, when looking at that row from the right, the product
of the numbers in the row must equal the boundary number on the right.
In the case of the top right of the 2 by 2 grid,
looking at it from the right means the number 9 must be in either (0,0)
or (0,1), as 9 * 5 = 45.
Hence, the first row in the 2 by 2 grid can either be 5 and 9, or 9 and 5.
One of the solutions for this problem, by hand, is
(0,0) = 5, (0,1) = 9, (1,0) = 5, (1,1) = 3
but how can I go about this computationally?
How can I go about translating these grid-like problems with differing conditions based on the position one "looks" at the grid into code?
Thanks!
I'm not convinced these puzzles were meant to be solved via code. They seem idiosyncratic and complicated enough that coding them would be time-consuming.
That said, the November puzzle in particular seems to have rather limited options for "fixing" a number placement. I would consider a backtracking algorithm that keeps a complete board state and has ready methods that evaluate if a particular row or column is not breaking a rule, as well as the "free square" rule.
Then try each possible placement of the numbers given by the black indicators, ordered -- there aren't that many, considering they concatenate squares -- and call the evaluation on the affected rows and columns. Given the constraints, I think wrong branches would likely terminate quickly.
It seems to me it's more or less the best we can do since there don't seem to be clear heuristics to indicate a branch is more likely to succeed.
If you are looking for a data structure to represent one filled grid, I would recommend a struct row containing numbers left and right and a std::vector of numbers. A grid would be a vector of rows. You can write methods that allow you to pass it functions that check conditions on the rows.
But solving these problems in a generic way seems complicated to me. Different rules can mean very different approaches to solving them. Of course, if the instances are always this small, one can probably just try all (reasonable) possible fillings of the grid. But this will very fast become infeasible.
You can maybe implement somewhat generic algorithms, if there are rules that are similar to each other. For example a fixed value for the sum of all numbers in a row is a very similar problem to having a fixed value for the product.
But without constraining the possible rules and finding some similarities in them, you will have to write specific solver code for each and every rule.

Method for avoiding re-visiting of nodes in a large DFS?

I'm exploring a tree of moves for a match-3 type game (with horizontal piece swapping), using a DFS to a depth of 4 moves ahead (because working towards bigger clear combos is much higher scoring). I'm evaluating each possible move of each board to look for the best overall next move to maximise score.
I'm representing the game board as a vector<char> with 100 chars per board, however my current DFS implementation doesn't check if a given board state has already been evluated (there's multiple move sequences that could lead to a given board state).
Given that each board has 90 possible moves, a DFS search to depth 4 evaluates 65,610,000 board states (in 100ms), and therefore I'd assume it's impractical to store each board state for the sake of DFS pruning to avoid re-evaluating a given board state. However, I recognise I could significantly prune the search tree if I avoid re-evaluation of previously evaluated states.
Is there an efficient and or memory conserving method to avoid re-evaluating previously evaluated board states in this DFS?

Get all build orders from a given model.

I have problem. I need for my work all possible build orders for some components. As a simple example you can imagine a simple Lego pyramid:
http://i.stack.imgur.com/Y7Lcr.jpg
I tried some kind of DFS but it didn't work out. There are missing some possbilities at the end.
Can anyone help me with that? Language should be C++ but I just need a hint not a complete algorithm.
Some informations: The models are available as XML files. There you can find all neighbourhood relationships in all 3 directions (x, y, z). All pieces have an unique name/id. The beginning is not defined. There is no restriction in the build order. So you don't have to finish one level of the pyramid to start another one. I know there are a lot of possible build orders. Even the 3x3-base on its own has a lot of possibilities (nine factorial). But it doesn't matter at the moment.
Please I need help.
Greetings,
Eric
First, treat each layer (or "course") as an independent problem. Consider the nine bricks on the bottom; ignoring all others, there are 9! possible orders, so generate those, call them P. Likewise the 4! possible orders for the middle bricks are Q. We can ignore the single brick at the top for now.
Iterate over P and Q. Given an ordering of the bottom bricks, p, and of the middle bricks, q, it may be that the first move of q (i.e. laying the first mid-level brick) is possible before the bottom is complete, so we can intersperse that move with the moves of p; for each permitted time of the first of q, iterate over the permitted times of the second of q, and for each of them iterate over the permitted times of the third, and so on.
Notice that the top brick must always be placed last. Good thing, too.
Is that enough to go on?
If there aren't any limits to the order of the placement, then there are exactly n! different permutations of the orders that the blocks can be placed. In that case, a simple solution is to put all the blocks (or rather, their id's) into a vector and generate all the permutations with std::next_permutation.

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.

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.