pub fn square(s: u32) -> u64 {
if (s < 1) | (s > 64) {
panic!("Square must be between 1 and 64");
}
1 << (s - 1)
}
pub fn total() -> u64 {
((1_u128 << 64) - 1) as u64
}
Instead of using math to calculate the number of grains on a square, you can simply set a bit in the correct position of a u64
or u128
value.
To understand how this works, consider just two squares that are represented in binary bits as 00
.
You use the left-shift operator to set 1
at the position needed to make the correct decimal value.
- To set the one grain on Square One you shift
1
for0
positions to the left. So, ifn
is1
for square One, you subtractn
by1
to get0
, which will not move it any positions to the left. The result is binary01
, which is decimal1
. - To set the two grains on Square Two you shift
1
for1
position to the left. So, ifn
is2
for square Two, you subtractn
by1
to get1
, which will move it1
position to the left. The result is binary10
, which is decimal2
.
Square | Shift Left By | Binary Value | Decimal Value |
---|---|---|---|
1 | 0 | 0001 | 1 |
2 | 1 | 0010 | 2 |
3 | 2 | 0100 | 4 |
4 | 3 | 1000 | 8 |
For total
we want all of the 64 bits set to 1
to get the sum of grains on all sixty-four squares.
The easy way to do this is to set the 65th bit to 1
and then subtract 1
.
However, we can't do this with a u64
which has only 64
bits, so we need to use a u128
.
To go back to our two-square example, if we can grow to three squares, then we can shift 1_u128
two positions to the left for binary 100
,
which is decimal 4
.
Note that the type of a binding can be defined by appending it to the binding name.
It can optionally be appended using one or more _
separators between the value and the type.
More info can be found in the Literals section of
Rust by Example
By subtracting 1
we get 3
, which is the total amount of grains on the two squares.
Square | Binary Value | Decimal Value |
---|---|---|
3 | 0100 | 4 |
Square | Sum Binary Value | Sum Decimal Value |
---|---|---|
1 | 0001 | 1 |
2 | 0011 | 3 |