Changing the variables around strings in a list of lists - list

I am programming a minesweeper game and i have encountered a problem and i can't solve it on my own. I want to change the 0's around the M's to 1 if one M is close to it, a 2 if two mines is close to it and so on. I have written this code:
hiddenfield = [[0, 0, 0, 0, 0, 'M', 0, 0, 0, 'M'],
[0, 0, 0, 'M', 0, 0, 0, 'M', 'M', 'M'],
[0, 0, 'M', 0, 'M', 0, 0, 'M', 0, 'M'],
[0, 0, 0, 0, 'M', 0, 0, 0, 0, 0],
[0, 0, 'M', 0, 'M', 0, 0, 0, 0, 0],
[0, 0, 0, 'M', 0, 'M', 'M', 0, 0, 0],
[0, 0, 0, 'M', 0, 0, 0, 'M', 0, 0],
[0, 0, 0, 'M', 0, 0, 0, 0, 0, 0],
[0, 'M', 'M', 0, 'M', 0, 0, 0, 0, 0],
['M', 0, 0, 'M', 0, 0, 0, 0, 'M', 0]]
for i in range(0,len(hiddenfield)):
for j in range(0,len(hiddenfield)):
try:
if hiddenfield[i][j] == 'M':
hiddenfield[i+1][j] += 1
hiddenfield[i-1][j] += 1
hiddenfield[i][j+1] += 1
hiddenfield[i][j-1] += 1
hiddenfield[i+1][j-1] += 1
hiddenfield[i-1][j+1] += 1
hiddenfield[i+1][j+1] += 1
hiddenfield[i-1][j-1] += 1
except IndexError:
continue
def showMineFieldHidden(hiddenfield):
border = list(range(0,len(hiddenfield)))
row = [' ']+border
i = 0
for rows in [border]+hiddenfield:
print(row[i], end=' ')
i += 1
for lines in rows:
print(lines, end=' ')
print()
but all i get is this:
0 1 2 3 4 5 6 7 8 9
0 0 0 0 1 1 M 1 0 1 M
1 0 0 2 M 2 1 1 M M M
2 0 1 M 2 M 0 0 M 1 M
3 0 1 2 1 M 0 0 1 0 1
4 0 1 M 1 M 1 1 0 0 0
5 0 1 1 M 1 M M 2 1 0
6 0 0 0 M 0 1 2 M 1 0
7 0 1 1 M 1 0 1 1 1 0
8 0 M M 3 M 1 0 0 0 0
9 M 1 1 M 2 1 1 0 M 0
would really appreciate some help.

You have 2 problems:
if there is an index error before the end you skip the rest
you overwrite other mines
for i in range(0, len(hiddenfield)):
for j in range(0, len(hiddenfield)):
if hiddenfield[i][j] == 'M':
if hiddenfield[i + 1][j] != 'M':
try:
hiddenfield[i + 1][j] += 1
except IndexError:
pass
if hiddenfield[i + 1][j] != 'M':
try:
hiddenfield[i - 1][j] += 1
except IndexError:
pass
#and so on ..... :(
This is awful and therefore you should put this into a funtion
def update_cell(x, y):
try:
if hiddenfield[x][y] != 'M':
hiddenfield[x][y] += 1
except IndexError:
pass
for i in range(0, len(hiddenfield)):
for j in range(0, len(hiddenfield)):
if hiddenfield[i][j] == 'M':
update_cell(i - 1, j - 1)
update_cell(i - 1, j)
update_cell(i - 1, j + 1)
update_cell(i, j - 1)
update_cell(i, j + 1)
update_cell(i + 1, j - 1)
update_cell(i + 1, j)
update_cell(i + 1, j + 1)
Now that looks way better :)

I would start by storing the indexes of your bombs in a list. Then I would try using a function to get all neighboring elements given a location.
check out Listing adjacent cells
Then you can update this function to take an additional parameter which would be a function ex increment or decrement to be executed on all adjacent cells found

Related

How to generate distinct permutations of a vector in C++?

Suppose that there is a vector with only binary elements like this:
X = [0, 0, 1, 1]
The only distinct permutations are:
X = [0, 0, 1, 1]
X = [0, 1, 0, 1]
X = [0, 1, 1, 0]
X = [1, 0, 0, 1]
X = [1, 0, 1, 0]
X = [1, 1, 0, 0]
Is there an efficient way to do this in C++?
Use std::next_permutation:
#include <algorithm>
#include <array>
#include <cstdio>
int
main()
{
std::array<int, 4> arr{ 0, 0, 1, 1 };
/* Sort the array if necessary */
std::sort(arr.begin(), arr.end());
do {
for (auto const e : arr)
std::printf("%d ", e);
std::putchar('\n');
} while (std::next_permutation(arr.begin(), arr.end()));
}
Output:
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
Demo

check if the rows from a set of indices are duplicates or not and reconstruction

I have a 2D binary array where the value can take 0 and 1 only.
I have a set of indices to check whether the entries of the binary matrix for those indices are duplicate or not. I want to get the matrix with duplicate rows removed and the set of duplicate indices.
For example,
>>>> a
array([[1, 0, 1, 0],
[0, 0, 1, 1],
[1, 0, 1, 0],
[0, 0, 1, 1],
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
])
I am given set of indices (0,2,3,4,6,7). From the set, the rows corresponding to (0,2) and (4,6,7) are duplicates. I want the resulting matrix with the duplicates removed (as shown below)
>>>> b
array([[1, 0, 1, 0],
[0, 0, 1, 1],
[0, 0, 1, 1],
[1, 1, 1, 0],
[1, 1, 1, 0],
])
and a method for reconstruction of the matrix 'a' from 'b'
If the order in the output array is not relevant, then you can probably just use Eelco Hoogendoorn's answer. However, if you want to keep the same relative order as in the original array, here is another possible approach.
import numpy as np
a = np.array([
[1, 0, 1, 0],
[0, 0, 1, 1],
[1, 0, 1, 0],
[0, 0, 1, 1],
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 1, 0],
])
idx = np.array([0, 2, 3, 4, 6, 7])
# Make an array of row numbers
r = np.arange(len(a))
# Replace row numbers in idx with -1
# (use assume_unique only if indices in idx are unique)
r[np.isin(r, idx, assume_unique=True)] = -1
# Add the column to the array
a2 = np.concatenate([a, r[:, np.newaxis]], axis=-1)
# Find unique indices and inverse indices
_, uniq_idx, inv_idx = np.unique(a2, return_index=True, return_inverse=True, axis=0)
# Sort indices to make output array and inverse indices
s = np.argsort(uniq_idx)
a_uniq = a[uniq_idx[s]]
inv_idx = s[inv_idx]
print(a_uniq)
# [[1 0 1 0]
# [0 0 1 1]
# [0 0 1 1]
# [1 1 1 0]
# [1 1 1 0]]
print(np.all(a_uniq[inv_idx] == a))
# True
EDIT: Some further explanation.
The idea in the solution above is to apply np.unique, but in a way that the rows that are not included in idx are not affected by it. In order to do that, you can just add a new number to each row. For the rows included in idx, this number will always be -1, and for the rest of rows it will be a different number for each. That way, it is impossible that rows that are not in idx get removed by np.unique. In order to do that, I build r, first with np.arange(len(a)), which gives you a number per row:
[0 1 2 3 4 5 6 7]
Then I check which of those are in idx with np.isin(r, idx, assume_unique=True) (assume_unique can only be used if elements in idx are guaranteed to be unique), so r[np.isin(r, idx, assume_unique=True)] = -1 will turn all indices idx into -1:
[-1 1 -1 -1 -1 5 -1 -1]
That is added as new column to a into a2:
[[ 1 0 1 0 -1]
[ 0 0 1 1 1]
[ 1 0 1 0 -1]
[ 0 0 1 1 -1]
[ 1 1 1 0 -1]
[ 1 1 1 0 5]
[ 1 1 1 0 -1]
[ 1 1 1 0 -1]]
Now it's just a matter of applying np.unique to a2. As expected, only rows in idx may be eliminated. However, since we want to keep the original relative order, we cannot use the output of np.unique, because it is sorted. We use return_index and return_inverse to get the indices that make the array of unique rows and the indices that get you back to the original array, and actually discard the new array.
To form the final array, you need to sort uniq_idx to keep the relative order, and then inv_idx accordingly. np.argsort gives you the indices that sort uniq_idx into s. uniq_idx[s] is just the array of unique row indices sorted, and s[inv_idx] will map every inverse index in inv_idx to the corresponding one in the resorted array. So, finally, a[uniq_idx[s]] gives you the output array, and the new inv_idx takes you back to the original one.
It feels like you could phrase your question at a higher level to get a more elegant solution; but this seems to solve the literal problem as stated.
idx = [0,2,3,4,6,7]
b = np.concatenate([np.unique(a[idx], axis=0), np.delete(a, idx, axis=0)], axis=0)

Strange behavior modifying a list while looping over it (Python)

I understand that modifying a list while iterating over it can spell disaster. I was curious so I tried it anyway. In the first few examples below, things go as expected; but then something unusual happens in the second to last example.
>>> A = [0, 0, 0, 0]
>>> for k in A:
if k == 0:
A.remove(k)
>>> A
[0, 0]
>>> A = [0, 0, 0, 0, 1]
>>> for k in A:
if k == 0:
A.remove(k)
>>> A
[0, 0, 1]
>>> A = [0, 0, 0, 0, 1, 1]
>>> for k in A:
if k == 0:
A.remove(k)
>>> A
[0, 0, 1, 1]
>>> A = [0, 0, 0, 0, 1, 1, 0] # Why does the presence of a fifth zero (the one at the end), cause an earlier zero to be removed?
>>> for k in A:
if k == 0:
A.remove(k)
>>> A
[0, 1, 1, 0]
>>> A = [0, 0, 0, 0, 1, 1, 2]
>>> for k in A:
if k == 0:
A.remove(k)
>>> A
[0, 0, 1, 1, 2]
I am not a Python expert, but just when I imagine how foreach loop is implemented:
len = size(array)
for i in range(0, len):
loop_body(array[i])
Then for the second example:
len = 5, array=[0, 0, 0, 0, 1]
First iteration: i=0, array=[0, 0, 0, 0, 1], zero in array[0] is removed.
Second iteration: i=1, array=[0, 0, 0, 1], zero in array[1] is removed.
Third iteration: i=2, array=[0, 0, 1], array[2] == 1, nothing happened.
And this is your result. The same for the last one.
The remove method removes the first occurrence of x (I knew that, but forgot about it completely!) So when I execute this code:
>>> A = [0, 0, 0, 0, 1, 1, 0]
>>> for k in A:
if k == 0:
A.remove(k)
the presence of the zero at the end causes the zero in front of it (the one that was skipped over while iterating) to be removed. This produces:
>>> A
[0, 1, 1, 0]
I expected:
>>> A
[0, 0, 1, 1, 0]

Bit shifting in signed char C++11

I have k (0 < k < 8) CSV files containing values all 0 or 1.
My C++ code reads from the file and stores the content of each file into a vector<signed char>.
I wished to merge (concat) then store them in a single vector<signed char>.
File 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector1
File 2: 1 1 1 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 Stored in vector2
File 3: 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector3
File 4: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector4
File 5: 1 1 0 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 Stored in vector5
I wished to store them in vector<signed char> vectork:
with vectork[0] stored where each element has bit pattern as [0 0 0 0 1 0 1 1] -- first col
with vectork[1] stored where each element has bit pattern as [0 0 0 0 1 1 0 1] -- second col
with vectork[2] stored where each element has bit pattern as [0 0 0 0 1 0 0 0] -- third col
I tried with
vectork.resize(vector1.size(),0);
for ( int i = 0; i < vector1.size(); i++ ) {
vectork[i] = vectork[i] << 1;
if (vector1[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector2[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector3[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector5[i] == 1) vectork[i] +=1;
}
Is the above correct?
This would be a lot easier done with bitsets, however, if you choose to do it this way, it would look something like this.
I'm still kind of confused as to what exactly you're trying to do, but it seems like you're trying to get all of those vectors into one two dimensional vector (you did as an array of vectors, but I feel as if you intended it like this).
This will get all the vectors, and append them into a new vector of vectors.
// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<signed char> vector1 = {0,1,0,1,0,1,0,1};
vector<signed char> vector2= {0,0,0,1,0,1,0,1};
vector<signed char> vector3= {0,1,1,1,0,1,0,1};
vector<signed char> vector4= {1,1,0,1,0,1,0,1};
vector<signed char> vector5= {1,0,0,1,0,1,0,1};
vector<vector<signed char>> vectork(5, vector<signed char>(8));
vectork.clear();
vectork.push_back(vector1);
vectork.push_back(vector2);
vectork.push_back(vector3);
vectork.push_back(vector4);
vectork.push_back(vector5);
//to check if it correctly works (it does).
for(vector<signed char> v : vectork) {
for(signed char i : v) {
printf("%d ", i);
}
printf("\n");
}
}
The output would look like this:
0 1 0 1 0 1 0 1
0 0 0 1 0 1 0 1
0 1 1 1 0 1 0 1
1 1 0 1 0 1 0 1
1 0 0 1 0 1 0 1
Let me know if you were trying to do something slightly different and I can tweak it for you, or if you need any explanation on what I wrote, or have any questions in general.
Firstly I would recomend that you use std::vector<bool> instead of std::vector<signed char> This is specifically for performance reasons as your compiler will likely reduce the memory usage by storing 8 Booleans in 1 byte as apposed to storing 1 Boolean in a byte. Secondly I think you have completely misunderstood the process of bit shifting, as far as I am aware from what you have posted you are simply trying to concatenate two STL Vectors this has been asked here. For reference I have included a code snippet from the excellent answer by Robert Gamble. In your
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
#include <vector>
std::vector<signed char>
merge(const std::vector<signed char>& vector1,
const std::vector<signed char>& vector2,
const std::vector<signed char>& vector3,
const std::vector<signed char>& vector4,
const std::vector<signed char>& vector5)
{
std::vector<signed char> result;
result.reserve(vector1.size());
auto i1 = vector1.begin();
auto i2 = vector2.begin();
auto i3 = vector3.begin();
auto i4 = vector4.begin();
auto i5 = vector5.begin();
while (i1 != vector1.end()) {
int n = 0;
for (auto *v: { &i1, &i2, &i3, &i4, &i5 })
n = n*2 + *(*v)++;
result.push_back(n);
}
return result;
}
// test it:
#include <algorithm>
int main()
{
auto v = merge({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 });
auto expected = { 0b1011, 0b1101, 0b1000, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000,
0b0001, 0b1001, 0b1001, 0b0000, 0b0000, 0b0000, 0b1001, 0b0000,
0b0000, 0b0000, 0b1001, 0b0000 };
return !std::equal(expected.begin(), expected.end(), v.begin());
}

Recursive problems in 2D array C++

I have a problem that from a certain number 1 in a 2D matrix with (x, y) coordinates. From this number, it will start spreading out its 4-neighbor which their values will be assigned by (start point + 1)
We start from a coordinate of (3, 3) = 1. Its neighbor's value will be 2. Next step, 4 neighbors of the point having value of 2 will be 3. And so on, until, all 1 numbers in the matrix are infected!
I have resolved this problem by using some loops. However, I'd like to resolve it by another way that is recursion. But I haven't done with it.
Before
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 1 1 1 1 1 1 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
After spreading out
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 3 2 3 0 0 0 0 0
0 0 2 1 2 3 4 5 0 0
0 0 3 2 3 4 0 0 0 0
0 0 0 0 4 5 0 0 0 0
0 0 0 0 5 6 0 0 0 0
0 0 8 7 6 0 0 0 0 0
0 0 9 8 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Below is my code but I just can spread all 1 numbers with another value but not as I want. So please help me resolve this problem.
#include <iostream>
#define MAX 10
using namespace std;
int data[MAX][MAX] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
int mark[MAX][MAX];
void spreading(int x, int y, int v){
if (x < 0 || x == MAX) return;
if (y < 0 || y == MAX) return;
if(data[x][y] == 0 || mark[x][y] != 0)
return;
data[x][y] = v;
mark[x][y] = v;
spreading(x + 1, y, v);
spreading(x, y + 1, v);
spreading(x - 1, y, v);
spreading(x, y - 1, v);
}
void printArr(int a[MAX][MAX]){
for (int i = 0; i < MAX; ++i) {
cout << endl;
for (int j = 0; j < MAX; ++j) {
cout << a[i][j] << " ";
}
}
}
int main(){
spreading(3, 3, 1);
printArr(data);
system("pause");
return 0;
}
Following may solve your issue: (https://ideone.com/VQmBhU)
void spreading(int x, int y, int v){
// Test if x, y is inside the propagation area
if (x < 0 || x == MAX) return;
if (y < 0 || y == MAX) return;
if (data[x][y] == 0) return;
// if already visited with a better path, cancel.
// if not visited, or the previous visit was worst than this try, continue
if (mark[x][y] != 0 && mark[x][y] <= v) return;
data[x][y] = v;
mark[x][y] = v;
spreading(x + 1, y, v + 1);
spreading(x, y + 1, v + 1);
spreading(x - 1, y, v + 1);
spreading(x, y - 1, v + 1);
}
Some example of 're' visit (with the mark array content):
(1) 0 -> 1 (2) -> 1 2 -> 1 2
0 0 0 0 0 (3) (4) 3
1 <= 5, 3 <= 5 : (4) finished
2 <= 4 : (3) finished
1 <= 3 : (2) finished
4 > 2 : we continue propagation from (1)
(1) 2 -> 1 2
4 3 (2) 3
...