beauty of a binary number game - algorithm

This a fairly known problem ( similar question: number of setbits in a number and a game based on setbits but answer not clear ):
The beauty of a number X is the number of 1s in the binary
representation of X. Two players are plaing a game. There is a number n
written on a blackboard. The game is played as following:
Each time a player chooses an integer number (0 <= k) so that 2^k is
less than n and (n-2^k) is equally as beautiful as n. Then n is removed from
blackboard and replaced with n-2^k instead. The player that cannot continue
the game (there is no such k that satisfies the constrains) loses the
game.
The First player starts the game and they alternate turns.
Knowing that both players play optimally must specify the
winner.
Now the solution I came up with is this:
Moving a 1 bit to its right, is subtracting the number by 2^p where ( p = position the bit moved to - 1). Example: 11001 --> 25 now if I change it to 10101 ---> 21 ( 25-(2^2))
A player can't make 2 or more such right shift in 1 round (not the programmatic right shift) as they can't sum to a power of 2. So the player are left with moving the set bit to some position to its right just once each round. This means there can be only R rounds where R is the number of times a set bit can be moved to a more right position. So the winner will always be the 1st player if R is Odd number and 2nd player if R is even number.
Original#: 101001 41
after 1st: 11001 25 (41-16)
after 2nd: 10101 21 (25-4)
after 1st: 1101 13 (21-8)
after 2nd: 1011 11 (13-2)
after 1st: 111 7 (11-4) --> the game will end at this point
I'm not sure about the correctness of the approach, is this correct? or am I missing something big?

Your approach is on the right track. The observation to be made here is that, also as illustrated in the example you gave, the game ends when all ones are on the least significant bits. So we basically need to count how many swaps we need to make the zeros go to the most significant bits.
Let's take an example, say the initial number from which game starts is 12 the the game state is as follows:
Initial state 1100 (12) ->
A makes move 1010 (10) ->
B makes move 1001 (9) ->
A makes move 0101 (5) ->
B makes 0011 (3)
A cannot move further and B wins
This can be programmatically (java program v7) achieved as
public int identifyWinner (int n) {
int total = 0, numZeros = 0;
while (n != 0) {
if ((n & 0x01) == 1) {
total += numZeros;
} else {
numZeros++;
}
n >>= 1;
}
return (total & 0b1) == 1 ? 1 : 2;
}
Also to note that even if there are multiple choices available with a player to make the next move, as illustrated below, the outcome will not change though the intermediate changes leading to outcome may change.
Again let us look at the state flow taking the same example of initial number 12
Initial state 1100 (12) ->
A makes move 1010 (10) ->
(B here has multiple choices) B makes move 0110 (6)
A makes move 0101 (5) ->
B makes 0011 (3)
A cannot move further and B wins
A cannot move further as for no k (k >=0 and n < 2**k so k =0, 1 are the only plausible choices here) does n-2^k has same beauty as n so B wins.
Multiple choices are possible with 41 as starting point as well, but A will win always (41(S) -> 37(A) -> 35(B) -> 19(A) -> 11(B) -> 7(A)).
Hope it helps!

Yes, each turn a 1 can move right if there is a 0 to its right.
But, no, the number of moves is not related to number of zeros. Counterexample:
101 (1 possible move)
versus
110 (2 possible moves)

The number of moves in the game is the sum of the total 1's to the left of each 0. (Or conversely the sum of the total 0's to the right of each 1.)
(i.e. 11000 has 2 + 2 + 2 = 6 moves, but 10100 has 1 + 2 + 2 = 5 moves because one 0 has one less 1 to its right)
The winner of the game will be the first player if the total moves in the game is odd, and will be the second player if the number of moves in the game is even.
Proof:
On any given move a player must choose a bit corresponding to
a 0 immediately to the right of a 1. Otherwise the total number of
1's will increase if a bit corresponding to a different 0 is chosen,
and will decrease if a bit corresponding to a 1 is chosen. Such a move
will result in the 1 to the right of the corresponding chosen bit
being moved one position to its right.
Given this observation, each
1 has to move through every 0 to its right; and every 0 it moves
through consumes one move. Note that regardless of the choices either
player makes on any given move, the total number of moves in the game
remains fixed.
Since Harshdeep has already posted a correct solution looping over each bit (the O(n) solution), I'll post an optimized divide and conquer O(log(n)) solution (in C/C++) reminiscent of a similar algorithm to calculate Hamming Weight. Of course using Big-Oh to describe the algorithm here is somewhat dubious since the number of bits is constant.
I've verified that the below code on all 32-bit unsigned integers gives the same result as the linear algorithm. This code runs over all values in order in 45 seconds on my machine, while the linear code takes 6 minutes and 45 seconds.
Code:
bool FastP1Win(unsigned n) {
unsigned t;
// lo: 0/1 count parity
// hi: move count parity
// 00 -> 00 : 00 >>1-> 00 &01-> 00 ; 00 |00-> 00 ; 00 &01-> 00 &00-> 00 *11-> 00 ^00-> 00
// 01 -> 01 : 01 >>1-> 00 &01-> 00 ; 01 |00-> 01 ; 01 &01-> 01 &00-> 00 *11-> 00 ^01-> 01
// 10 -> 11 : 10 >>1-> 01 &01-> 01 ; 10 |01-> 11 ; 10 &01-> 00 &01-> 00 *11-> 00 ^11-> 11
// 11 -> 00 : 11 >>1-> 01 &01-> 01 ; 11 |01-> 11 ; 11 &01-> 01 &01-> 01 *11-> 11 ^11-> 00
t = (n >> 1) & 0x55555555;
n = (n | t) ^ ((n & t & 0x55555555) * 0x3);
t = n << 2; // move every right 2-bit solution to line up with the every left 2-bit solution
n ^= ((n & t & 0x44444444) << 1) ^ t; // merge the right 2-bit solution into the left 2-bit solution
t = (n << 4); // move every right 4-bit solution to line up with the every left 4-bit solution
n ^= ((n & t & 0x40404040) << 1) ^ t; // merge the right 4-bit solution into the left 4-bit solution (stored in the high 2 bits of every 4 bits)
t = n << 8; // move every right 8-bit solution to line up with the every left 8-bit solution
n ^= ((n & t & 0x40004000) << 1) ^ t; // merge the right 8-bit solution into the left 8-bit solution (stored in the high 2 bits of every 8 bits)
t = n << 16; // move every right 16-bit solution to line up with the every left 16-bit solution
n ^= ((n & t) << 1) ^ t; // merge the right 16-bit solution into the left 16-bit solution (stored in the high 2 bits of every 16 bits)
return (int)n < 0; // return the parity of the move count of the overall solution (now stored in the sign bit)
}
Explanation:
To find number of moves in the game, one can divide the problem into smaller pieces and combine the pieces. One must track the number of 0's in any given piece, and also the number of moves in any given piece.
For instance, if we divide the problem into two 16-bit pieces then the following equation expresses the combination of the solutions:
totalmoves = leftmoves + rightmoves + (rightzeros * (16 - leftzeros)); // 16 - leftzeros yields the leftones count
Since we don't care about the total moves, just weather the value is even or odd (the parity) we only need to track the parity.
Here is the truth table for the parity of addition:
even + even = even
even + odd = odd
odd + even = odd
odd + odd = even
Given the above truth table, the parity of addition can be expressed with an XOR.
And the truth table for the parity of multiplication:
even * even = even
even * odd = even
odd * even = even
odd * odd = odd
Given the above truth table, the parity of multiplication can be expressed with an AND.
If we divide the problem into pieces of even size, then the parity of the zero count, and the one count, will always be equal and we need not track or calculate them separately.
At any given stage of the algorithm we need to know the parity of the zero/one count, and the parity of the number of moves in that piece of the solution. This requires two bits. So, lets transform every two bits in the solution so that the high bit becomes the move count parity, and the low bit becomes the zero/one count parity.
This is accomplished with this computation:
unsigned t;
t = (n >> 1) & 0x55555555;
n = (n | t) ^ ((n & t & 0x55555555) * 0x3);
From here we combine every adjacent 2-bit solution into a 4-bit solution (using & for multiplication, ^ for addition, and the relationships described above), then every adjacent 4-bit solution into a 8-bit solution, then every adjacent 8-bit solution into a 16-bit solution, and finally every adjacent 16-bit solution into a 32-bit solution.
At the end, only the parity of the number of moves is returned stored in the second least significant bit.

Related

Is there an algorithm to bit shift every n-long bits from a number without overflow?

For example, if I have a number 0101 1111 and I want to shift every 4 bit long section to the left to get 1010 1110. While I could just modulo off each section to get two 4-bit numbers, is there an algorithm that doesn't need to do this?
A naive approach
A first naive appraoch is to slice the 4 bit groups and process them individually. The expected result is obtained with the following for the first group of 4 bits.
(((x & 0xf) // take only 4 bits
<< 1) // shift them by 1
& 0xf) // get rid of potential overflow
For the n+1 th group of 4 bits, it's
(((x & (0xf<<(n*4)))
<< 1)
& (0xf<<(n*4)))
Since this is designed, so that there is no overlap around the 4 bits that are processed, you could iterate, and binary-or the partial results.
A less naive approach
Another approach is to simply shift the full x by 1, causing every 4 bit group to be shifted at once:
0101 1111 -> 1011 1110
We can then easily get rid of the overflow, and at the same time make sure that 0's are injected on the left, by clearing every 4th bit in the result of the shift:
1011 1110
& 1110 1110
---------
1010 1110
1110 is e in hexadecimal. So you need to generate a number with as many 0xe as there are 4 bit segments. In your case it's 0xee if it's just 8 bits. It's 0xeeeeeeeeeeeeeeee if it's 64 bits. Someone told this answer in the comments. Here you have the explanation.
Caution if your underlying data type is signed, because of the sign bit. Do this processing on unsigned integers to avoid any surprise.
Here is one way.
int bits = 0b1111_0001_0011_0111;
int result = 0;
int m = 0b1111;
while(m != 0) {
result |= ((bits & m) << 1) & m;
m <<= 4;
}
System.out.printf("%-7s = %s%n","src", Integer.toBinaryString(bits));
System.out.printf("%-7s = %s%n","result", Integer.toBinaryString(result));
Prints
src = 1111000100110111
result = 1110001001101110

Falling segment reunites with other segments with a probability, determine the expected medium length of the segment

This is a really tough problem, just a heads-up.
We have N segments, numbered from 1 to N and defined by their left and right points, {Left[i],Right[i]}.
The i-th segment is at height N-i. The first segment (the highest one) starts falling while the others remain fixed. If during the fall a segment i intersects another segment j in at least one point, then the two will reunite with the probability P[j]/Q[j], and the obtained segment will keep falling. From the reunion of two segments, {A,B} and {C,D}, the obtained segment will be {min(A,C),max(B,D)}.
You are asked to determine the expected medium length of the first segment (i.e after it reached a height smaller than the height of any of the other segments). If this answer is a rational number U/V, you are asked to determine X such that X*V=U (mod 10^9+7)
Restrictions :
0 < P < Q < 1 000
0 < Left < Right < 1 000 000
N ≤ 100 000
time : 2.5 sec
memory : 32768 kbytes
`
The input contains N on the first line, then on the following N lines there are 4 integers : Left, Right, P, Q, representing the i-th segment [Left, Right] with a probability P/Q to reunite with the falling segment.
Example:
input:
5
35 64 58 873
41 70 407 729
18 90 165 628
10 57 33 104
60 69 152 466
output:
779316733
The answer is approximately 49.813963.
Idea 1
The length of the final segment is R-L where R is the location of the right end, and L is the location of the left end.
Expectation is a linear operation so
E(length) = E(R) - E(L)
We can compute E(R) and E(L) separately, then combined the results.
Idea 2
We can iteratively compute the PDF for the position of the left end.
It starts off being at the left end of the first segment (Left[1]) with probability 1.
When it falls past segment i, there will be an interesting collision if the left end is between Left[i] and Right[i]. We define an interesting collision to be one that affects the position of the left end.
The key point here is that if we need to know the current position of the right end to determine if there is a collision, then it is not an interesting collision! This is because if we need to know the right end, then the segment i must be completely to the right of the start point, and therefore it does not affect the position of the left edge.
So to update the PDF we collect up all the probability mass between Left[i] and Right[i], multiply by the probability of collision, and add the result to Left[i]. (The existing mass in those locations is scaled down by the probability of collision.)
Idea 3
At the moment we have an O(n^2) algorithm made of n iterations of O(n) to count and modify the mass in each range.
However, we can use a data structure such as a segment tree to allow us to perform each iteration in O(logn) time for a total time complexity of O(nlogn).

Non-recursive Grey code algorithm understanding

This is task from algorithms book.
The thing is that I completely don't know where to start!
Trace the following non-recursive algorithm to generate the binary reflexive
Gray code of order 4. Start with the n-bit string of all 0’s.
For i = 1, 2, ... 2^n-1, generate the i-th bit string by flipping bit b in the
previous bit string, where b is the position of the least significant 1 in the
binary representation of i.
So I know the Gray code for 1 bit should be 0 1, for 2 00 01 11 10 etc.
Many questions
1) Do I know that for n = 1 I can start of with 0 1?
2) How should I understand "start with the n-bit string of all 0's"?
3) "Previous bit string"? Which string is the "previous"? Previous means from lower n-bit? (for instance for n=2, previous is the one from n=1)?
4) How do I even convert 1-bit strings to 2-bit strings if the only operation there is to flip?
This confuses me a lot. The only "human" method I understand so far is: take sets from lower n-bit, duplicate them, invert the 2nd set, add 0's to every element in 1st set, add 1's do every elements in 2nd set. Done (example: 0 1 -> 0 1 | 0 1 -> 0 1 | 1 0 -> 00 01 | 11 10 -> 11 01 11 10 done.
Thanks for any help
The answer to all four your questions is that this algorithm does not start with lower values of n. All strings it generates have the same length, and the i-th (for i = 1, ..., 2n-1) string is generated from the (i-1)-th one.
Here is the fist few steps for n = 4:
Start with G0 = 0000
To generate G1, flip 0-th bit in G0, as 0 is the position of the least significant 1 in the binary representation of 1 = 0001b. G1 = 0001.
To generate G2, flip 1-st bit in G1, as 1 is the position of the least significant 1 in the binary representation of 2 = 0010b. G2 = 0011.
To generate G3, flip 0-th bit in G2, as 0 is the position of the least significant 1 in the binary representation of 3 = 0011b. G3 = 0010.
To generate G4, flip 2-nd bit in G3, as 2 is the position of the least significant 1 in the binary representation of 4 = 0100b. G4 = 0110.
To generate G5, flip 0-th bit in G4, as 0 is the position of the least significant 1 in the binary representation of 5 = 0101b. G5 = 0111.

Algorithm for sequence calculation

I'm looking for a hint to an algorithm or pseudo code which helps me calculate sequences.
It's kind of permutations, but not exactly as it's not fixed length.
The output sequence should look something like this:
A
B
C
D
AA
BA
CA
DA
AB
BB
CB
DB
AC
BC
CC
DC
AD
BD
CD
DD
AAA
BAA
CAA
DAA
...
Every character above represents actually an integer, which gets incremented from a minimum to a maximum.
I do not know the depth when I start, so just using multiple nested for loops won't work.
It's late here in Germany and I just can't wrap my head around this. Pretty sure that it can be done with for loops and recursion, but I have currently no clue on how to get started.
Any ideas?
EDIT: B-typo corrected.
It looks like you're taking all combinations of four distinct digits of length 1, 2, 3, etc., allowing repeats.
So start with length 1: { A, B, C, D }
To get length 2, prepend A, B, C, D in turn to every member of length 1. (16 elements)
To get length 3, prepend A, B, C, D in turn to every member of length 2. (64 elements)
To get length 4, prepend A, B, C, D in turn to every member of length 3. (256 elements)
And so on.
If you have more or fewer digits, the same method will work. It gets a little trickier if you allow, say, A to equal B, but that doesn't look like what you're doing now.
Based on the comments from the OP, here's a way to do the sequence without storing the list.
Use an odometer analogy. This only requires keeping track of indices. Each time the first member of the sequence cycles around, increment the one to the right. If this is the first time that that member of the sequence has cycled around, then add a member to the sequence.
The increments will need to be cascaded. This is the equivalent of going from 99,999 to 100,000 miles (the comma is the thousands marker).
If you have a thousand integers that you need to cycle through, then pretend you're looking at an odometer in base 1000 rather than base 10 as above.
Your sequence looks more like (An-1 X AT) where A is a matrices and AT is its transpose.
A= [A,B,C,D]
AT X An-1 ∀ (n=0)
sequence= A,B,C,D
AT X An-1 ∀ (n=2)
sequence= AA,BA,CA,DA,AB,BB,CB,DB,AC,BC,CC,DC,AD,BD,CD,DD
You can go for any matrix multiplication code like this and implement what you wish.
You have 4 elements, you are simply looping the numbers in a reversed base 4 notation. Say A=0,B=1,C=2,D=3 :
first loop from 0 to 3 on 1 digit
second loop from 00 to 33 on 2 digits
and so on
i reversed i output using A,B,C,D digits
loop on 1 digit
0 0 A
1 1 B
2 2 C
3 3 D
loop on 2 digits
00 00 AA
01 10 BA
02 20 CA
03 30 DA
10 01 AB
11 11 BB
12 21 CB
13 31 DB
20 02 AC
21 12 BC
22 22 CC
...
The algorithm is pretty obvious. You could take a look at algorithm L (lexicographic t-combination generation) in fascicle 3a TAOCP D. Knuth.
How about:
Private Sub DoIt(minVal As Integer, maxVal As Integer, maxDepth As Integer)
If maxVal < minVal OrElse maxDepth <= 0 Then
Debug.WriteLine("no results!")
Return
End If
Debug.WriteLine("results:")
Dim resultList As New List(Of Integer)(maxDepth)
' initialize with the 1st result: this makes processing the remainder easy to write.
resultList.Add(minVal)
Dim depthIndex As Integer = 0
Debug.WriteLine(CStr(minVal))
Do
' find the term to be increased
Dim indexOfTermToIncrease As Integer = 0
While resultList(indexOfTermToIncrease) = maxVal
resultList(indexOfTermToIncrease) = minVal
indexOfTermToIncrease += 1
If indexOfTermToIncrease > depthIndex Then
depthIndex += 1
If depthIndex = maxDepth Then
Return
End If
resultList.Add(minVal - 1)
Exit While
End If
End While
' increase the term that was identified
resultList(indexOfTermToIncrease) += 1
' output
For d As Integer = 0 To depthIndex
Debug.Write(CStr(resultList(d)) + " ")
Next
Debug.WriteLine("")
Loop
End Sub
Would that be adequate? it doesn't take much memory and is relatively fast (apart from the writing to output...).

algorithm to check a connect four field

I'm wondering what's the best way to check for a winner on a connect four field.
I'm interested in what you guys think and whether there is some "well-known" algorithm for this sort of problems?
Solution:
I implemented Ardavan's hash-table solution in Python.
I let the algorithm run over every field once. The best checking time with my implementation was 0.047 ms, the worst 0.154 ms and the average 0.114 ms on my Intel(R) Core(TM)2 Duo CPU T9600 # 2.80GHz. This is fast enough for my needs, and the algorithm seems neat to me.
The source code from the Fhourstones Benchmark from John Tromp uses a fascinating algorithm for testing a connect four game for a win. The algorithm uses following bitboard representation of the game:
. . . . . . . TOP
5 12 19 26 33 40 47
4 11 18 25 32 39 46
3 10 17 24 31 38 45
2 9 16 23 30 37 44
1 8 15 22 29 36 43
0 7 14 21 28 35 42 BOTTOM
There is one bitboard for the red player and one for the yellow player. 0 represents a empty cell, 1 represents a filled cell. The bitboard is stored in an unsigned 64 bit integer variable. The bits 6, 13, 20, 27, 34, 41, >= 48 have to be 0.
The algorithm is:
// return whether 'board' includes a win
bool haswon(unsigned __int64 board)
{
unsigned __int64 y = board & (board >> 6);
if (y & (y >> 2 * 6)) // check \ diagonal
return true;
y = board & (board >> 7);
if (y & (y >> 2 * 7)) // check horizontal
return true;
y = board & (board >> 8);
if (y & (y >> 2 * 8)) // check / diagonal
return true;
y = board & (board >> 1);
if (y & (y >> 2)) // check vertical
return true;
return false;
}
You have to call the function for the bitboard of the player who did the last move.
I try to explain the algorithm in my answer to the question "How to determine game end, in tic-tac-toe?".
Each cell can only attribute to a maximum number of 12 winning combinations. (4 horizontal, 4 vertical and 4 diagonal). Each combination would have 4 cells including the one under consideration. And these numbers are going to be much lower for the cells closer to the sides. So it would make sense to pre-compile these combinations and store a hash of hash of related cells which can make a single play a winner. This way after each cell is player you simply pull out the related combinations/cells to check if it's a winner.
This is related to this question: How to find the winner of a tic-tac-toe game of any size?
The twist is the 7x6 board with 4 in a row winning rather than a NxN board with N in a row winning. But it is trivial to adapt the solution to NxN tic tac toe to connect 4.
EDIT: Actually, it's not quite trivial to adapt the other solution to this one. But you can get there with a little bit of extra work.
Store a count for each player for every row, column, diagonal and anti-diagonal that could ever have 4 pieces in a row. When that count hits 4 or more for either player, check to see if that row/column/diagonal/anti-diagonal has the four pieces in a row. If it does, that player wins!

Resources