Reading in a file to create multiple "minesweeper"ish arrays - c

What I got so far, is a .in file that will create 100 arrays, followed by how many "mines" are on the board, and then 2 numbers for each "mine" representing where they will be placed on the array. This is for my beginner C class, and honestly we've not been taught properly for something this advanced (i say advanced using the term lightly). I know how to read in files, and I know how to create an array, but im unsure how I would read in that many lines, switching from mines to placement over and over again. I also find myself confused as to how to change an array number from 0 to another number based on where a mine is placed.
An example input file:
1
4
1 3
7 5
7 3
3 3
Where the 1 in the first line means we have one board. The 4 on the next line means it will have 4 bombs. The following 4 lines describe the position of the bomb in the array as row column.
Is there anything that anyone can offer me to point me in the right direction?

Below is a partial solution, it leaves a few parts as an exercise for the OP.
#include <stdio.h>
#include <stdlib.h>
#define BOARD_SIZE 8
int main(void) {
FILE *fp;
fp = fopen("mines.in","r");
if ( fp == NULL ) {
fprintf(stderr,"Could not open file\n");
return 1;
}
int nBoards = 0;
int nMines = 0;
int col;
int row;
int currentBoard = 0;
/* We know the first row is going to be the number of boards */
fscanf(fp,"%d",&nBoards);
printf("We have %d boards\n",nBoards);
while ( fscanf(fp,"%d",&nMines) > 0 ) {
int i,j;
/* initialize board as all zeros */
int board[BOARD_SIZE][BOARD_SIZE] = { {0} };
currentBoard++;
printf("Board %d:\n",currentBoard);
/* Read in and set the mines */
for (i=0; i<nMines; i++) {
fscanf(fp,"%d %d",&col,&row);
board[col-1][row-1] = 9;
}
/* Add mine proximity */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
if ( board[i][j] == 9 ) { /* we have a mine */
/* Square to the left */
if (j > 0 && board[i][j-1] != 9) {
board[i][j-1]++;
}
/* Square to the right */
/* Left as exercise for the OP*/
/* Square above */
/* Left as exercise for the OP*/
/* Square below */
/* Left as exercise for the OP*/
}
}
/* Print out the board */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
printf("%d ",board[i][j]);
}
printf("\n");
}
printf("\n");
}
fclose(fp);
if (currentBoard != nBoards) {
fprintf(stderr,"Expected %d boards, read in %d boards\n",nBoards,currentBoard);
return 1;
}
return 0;
}
The code reads in the first line to record the number of boards, then it loops over the blocks of data containing the number of mines and the mine locations. The while loop will perform an fscanf on the lines containing the number of mines, and in the body of the while loop the different mine locations will be read in to the number defined for the board.
Once we have all the mine locations we can calculate the numbers in other squares on the board, only one of which I've shown in the code (others are similar).
Note that the above code does almost no error handling and almost no validation on the input file - if the input file is wrong you could get errors i.e. 'out of range' accesses to arrays. I've left out such checks to make the underlying logic of the program clearer.
Note also that I've assumed that the input indexs are '1'-indexed (i.e. in the range [1,8] rather than '0'-indexed as C expects (i.e. in the range [0,7]), hence the substitution of 1 in the line board[col-1][row-1] = 9;.

Related

How do I record the frequency of numbers inputted by a user using functions in C

Hey there i'm currently developing a lotto type game and one of my requirements is to record the frequency of the numbers inputted by the user and then display them if the users wishes to see them. The program also must be modular hence the functions.
My problem is that i can't seem to figure out how to keep track of the numbers I tried numerous things and this is the closest I've gotten...
void num_free(int *picked_nums)
{
static int elements[MAX] = { 0 };
int i;
for (i = 0; i < MAX; i++)
if (*(picked_nums + i) == i)
{
elements[i]++;
}
for (i = 0; i < MAX; i++)
{
if (elements[i] != 0)
{
printf("\nThe amount of times you chose %d is %d", i, elements[i]);
}
}
printf("\nEnter any key to return to main menu");
getchar();
}
The output of this every time i run it no matter the input is
"The amount of times you chose 11 is 1"
I'm really clueless as to what to do next so any and all help would be appreciated. Thanks in advance!
EDIT: The user can play multiple rounds and thats how the frequency of the numbers can add up.
I think the main problem in your code is here:
if (*(picked_nums + i) == i)
{
elements[i]++;
}
you actually check if the i-th number the user chose equals to i. That means that increment is done only in that case - which is not what you want (if I got you right).
I think you should give up the if statement, and, assuming that the user chooses only non-negative numbers (and that the elements array is properly zeroed at the beginning), do this:
elements[picked_nums[i]]++;
Namely, you increment the array cell matching the chosen number (and the i is only the index you use to iterate the picked_num array).
The problem is how you count and store the numbers:
if (*(picked_nums + i) == i)
{
elements[i]++;
}
Your i is moving and at the same time the element chosen from picked_nums is moving. This loop will not count or store properly.
The provided solution assumes that picked numbers are stored in the numbers array. I assumed that numbers are in 1 to 64 range. You can adjust program to your needs. Test provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void num_free(int picked_nums[], int size )
{
static int elements[65] = { 0 }; // numbers can be from 1 to 64 range
int i;
for (int j = 0; j < size; j++)
{
int n = picked_nums[j];
for (i = 1; i < 65; i++) // numbers can be from 1 to 64 range
{
if ( n == i)
{
elements[i] = elements[i]+1;
}
}
}
for (i = 0; i < 65; i++)
{
if (elements[i] != 0)
{
printf("\nThe amount of times you chose %d is %d", i, elements[i]);
}
}
// printf("\nEnter any key to return to main menu");
// getchar();
}
// array of entered numbers:
int numbers[] = { 2, 2, 2, 40, 7, 7, 8, 9, 40 };
int main(void) {
num_free(numbers, 9); // call with sizeof numbers
return 0;
}
Test:
The amount of times you chose 2 is 3
The amount of times you chose 7 is 2
The amount of times you chose 8 is 1
The amount of times you chose 9 is 1
The amount of times you chose 40 is 2

Can't find the logical bug

I have solved this programming problem and when I submitted my code, the judge said it was wrong. I tried and I couldn't figure out the bug. Can someone give me a hint please?
Because stack overflow won't accept my question if I don't specify more details, I am copying the question here
A sequence of n > 0 integers is called a jolly jumper if the absolute values of the
differences between successive elements take on all possible values 1 through n − 1. For
instance,
1 4 2 3
is a jolly jumper, because the absolute differences are 3, 2, and 1, respectively. The
definition implies that any sequence of a single integer is a jolly jumper. Write a program
to determine whether each of a number of sequences is a jolly jumper.
Input
Each line of input contains an integer n < 3, 000 followed by n integers representing the
sequence.
Output
For each line of input generate a line of output saying “Jolly” or “Not jolly”.
The code
#include <stdio.h>
#define SEQ_SIZE 3000
static char stack[SEQ_SIZE];
void initStack(int count)
{
for(int i=0;i<count; ++i)
stack[i]=0;
}
int absDiff(int a, int b)
{
return (a-b)>=0?((a-b)%SEQ_SIZE):(((a-b)*-1)%SEQ_SIZE);
}
int main()
{
int n,prev,curr;
/*FILE *sample=fopen("SampleInput","r");
if(!sample)
return 0;*/
while(scanf("%d",&n)!=EOF)
{
scanf("%d",&prev);
if(n<1)
break;
else if(n==1)
printf("Jolly\n");
else
{
int i;
for(i=1; i<n; ++i)
{
scanf("%d",&curr);
stack[absDiff(curr,prev)-1]=1;
prev=curr;
}
for(i=0; i<(n-1); ++i)
{
if(stack[i]==0)
break;
}
if(i<n-1)
printf("Not jolly\n");
else
printf("Jolly\n");
initStack(n);
}
}
}
I think your solution is fine except the line
return (a-b)>=0?((a-b)%SEQ_SIZE):(((a-b)*-1)%SEQ_SIZE);
No need to use % here. It should be
return (a-b)>=0?((a-b)): (a-b)*(-1));
To limit n below 3000 you can do as
if(n<1 || n >= 3000) // I merged it with n<1 condition
break;

Find a triad in a network with a C program

I've the following problem: I have two file file1.dat and file2.dat with 9 numbers put in a column each. For exemple:
file1.dat = 1,1,1,2,2,4,4,4,7
file2.dat = 2,4,7,3,4,1,3,7,1
I've tried to write a program that should find the triad in this network, where for triads I mean a group of three numbers that start with one of this number, pass to another two that are linked toghether and return back to the original one. In this case the file1.dat describe the "nodes" from where to start, and file2.dat describe the nodes where you arrive (1->2, 1->4, 1->7, 2->3 ...). There are two triads in this little "network" and they are composed from 1,2,4 and 1,4,7. I wrote the following program:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main (void){
int A[N],B[N],i,j,l,m,k;
int x,y;
int valueA,valueB,count,middle_value,new_value;
FILE *fp,*fq;
if ((fp = fopen("file1.dat", "r")) == NULL ) {
printf("Error opening file 1\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; i++) {
fscanf(fp,"%d", &x);
A[i] = x;
}
if ((fq = fopen("file2.dat", "r")) == NULL ) {
printf("Error opening file 2\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; i++) {
fscanf(fq,"%d", &y);
B[i] = y;
}
the up code is used to fill the two array A and B with all the data in the two files.
for (i=0;i<N;i++){
valueA=0;
valueB=0;
valueA=A[i];
valueB=B[i];
count=0;
middle_value=0;
new_value=0;
//Start the research of the first node of the file2.dat in the file1.dat
for(k=i+1;k<N;k++){
if(A[k]==valueB){
count++;
Up here I put a counter "count" that increase to 1 let me know if I find in the first file some number that have the same value as the first attending node. Now if the counter = 1, I want the computer to memorize the valueB = A[k] to write it at the end of the file as the middle term of the triad. Then I give to "valueB" the new value that is the "node arrival" corrisponding at the start one of A[k]--> B[k];
if(count==1){
middle_value = valueB;
valueB = B[k];
Then I look forward in the file, icreasing the for from where I stop before (l = k+1 ) for the last value of the triad that have to be like A[l] --> first value of A == B[l]. I increase then the counter and when the counter reach 2 the program should print me the 3 values, otherwise it should leave counter == 1, and if it can't find the first valueB in the file1, leave the counter == 0 (that's why I put the else at the end..)
for(l=k+1;l<N;l++){
new_value=A[l];
if(new_value==valueB && valueA==B[l]){
count++;
if(count==2){
printf ("%d,%d,%d\n\n",valueA,middle_value,valueB);
}else{
count=1;
}
}
}
}else{
count=0;
}
}
}
}
fclose(fp);
fclose(fq);
return (0);
}
But it doesn't work as I want. But if, e.g., I create 2 new files like
file1.dat = 1,1,1,2,3
file2.dat = 2,4,7,3,1
where there is the triad 1,2,3, the program works (must put # define N 6 in the 3rd row).. Someone can help me?
The problem that I think to have is that the program, with the beginning files, when it associate to valueA = 1, valueB=2, then it looks again to file 1 the position of 2 (that now becomes "the middle_value") and it gives to the new valueB = 3. Now it will search the 3 in the file1 but it don't find it. So it should pass at the second '2' that is in the file1 and give to the new valueB = 4 and then everything should goes well. But it doesn't. I don't understand why
So, I see a number of problems with your method. Perhaps the biggest problem is that you have three loops:
for(i=0 ;i<N;i++){
for(k=i+1;k<N;k++){
for(l=k+1;l<N;l++){
And each loop begins where the other ends. But, in general, you may need to look at smaller nodes in order to find loops. For instance, if you have the following graph:
1 2 3
3 1 2
you can verify that your approach will not work. So we know right away that we need to expand the range of the loops.
Also, you have a lot of variables floating around. Sometimes (but not always), that's an indication that the program is needlessly complex. Often times, considerably complicated problems can be solved without too many intermediate variables.
Your x and y variables were obviously unnecessary because you were using them as simple intermediates, so I cut them.
You used two file pointer variables, but really only needed one. I cut out the second one.
I also moved the fclose statements closer to where you read in the files, so that they would be open for the shortest possible time, which is a polite way to read a file.
Your valueA, valueB, and count variables immediately struck me as being questionable. Especially this bit:
valueA=0;
valueB=0;
valueA=A[i];
valueB=B[i];
You give them values, and then immediately change the values.
But a deeper look at the code shows that you're using valueA and valueB to keep track of which A and B you're looking at. And you use count to keep track of how deep you are in the loops. But each of these is inherent in the structure of the code!
So I cut all that out and widened the loop range, as discussed above, resulting in this:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main () {
int A[N], B[N];
FILE *fp;
if ((fp = fopen ("file1.dat", "r")) == NULL) {
printf ("Error opening file 1\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &A[i]);
fclose (fp);
if ((fp = fopen ("file2.dat", "r")) == NULL) {
printf ("Error opening file 2\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &B[i]);
fclose (fp);
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
for(int k=0; k<N; k++)
if(B[i]==A[j] && B[j]==A[k] && B[k]==A[i])
printf("%d,%d,%d\n",A[i],A[j],A[k]);
return 0;
}
It will find each triad-loop three times, which is unfortunate, but it will find all the loops. There are slightly more complicated algorithms which would find loops once or find them more efficiently, but this algorithm most closely matches your original code, so it may be the most useful for you now.

program in C is crashing when more memory is used

I have to do as a school assigment small program in C that will read standart input and prints some standart output. To be more specific, it's about reading numbers and sorting them.
(you can skip this, it's just for understanding the code)
First line of the input should determine how many lines of numbers there will be. Second line is ammount of numbers in next line. Third line are to concrete numbers. Fourth line is ammount of numbers in next line and so on until it reaches K number of lines. Restrictions are 0 < K <= 10 (max 10 sequences), each sequence can contain max 10.000.000 numbers and each number's value is max 10.000.000
Example
Input:
2 //which means that there will be 2 sequences (lines) of numbers and their corresponding ammount
3 //in the first sequence there will be 3 numbers
5 99912 45 //first sequence
6 //in the second sequence there will be 6 numbers
9489498 22131 0 521313 7988956 5 //second sequence
Ouptup:
0 5 5 45 22131 99912 521313 7988956 9489498
So I have done a working program but it seems to be unstable with higher values. However I can't determine when and where exactly the program fails. On my computer, I have tested all possible max values and it returned correct output in reasonable time, but on a school server where tests are done it just can't handle high values and fails.
There is one thing, that the program should only use C, not C++, but I am not very sure of differences between them and as I was using C++ compiler, it's possible that my code isn't just raw C.
I am a C beginner and this is something like "Hello world" for me, so please, can you just quick look through the code and say what can cause the unstability? Thanks
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int k, n, i, y, x, index = 0;
int *numbers = (int*) malloc(100000000 * sizeof(int));
if(numbers == NULL){
exit(1);
}
scanf("%d", &k);
for (x = 0; x < k; x++) {
y = 0;
scanf("%d", &n);
while(scanf("%d", &i) > 0){
numbers[index++] = i;
if(++y == n){
break;
}
}
}
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
}
int smallest, smallestIndex;
for(x = 0;x < index;x++){ //print all other numbers in ascending order
smallest = 0;
for(y = 0;y < index;y++){ //find current smallest number
if((numbers[y] < smallest || smallest == 0) && numbers[y] != 0){
smallest = numbers[y];
smallestIndex = y;
}
}
numbers[smallestIndex] = 0;
if(smallest > 0){
if(x == index-1){
printf("%d", smallest);
}else{
printf("%d ", smallest);
}
}
}
free(numbers);
numbers = NULL;
return 0;
}
Based on the information you give, I think this is simply a resource limitation on the server. The server simply runs out of memory and your malloc() fails. I suggest you debug or do this:
if(numbers == NULL){
printf("malloc() failed\n");
exit(1);
}
The code for printing the initial zeros is suspicious:
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
Suppose you have a sequence with 0 as the last element (e.g. 1 2 3 4 5 0); i guess this code will print just 0 with no space after it, and the subsequent code will print 1 2 3 4 5, so you will get something like 01 2 3 4 5.
I understand that you want the output to be as beautiful as possible, that is, without a space at the end. Please also note that a newline (\n) at the end of output might be good.
I rewrote beginning parts of your program to get you on the right path. This should help you but I can't be sure since I don't really know what is causing your program to crash.
This implements the realloc function which should make your program drastically more efficient than it is now. If you don't know what realloc is you can read about it here, and here.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER 256 //for memory management
int main(void)
{
int k, n, i, y , x, index = 0, bff; //declare integer 'bff' and set it to BUFFER
int *numbers = NULL, *tmp; //declare a pointer (numbers) for allocated memory, and a pointer (tmp) for the realloc function
if(!(numbers = malloc(BUFFER * sizeof(int)))) //allocate space for 'bff' integers
{
exit(1); //allocation failed
}
scanf("%d", &k);
for (x = 0; x < k; x++)
{
scanf("%d", &n);
while(scanf("%d", &i) > 0)
{
if(bff <= index) //if the size of index grows larger than the amount of space we allocated
{
bff += BUFFER; //increase the size of bff by BUFFER
if(!(tmp = realloc(numbers, bff * sizeof(int)))) //resize our allocated memory block using the tmp pointer
{
free(numbers); //allocation failed so free already allocated memory
exit(1); //and terminate the program
}
numbers = tmp; //make numbers point to the same location as tmp
numbers[index++] = i;
if(++y == n) break;
}
}
}
.
.
.
free(numbers);
return 0;
}
Keep in mind there are more efficient ways to use realloc. I just posted this here to get you on the right track. Good luck!
You are allocating the wrong amount of memory. The specification states that each sequence can contain 10 million values whereas you allocate a fixed amount. There may be up to k*10 million values of input, and you cannot know that the amount you allocate is enough.
As pointed out by m0skit0, the problem may also be due to over-allocation.
To fix the problem you should allocate the needed amount of memory, no more, no less.
Use the sequence length provided for each sequence to do that.
Also, you need to check the return value of malloc and realloc. If the return value is NULL then the allocation failed and you should print an error message and exit.

Issues with reading words from a text file into 2d Array

I recently started a program in which I have to sort a list of guests, but the overall problem details are irreverent for the issue I'm having.
Well, I want to scan in first and last names from a file SEPARATELY, which I know you do by scanning them as strings. However, we just started using strings and I'm having a little brain fart and I've searched places but I can't figure out how to do so. I'm also having trouble structuring the array inside the for loops. My mind has been totally out of school since Skyrim came out :). Here's the input text file:
//First number is the amount of families on the list, second number is the room capacity, ignore that for now.
10 30
//Format = First Name, Last Name, Number of Family Members (ignore), Priority Level (ignore)
BEN JOHNSON 4 2
DOUG ESPINOSA 3 2
SARAH TELLINGER 5 3
GRANT THOMPSON 5 2
JENNIFER WEST 7 6
JACKSON JOHNSON 1 5
MARTY MCFLY 4 1
ELIZABETH JAMES 2 6
MICKEY MOUSE 2 4
RAJ SHAH 2 5
Here's my code so far: Assume MAX_FAMILY_MEMBERS = 10 and MAX_NAME_LENGTH = 20
void Read_First_Name(FILE *ifp, char First_Name[//Assume MAX_FAMILY_MEMBERS is here][MAX_NAME_LENGTH]){
int i, j;
for(i = 0; i < MAX_FAMILY_MEMBERS; i++)
{
for(j = 0; j < MAX_NAME_LENGTH; i++)
{
fscanf("%s", First_Name[i][j]);
}
}}
I'm sure this is most likely wrong but I'm quite confused and out of it. If there are any questions about my program please ask.
Its easy if you use fgets with sscanf in one loop like
char line[100], firstnames[100][100], famnames[100][100];
int counter=0;
while( fgets(line,100,yourfilepointer) )
if( sscanf(line,"%s%s",firstnames[counter],famnames[counter])==2 )
++counter;
...
while( counter-- )
printf("%s %s\n",firstnames[counter],famnames[counter]);
void Read_And_Store(FILE *ifp, int FAMILIES_KNOWN, char First_Name[][MAX_NAME_LENGTH], char Last_Name[][MAX_NAME_LENGTH], int Family_Members[], int Priority[]){
int i;
for(i = 0; i < FAMILIES_KNOWN - 1; i++)
{
fscanf(ifp, "%s", First_Name[i]);
fscanf(ifp, "%s", Last_Name[i]);
fscanf(ifp, "%d", &Family_Members[i]);
fscanf(ifp, "%d", &Priority[i]);
}}
Here's what I did and it works fine when I print it out. However, I've tried a bunch of stuff trying to sort the printed list by priority level, but none of them are successful... any ideas? After I get the sort down the rest is just basic logic and swapping.
I Presume you want to sort the families basing on their priority level. In the code you wrote,
Your fscanf syntax is incorrect. Go through the syntax once more.
for(i = 0; i < MAX_FAMILY_MEMBERS; i++)
{
for(j = 0; j < MAX_NAME_LENGTH; i++)
{
fscanf("%s", First_Name[i][j]);
}
}
It is good that you want to read line by line (family by family) but how you read each family is improper.
%s format specifier reads an entire string until it encounters a space.
so that second for loop is very messy.
I will slightly change the code, you can improve on it and write your own logic
#define NUMBEROFFAMILIES 10
#define FAMILYNAMELENGTH 20
char firstName[NUMBEROFFAMILIES][FAMILYNAMELENGTH]; // to store first name
char secondName[NUMBEROFFAMILIES][FAMILYNAMELENGTH]; // to store second name
int familtyPriority[NUMBEROFFAMILIES][1]; // to store priority
int i, j;
for(i = 0; i < MAX_FAMILY_MEMBERS; i++){
fscanf(ifp,"%s",firstName[NUMBEROFFAMILIES]); // read first name
fscanf(ifp,"%s",secondName[NUMBEROFFAMILIES]); // read second name
fscanf(ifp,"%d", &j); // Ignore family members count
fscanf(ifp,"%d", &familtyPriority[NUMBEROFFAMILIES][1]); // family priority
}
EDITED FOR THE NEXT QUESTION
You want to sort based on the priority level.
int familtyPriorityCopy[NUMBEROFFAMILIES][1]; // to store priority
int familyOrder[NUMBEROFFAMILIES][1]; // to store the proper order.
// initialize them
for (i=0;i<NUMBEROFFAMILIES;i++){
familtyPriorityCopy[i][1] = familtyPriority[i][1];
familyOrder[i][1] = i;
}
// sorting [insertion sort]
for (i=1;i<NUMBEROFFAMILIES;i++){
for (j=0;j<i;j++){
if (familtyPriorityCopy[j][1] < familtyPriorityCopy[i][1]){
swap(familtyPriorityCopy[i][1],familtyPriorityCopy[j][1]);
swap(familyOrder[i][1], familyOrder[j][1]);
}
}
}
At the end, familtyPriorityCopy array is sorted. But this is not what is important. familyOrder array is what points to the correct order. We will use this array to print them in the right order.
for(i = 0; i < MAX_FAMILY_MEMBERS; i++){
printf("%s",firstName[familyOrder[i][1]][1]); // read first name
printf("%s",secondName[familyOrder[i][1]][1]); // read second name
printf("%d", familtyPriority[familyOrder[i][1]][1]); // family priority
}

Resources