Im programming in c the minesweeper game.
im pretty at the end.
I have only problem with the last part.
in the game (see picture) when I click on the upper left field, the fields where no mine is are turned around and at the border there are numbers.
how is the algorithm for finding this field and turn them around or to show them .... I mean algorithm for the field in the green circle?
I am doing a design from scratch, I hope it helps you.
If my game arena is nxn matrix of integers,
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
I can model placing a bomb in that matrix by applying such a 3x3 matrix:
1 1 1
1 9 1
1 1 1
Here 9 denotes a bomb, you probably need to use a bigger integer. And when I say apply, I pick the location and increment it by the numbers in that 3x3 matrix. So let's place 1 bomb:
0 1 1 1 0
0 1 9 1 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
Let's place another bomb, just next to the first one. And let's be a bit clever and not increment the location when the initial value in a cell is 9.
0 1 2 2 1
0 1 9 9 1
0 1 2 2 1
0 0 0 0 0
0 0 0 0 0
Let's place another one this time somewhere below.
0 1 2 2 1
0 1 9 9 1
0 1 3 3 2
0 0 1 9 1
0 0 1 1 1
So if I try to start revealing numbers from bottom right. What should be my algorithm? Here is my take:
function revealCell(location)
{
if(cellValueIsRevealed(location)) {
return;
}
var value = revealValueOfCell(location);
if(value > 0)
{
return;
}
foreach(neighbor in neighbors)
{
revealCell(neighbor);
}
}
To implement cellValueIsRevealed method, one way would be to implement a matrix of booleans.
Might be a little late to answer the question, but I'll do it anyway so that if someone sees this in the future it might help them out. This is also written in C# but the general idea should be the same.
The idea is to have a Queue of cells to visit, and a unique collection for visited cells. Start by queueing the current position and then evaluate the whole queue until it's empty. Dequeue the current cell and check if it's already visited. If it's not then check all the surrounding cells and enqueue them if they are empty cells. When you have finished the queue the hashset contains all the empty cells.
public void AsQueue(Queue<(int i, int j)> toVisit, HashSet<(int i, int j)> visited, Cell[] grid, int i, int j)
{
List<(int i, int j)> neighbours = new();
toVisit.Enqueue((i, j));
while (toVisit.Count != 0)
{
var temp = toVisit.Dequeue();
if (!visited.Contains(temp))
{
Neighbours(neighbours, i, j, grid.GetLength(0), grid.GetLength(1));
for (int k = 0; k < neighbours.Count; k++)
{
if (grid[neighbours[k].i, neighbours[k].j].Type == BoxType.Empty &&
!(neighbours[k].i == i && neighbours[k].j == j) &&
!visited.Contains(neighbours[k]))
{
toVisit.Enqueue(neighbours[k]);
}
}
}
visited.Add(temp);
}
}
private void Neighbours(List<(int i, int j)> neighbours, int i, int j, int maxh, int maxw)
{
int[] iOffsets = new int[] { -1, 0, 1 }, jOffsets = new int[] { -1, 0, 1 };
if (i == 0) iOffsets = new int[] { 0, 1 };
else if (i == maxh - 1) iOffsets = new int[] { -1, 0 };
if (j == 0) jOffsets = new int[] { 0, 1 };
else if (j == maxw - 1) jOffsets = new int[] { -1, 0 };
neighbours.Clear();
foreach (var ip in iOffsets)
{
foreach (var jp in jOffsets)
{
neighbours.Add((i + ip, j + jp));
}
}
}
Related
I allocated matrix like this :
prevMatrix = (int**)malloc(sizeof(int) * arraySize[0]);
for (int i = 0; i < arraySize[0]; i++) {
prevMatrix[i] = (int*)malloc(sizeof(int) * arraySize[1]);
}
I checked arraySize[] has normal value. arraySize[0] means row, and arraySize[1] means column.
and I handed over the matrix like this :
void getInputMatrix(FILE* input, int column, int** matrix)
getInputMatrix(input, arraySize[1], prevMatrix);
and then function's body is this :
void getInputMatrix(FILE* input, int column, int** matrix) {
int i = 0, j = 0, c = 0;
while (!feof(input)) {
if (j == column) {
j = 0;
i++;
}
c = fgetc(input);
if (c != EOF && c != 32 && c != 10 && c != 13) {
matrix[i][j] = c - 48;
j++;
}
}
}
this is the example of matrix file:
1 0 0 0 0 0 0
0 1 0 1 0 0 0
0 1 0 0 1 1 0
0 1 1 1 0 0 0
0 0 0 0 1 0 0
0 1 0 0 0 1 0
1 0 1 1 0 0 0
0 1 0 0 0 0 1
It works very well in VS 2019, but it cause segmentation fault in Linux system(Ubuntu).
This program works well in Linux till the column is 6 or 7, but it occurs corrupted size vs. prev_size error or segmentation faultwhen the column overs that number.
Is it a problem of allocation? or fgetc()?
How can I fix it?
For starters, your first level allocation should be using the size of an int pointer rather than an int:
int **prevMatrix = malloc(sizeof(int*) * arraySize[0]);
If those types are different sizes, your original code could have a problem.
And, just as an aside, you should not cast the malloc return value in C, it can cause subtle problems.
I'm still a noob at programming and still don't know many of the functions that I'm able to use so I kept to the basics, I was trying to create the game 2048 in C, for that I decided to make a function to push numbers in certain directions, either upwards, downwards, left or right. My up function is working, but my down function isn't even though I did the opposite of what I did in my up function. In the push_down function the numbers actually do what they do in the push_up functions, they move up instead of down.
Would love to know why it isn't working if anyone can spot my mistake
//this one is working
void push_up(int game_size, int grid[game_size][game_size])
{
int replace;
int num=0;
for (int j = 0; j < game_size ; ++j)
{
for (int i = 0; i < game_size ; ++i)
{
replace = 100;
if(grid[i][j]==0)
{
for (int a = game_size - 1 ; a > 0 + i ; --a)
{
if(grid[a][j]!=0)
{
num=grid[a][j];
replace=a;
}
}
grid[i][j]=num;
num=0;
}
if(replace!=100){
grid[replace][j]=0;
}
}
}
}
// this one isn't working
void push_down(int game_size, int grid[game_size][game_size])
{
int replace;
int num=0;
for (int j = 0; j < game_size ; ++j)
{
for (int i = game_size - 1; i >= 0 ; --i)
{
replace = 100;
if(grid[i][j]==0)
{
for (int a = 0 ; a < game_size - i ; ++a)
{
if(grid[a][j]!=0)
{
num=grid[a][j];
replace=a;
}
}
grid[i][j]=num; //
num=0;
}
if(replace!=100){
grid[replace][j]=0;
}
}
}
}
What I did in both is mainly to run the column(either upwards or downwards depending on the function) trying to find a zero, lock the position of the zero and try to find the next number in that column by running the column in the opposite direction, the last number (if a number was even found) would be used to fill that zero and the position where the number was would be filled with 0.
So, let me give an example of what I wanted with these function:
In the first function (push_up) I wanted and was able to do a function that would transform this matrix :
4 2 4 0
0 0 0 0
0 4 2 2
2 0 4 2
into this one:
4 2 4 2
2 4 2 2
0 0 4 0
0 0 0 0
So, all the values would move to the highest position possible inside the column.
In the second function what I wanted was to transform this matrix:
4 2 4 0
0 0 0 0
0 4 2 2
2 0 4 2
into this one:
0 0 0 0
0 0 4 0
4 2 2 2
2 4 4 2
All the values would move to the lowest possible position inside the matrix. But I wasn't able to, by running the function what I get is:
This is the original matrix:
0 0 0 0
4 0 0 2
2 0 0 4
0 2 0 0
This is the matrix after using the function push_down:
2 2 0 4
4 0 0 2
0 0 0 0
0 0 0 0
There are probably easier ways to do this, I would love to hear them but I would also love to know where my logic went wrong in the push_down function since in the push_up function it's working fine.
Your example isn't reproducible and I'm not certain exactly what you're trying to do, but this is the obvious error:
for (int a = 0 ; a > game_size - i ; ++a)
{
if(grid[a][j]!=0)
{
num=grid[a][j];
replace=a;
}
}
This loop will never run, a is zero and will never be greater than game_size - 1.
I'm trying to implement a two functions based on Depth First Search using a recursion method. I'm ultimately trying to compare the runtime against warshall's algorithm (which I already have working). When I print my matrix it's off by a couple off paths.
The recursion is what may be throwing me off, it's my weakness. Because of the top if statement if(iIndex1 == iIndex2) return TRUE;, when I try to find if there is a path from (A,A), (B,B), (C,C), etc. I will always get 1 even if there is no path from A to A.
typedef enum { FALSE, TRUE } bool;
/* Recursive function will determine if there is a path from index 1 to 2
* Based of DFS
*/
bool recPathExists( Graph G, int iIndex1, int iIndex2 )
{
int j;
G.nodeArray[iIndex1].visited = TRUE;
if(iIndex1 == iIndex2){
return TRUE;
}
for(j = 0; j < G.iNumNodes; j++){
if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j]==1){
if(recPathExists(G, j, iIndex2))
return TRUE;
}
}
return FALSE;
}
/* Write a function to find all pairs of nodes which have paths between them.
* Store this information in the provided pathMatrix.
*/
void allPathsRecFunc( Graph G , int **pathMatrix )
{
int i, j;
for(i = 0; i < G.iNumNodes; i++){
for(j = 0; j < G.iNumNodes; j++){
if(recPathExists(G, i , j)== TRUE){
pathMatrix[i][j] = 1;
}
resetVisited(G); //resets all nodes to FALSE
}
}
}
what it should be
A 0 1 1 1 1 1 1 1
B 0 1 0 0 1 1 1 1
C 0 1 0 0 1 1 1 1
D 0 0 0 0 0 0 0 0
E 0 0 0 0 0 0 0 0
F 0 1 0 0 1 1 1 1
G 0 1 0 0 1 1 1 1
H 0 1 0 0 1 1 1 1
what I get
A 1 1 1 1 1 1 1 1
B 0 1 0 0 1 1 1 1
C 0 1 1 0 1 1 1 1
D 0 0 0 1 0 0 0 0
E 0 0 0 0 1 0 0 0
F 0 1 0 0 1 1 1 1
G 0 1 0 0 1 1 1 1
H 0 1 0 0 1 1 1 1
Your issue may be here:
for(j = 0; j < G.iNumNodes; j++)
{
if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1)
{
return recPathExists(G, j, iIndex2);
}
}
By returning the result of recursing on recPathExists, you're not checking the other possible nodes that could be reachable in the loop (in essence, you're returning failure too early, and missing possible paths).
I believe you want just a little modification:
for(j = 0; j < G.iNumNodes; j++)
{
if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1)
{
if (recPathExists(G, j, iIndex2))
return TRUE;
}
}
That is, "if a path does exist, return as we've found it. If not, keep looking".
My depth first search uses recursion but it outputs a parent array, though the functionality should be the same. It got a perfect grade so I know it works. Hope it helps.
https://github.com/grantSwalwell/Data-Structures/blob/master/Depth%20First%20Search.h
Algorithm~
bool array, visited for flagging nodes
search number array to measure the depth of access
depth to increment and come up with search num
Call DFS on 0,0
For each non visited neighbor
DFS depth + 1, search = depth, visited = true
return parent array, showing the search pattern
// Depth First Search recursive helper method
void DFS(Graph& G, int v0, Array<bool>* visited, Array<int>* search, int
depth)
{
// set visited
(*visited)[v0] = true;
// set search num
(*search)[v0] = depth;
// iterate through neighbors
for (int i = 0; i < G.nodes(); i++)
{
// if i is a neighbor
if (G.edge(i, v0))
{
// if it has not been visited
if (!(*visited)[i])
{
// call DFS
DFS(G, i, visited, search, depth + 1);
}
} // end if
} // end for
}
// Depth First Search
Array<int>* DFS(Graph& G, int v0)
{
// visited array
Array<bool>* visited = new Array<bool>(G.nodes());
// search number array, order of visitation
Array<int>* search = new Array<int>(G.nodes());
// initialize both arrays
for (int i = 0; i < G.nodes(); i++)
{
(*visited)[i] = false;
(*search)[i] = 1;
}
// create depth field
int depth = 1;
// call DFS
DFS(G, v0, visited, search, depth);
return search;
};
I'm working on a problem dealing with iteration. I'm supposed to pass in two ints into a function, which represent a number of N objects and M values that I must find all permutations of. I am also given a sample of what the output is supposed to look like
void perm_iter(int N, int nr_values)
and the output this is supposed to print is :
Called : perm_iter(3, 2);
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
I understand the concept of recursion by using a swap function to change the orders of strings to find all permutations of a string, but I'm unsure of how to use iteration to get the same, or similar result. Is this a case where I need to use the stack and push/pop iteratively to get my answer? I was thinking I could use something like a set of nested loops to take the place of recursion and get something like this output but I'm unsure how to set the loops up to go through every permutation and not just iterate, missing some of the possible permutations.
Any help would be appreciated, and thank you for your time.
You just need to count up each "digit" until the max is reached, then reset and increment the next.
Imagine nr_values is 10 (with n=2):
0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
Looks familiar because it's just "regular" counting in this case.
Implement this just like you count up: In each step, increment the leftmost value. If max is reached, reset and increment the next value etc.
void perm_iter(int n, int nr_values) {
int[] counter = new int[n];
int i;
// Clear all values
for (i = 0; i < n; i++) {
counter[i] = 0;
}
do {
// Print the current set of values
for (i = 0; i < n; i++) {
printf("%n ", counter[i]);
}
printf("\n");
// Keep incrementing while the values overflow,
// starting at the rightmost counter
i = n - 1;
while (i >= 0) {
counter[i]++;
if (counter[i] < nr_values) {
break;
}
counter[i] = 0;
i--;
}
// We are done when the first value overflows
} while (i >= 0);
}
I am trying to work my way up from the beginning in C and making sure I understand every little thing before moving on. Today, my goal was to write a program that would take in a list of integers (assume less than 50 integers) and would print a table with the list of unique integers in one side and the number of times it appeared in the other. I have a copy of my function which takes care of counting the number of times it appears.
Quick summary of my function: takes in 2 pointers to arrays, and one integer of how many integers to iterate over. Assumption: we are checking for repeats of some number x. Somewhere in the array, we hit another x. It increments the count for x and turns x into 0 for later purposes.
Sample trials
input: 1 2 1 2 2 1 2
output: 1 appears 3 times. 2 appears 4 times.
input: 1 2 3 1 2 3 1 2 3
output: 1 appears 3 times. 2 appears 3 times. 3 appears 3 times.
input: 1 2 1 3 1 2 3
output: 1 appears 3 times. 2 appears 2 times. 3 appears 1 times.
Although the program is working for the most part, I want to make sure it works completely. Thus, my issue is that last trial. Why is 3 being read only once when it works for other 2 input sets?
void countOccurrences(int *list, int size, int *uniques){
for (int i = 0, t = 0; i < size; i++){
int temp = list[i];
if (temp == 0){ //If the number was a repeat of another previous number
continue; //skip over it and go to the next element in list
}
uniques[t] = 1;
for (int j = i+1; j <= size; j++){ //this iterates through list for any repeats of temp
if (temp == list[j]){ //All repeats of temp turn to 0
uniques[i]++;
list[j] = 0;
}
}
t++;
}
}
It is because, 3 comes as last number and you reset the count of occurrence to 1
uniques[t] = 1;
and for loop doesn't run at all since thats the last number, you are not looking back in the array.
I would simply write this program as below.Given list has values >=0
for (int i = 0; i < size; i++){ //this iterates through list for any repeats of temp
uniques[list[i]]++;
}
For a list with any values, use a hash table data structure
I wouldn't go stomping over the original data.
High level view:
for each element
if it apeared before
increment it's count
else
record it's first occurence
Say you need to count the contents of an N element array, it can't contain more than N different elements. One simple way of representing the counts is to have an array of values and counts, and a number of used entries (different values seen). This would be along the lines:
#define N ...
struct {
int value, cnt;
} count[N];
int entries = 0;
Your check to see if the value v is already there is:
for(k = 0; k < entries && count[k].value != v; k++)
;
if(k == entries) {
/* Not found */
count[k].value = v;
count[k].cnt = 1;
entries++;
}
else {
/* Found it */
count[k].value++;
}
Just need to wrap this up with the code to comb your data array...
(Yes, this is quite inefficient; for serious use a smarter/faster structure to keep the values would be needed).
There are several problems with this code that we can illustrate with some more complete testing. Here's a short, self-contained, compilable (in C99) example (see SSCCE) with some tests and some additional diagnostic results:
#include <stdio.h>
void printArray(char *name, int *list, int size) {
printf ("%s = {",name);
for (int i = 0; i < size; i++) {
printf ("%d ",list[i]);
}
printf ("}\n");
}
void countOccurrences(int *list, int size, int *uniques, int *values) {
for (int i = 0, t = 0; i < size; i++) {
int temp = list[i];
if (temp == 0) {
//If the number was a repeat of another previous number
continue;
//skip over it and go to the next element in list
}
uniques[t] = 1;
values[t] = temp;
for (int j = i+1; j <= size; j++) {
//this iterates through list for any repeats of temp
if (temp == list[j]) {
//All repeats of temp turn to 0
uniques[i]++;
list[j] = 0;
}
}
t++;
}
}
void test(int *x, int size) {
const int n = 10;
int uniques[n],values[n];
for (int i = 0; i < n; i++) {uniques[i] = 0; values[i] = -1; }
countOccurrences (x,size,uniques,values);
printArray ("uniques",uniques,sizeof(uniques)/sizeof(*uniques));
printArray ("values ",values,sizeof(values)/sizeof(*uniques));
}
int main (int argc, char* argv[]) {
int x1[] = {1, 2, 1, 2, 2, 1, 2};
int x2[] = {1, 2, 3, 1, 2, 3, 1, 2, 3};
int x3[] = {1, 2, 1, 3, 1, 2, 3};
int x4[] = {3, 2, 1, 3, 1, 2, 3};
test(x1,sizeof(x1)/sizeof(*x1));
test(x2,sizeof(x2)/sizeof(*x2));
test(x3,sizeof(x3)/sizeof(*x3));
test(x4,sizeof(x4)/sizeof(*x4));
return 0;
}
(EDITED thanks to #Matt McNabb's advice, by refactoring common code into the test() function)
... for which the output is:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 2 1 1 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 3 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
The first test gives you the expected output. The second test shows that there is an extra count for the first item in the list. This can be fixed by changing:
for (int j = i+1; j <= size; j++){
to
for (int j = i+1; j < size; j++){
... because the code is counting one space beyond the end of the data. The output with this bug fixed is:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 1 1 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
The third and fourth test results are harder to interpret because it isn't so obvious what the intended output should be. The counting function appears to be intended to report counts of unique numbers in the order in which it finds those numbers in list. With the third test, however, the first appearance of "3" is at the fourth item in the list. Changing:
uniques[i]++;
to
uniques[t]++;
... means that the count is output as the tth item in the count list, giving the output:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
This output is correct now, but it is difficult to interpret the counts found in uniques without the values array that I've added to the code. See that, in the last test case, the first count is the number of 3s in list, not the number of 1s, for instance.
Finally, it is generally poor practice to modify a parameter to a function at all. It is necessary to do so in C because you can't return an array from a function but modifying the arrays pointed to by uniques and values is generally tolerable because they are explicitly available to return results outwards from the function. Modifying a parameter used to supply input data to a function, though, as countOccurrences() does with list is generally unwise because that means the code that uses countOccurrences() has to make a copy of list before passing the pointer to that list to countOccurrences(), if it wants to use the original content of list for some other purpose as well.
If we know that the integers to be counted are all less than or equal to than the size of the uniques array, the function suggested by #Saravana Kumar is both quicker to run and easier to make correct:
// Requirements:
// uniques initially contains all zeros
// no integer in list is less than zero or greater than sizeof(uniques)/sizeof(int)-1
//
void countOccurrences2 (int *list, int size; int *uniques) {
for (int i = 0; i < size; i++) {
uniques[list[i]]++;
}
}