Minesweeper game - c

do you know the minesweeper game of windows . well , the following problem is the same , you will input m and n ...
0 < n,m <= 100
n : colons , m : rows
input :
4 4
*...
....
.*..
....
output :
*100
2210
1*10
1110
and , that is my code .
#include <stdio.h>
#include <stdlib.h>
char ms[100][101] ;
int m , n;
void input(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c <= n ; c++){
scanf("%c",&ms[r][c]);
if('.' == ms[r][c])
ms[r][c] += 2 ;
}
}
void calc(int m , int n){
for(int r = m ; r <= (m+2) ; r++)
for(int c = n ; c <= (n+2) ; c++)
if(r >= 0 && c >= 0 && ms[r][c] != '*')
ms[r][c] += 1 ;
}
void solve(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c < n ; c++)
if( '*' == ms[r][c])
calc(r-1 , c-1);
}
void output(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c <= n ; c++)
printf("%c ", ms[r][c]);
}
int main()
{
scanf("%d%d" , &m , &n);
input();
solve();
output();
return 0;
}
when running my code , if the input have * at the first as follows :
4 4
*...
....
.*..
....
the output is :
important to see it .. click here
note: i tried to print the value of the symbol that appeard in the picture and it is 11 in ascii code which is vertical tab.
and , another problem if the * is at the last as follows :
4 4
...*
....
....
...*
000*
0000
0000
000*
but my code works well when the * is at the middle as follows :
4 4
....
..*.
.*..
....
0111
12*1
1*21
1110
so , what's the problem with my code ?

In this line you can go out of bounds:
if(r >= 0 && c >= 0 && ms[r][c] != '*')
ms[r][c] += 1 ;
You only test if r and c are not negative, but you should also test they are not too large.
The thing becomes more complicated because you have global variables m and n which are the dimensions of your array, but they are not available in the calc function, because there you have local variables with the same name.
So you better use different variable names. And then you should test that r<m and c<n, as follows:
void calc(int p , int q){
for(int r = p ; r <= (p+2) ; r++)
for(int c = q ; c <= (q+2) ; c++)
if(r >= 0 && c >= 0 && r < m && c < n && ms[r][c] != '*')
ms[r][c] += 1 ;
}
Now the reason you saw an ASCII 11 is explained by the fact that ASCII 10 is the line feed character that marks the end of a row. Then when your code performs ms[r][c] += 1 on it (because it goes too far), it becomes that funny character.
That you have that ASCII 10 in your array is explained by how you read the input (see #pmg's answer). If you would not have read those white space characters, you would still overrun, and probably touch data in a next row of data, which is not what you want to happen.

scanf("%d", ...);
leaves whitespace (the ENTER) in the input buffer. Then
scanf("%c", ...);
reads that whitespace into the variable.
You need to ignore the whitespace before (and during) reading the stars and dots.
Use
scanf(" %c", ...);
// ^^^ ignore whitespace
Note: the conversion specifier "%d" (and many others) already includes ignoring whitespace; the exceptions are "%c", "%[", and [for different reasons] "%n").

Related

c program prints question mark in a box as an output

There is a char pointer variable, and its value coming from a function.
char* apple = ....(function call)
I wanted to print this as follows:
int len = strlen(apple);
for(i=0;i<len;i++){
printf("%c ", apple[i]);
}
But in the console, it gives a question mark in a box as an output. What should I do, how should I print it? Thanks.
I dont see issue in the printing part, through the fucntion that retuns pointer to char array needs to be investigatd.
// In this example, getString function returns string literal
// That is being iterated in the next for loop over its length and prints its characters
#include <stdio.h>
#include <stdlib.h>
char *getString(void); // declare
int main() {
char *apple = getString();
int len = strlen(apple);
for(int i = 0; i < len ; i++) {
printf("%c ", apple[i]);
}
return 0;
}
char *getString() {
return "somesthing";
}
Below example will print only printable ascii chars. From 0 to 31 , 0 is for null, 1 is for SOH and so on. Simply you cannot print control codes (ASCII codes < 32) if you print strange output is expected.
#include <stdio.h>
#include <string.h>
#define PRINTABLE_ASCII_CHAR_COUNT 96
/*
Printable chars list
"! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
# A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~"
*/
char *getASCIIs(void);
int main() {
char *apple = getASCIIs();
int len = strlen(apple);
for(int i = 0; i < len ; i++) {
// p << i << ((i % 16 == 15) ? '\n' : ' ');
printf("%c ", apple[i]);
}
return 0;
}
char *getASCIIs() {
static char buffer[PRINTABLE_ASCII_CHAR_COUNT];
for (int i = 32, j=0 ; i <= PRINTABLE_ASCII_CHAR_COUNT; i++, j++) {
buffer[j] = i;
}
return buffer;
}
enter code here
Your syntax seems legit. I highly suspect that cigar[i] donates the proper character that you are looking for. Trying affirming that by casting cigar[i] into a character using (char) cigar[i]. You might output cigar[i] as a string %s as a part of debugging where does it really point at.

decompress string in c

I have a string like this :
h12pw3Bb4
I want decompressed to :
hhhhhhhhhhhhpwwwBbbbb
for numbers less than 10 i wrote this code but it isn't work for numbers greater than 10
for(int j = 0;j< strlen(txt);j++){
if(isdigit(txt[j])){
int x = txt[j];
x = x - 49;
while(x > 0){
printf("%c" , txt[j-1]);
x--;
}
}else{
printf("%c" , txt[j]);
}
}
See h12 implies print 'h' 12 times right. But you are reading character by character then when '1' is read 1 h will be print and next when 2 is read 2 h's are printed. So based on your code you are not going to achieve what you desire. You need to change it.
So, I think this should help:
int st = 0;
for(int j = 0;j< strlen(txt);) {
int x = 0;
while(j < strlen(txt) && isdigit(txt[j])) {
x = (x * 10) + (txt[j] - '0');
j++;
}
x--;
while(x > 0){
printf("%c" , txt[st]);
x--;
}
if (j < strlen(txt))
printf("%c" , txt[j]);
st = j;
j++;
}
Assumptions :
The first number must be a letter.
Please change them accordingly to your requirements.
Right, with multi-digit numbers you need several iterations of the loop before knowing the value of x.
So personally what I would do is this:
define and initialize two variables int x and char c outside of the loop
in the if block: calculate the value of x (multiplying it by 10 and adding txt[j] - 49 ?)
in the else block: print c x times, reset x to 0, set c to txt[j]

What does this line of code translate to ? and why divide by 16?

I have been trying to translate this code to put it in simple terms to understand but can't quite get it.
Can someone help me understand it better and why the next line would they want to divide by 16?
char r = (c+n1+n2)>=16 ?
((c+n1+n2)-16+'0') :
((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
c = (c+n1+n2)/16;
the lines above this are a while loop to print multiple numbers and are:
int i=s1-1, j=s2-1, c=0, k=0;// sets up for the calculations -1
// for the s1 and s2 because you do not want null character included here
// k is the number of places we use for addition
printf("COL d d c\n");
while(i>=0 || j>=0){
int n1 = i<0?0:num1[i]-'0';// is converting from the character representation
// of a number to the actual integer value of the same digit if not 0
int n2 = j<0?0:num2[j]-'0';
char r = (c+n1+n2)>=16 ?
((c+n1+n2)-16+'0') :
((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
c = (c+n1+n2)/16;
printf("%3d : %d+%d+%d = %c\n", k, n1, n2, c, r);
i--;
j--;
k++;
}
It seems, the function above was intended to add two hex strings. I believe this, because the line in question encodes hex characters and the overflow, that occurs when adding two digits is treated in a way, that makes only sense if the digits are treated as 4 bit digts (hex digits). E.g. because of the division by 16.
If I am right, the hex decoding contains a bug, while the hex encoding for outputting the result seems almost correct. Almost, because if I got it right, the original version will not be able to calculate string additions like "00F" + "00F" correctly (see last output below).
It seems, as if even the original author was overwhelmed by his code.
Here is a version, that should do, what the original author intended to do:
void string_add(char num1[], char num2[], int s1, int s2) {
int i=s1-1, j=s2-1, c=0, k=0;// sets up for the calculations -1 for the s1 and s2 because you do not want null character included here
int z=0;
// k is the number of places we use for addition
printf("COL d d c\n");
while(i>=0 || j>=0){
/*
* the following lines represent the expressions
* int n1 = i<0?0:num1[i]-'0';// is converting from the character representation of a number to the actual integer value of the same digit if not 0
* int n2 = j<0?0:num2[j]-'0';
* I added the conversion of hex digits in the range A-F
*/
int n1, n2= 0;
char r;
if(i>=0) {
n1= num1[i];
if(n1>='A') {
n1-= 'A'-10;
} else {
n1-= +'0';
}
}
if(j>=0) {
n2= num2[j];
if(n2>='A') {
n2-= 'A'-10;
} else {
n2-= '0';
}
}
/*
* the following code is, what the line
* char r = (c+n1+n2)>=16?((c+n1+n2)-16+'0'):((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
* originally did (I also do a partial calculation of the line
* c = (c+n1+n2)/16;
* to avoid repeating the term
*/
c= c+n1+n2;
r= c&15; // only take the lower 4 bits (ignore overflow bits)
z|= r << (4*k);
// construct the binary representation (shift the 4 bits into position and use bitwise or to add them to z)
if(r>9) {
r+= 'A'-10; // produces chars in range A-F = (ascii('G')-16+c
} else {
r+= '0'; // produces chars in range 0-9 if no overflow occurs
}
/*
* now just do the /16 part of
* c = (c+n1+n2)/16;
*/
c/= 16;
printf("%3d : %d+%d+%d = %c\n", k, n1, n2, c, r);
i--;
j--;
k++;
}
printf("%d\n", z);
}
void main(void) {
char s1[]= "0100";
char s2[]= "0B01";
string_add(s1, s2, 4, 4);
}
Tests (first output is from the version above, second from the original version):
"0005"+"0005"=
COL d d c
0 : 5+5+0 = A
1 : 0+0+0 = 0
2 : 0+0+0 = 0
3 : 0+0+0 = 0
10
COL d d c
0 : 5+5+0 = A
1 : 0+0+0 = 0
2 : 0+0+0 = 0
3 : 0+0+0 = 0
"9989"+"0987"=
COL d d c
0 : 9+7+1 = 0
1 : 8+8+1 = 1
2 : 9+9+1 = 3
3 : 9+0+0 = A
41744
COL d d c
0 : 9+7+1 = 0
1 : 8+8+1 = 1
2 : 9+9+1 = 3
3 : 9+0+0 = A
"000F"+"000F"=
COL d d c
0 : 15+15+1 = E
1 : 0+0+0 = 1
2 : 0+0+0 = 0
3 : 0+0+0 = 0
30
COL d d c
0 : 22+22+2 = L
1 : 0+0+0 = 2
2 : 0+0+0 = 0
3 : 0+0+0 = 0
The last output seems suspicuous. Was this really intended?
The code seems to perform the addition of 2 numbers stored as hexadecimal encoded strings. It is obfuscated in silly ways. Here is how to improve readability:
white space should be used wisely to make the logic more obvious: typically insert a space character on both sides of binary operators, between keywords and the corresponding ( and before the { opening a block.
the magic constant 55 should be replaced with 'A' - 10, making it more evident that the code performs a conversion from a numeric value to a hexadecimal digit character.
intermediary values should be computed and stored into aptly named local variables.
comments can be used for non obvious steps.
The code seems incorrect:
c > 0 should be tested too to account for possible overflow on the most significant digit.
conversion from hex should be performed when reading digits from the num1 and num2 strings, converting digits A through F to the values 10 to 15.
the resulting digit would be incorrect if c + n1 + n2 >= 26
Here is an attempt at fixing the code:
// s1 is the length of hex encoded string num1
// s2 is the length of hex encoded string num2
int carry = 0;
int i = s1, j = s2, k = 0;
// k is the number of places we use for addition
printf("COL d d c\n");
while (i > 0 || j > 0 || carry > 0) {
// get the digit values from num1 and num2
char c1 = i == 0 ? '0' : num1[--i];
char c2 = j == 0 ? '0' : num2[--j];
int d1 = c1 <= '9' ? c1 - '0' : c1 - 'A' + 10;
int d2 = c2 <= '9' ? c2 - '0' : c2 - 'A' + 10;
int digit = carry + d1 + d2;
carry = digit >> 4;
digit %= 15;
char r = digit > 9 ? (digit - 10 + 'A') : (digit + '0');
printf("%3d : %d+%d+%d = %c\n", k, d1, d2, carry, r);
k++;
}

understanding entab example code in k&r

I'm teaching myself C and working through K&R. I'm doing exercise 1-21:
Write a Program entab that replaces strings of blanks by the minimum number of tabs and blanks to acheive the same spacing. Use the same tab stops as for detab.
I was having trouble doing this exercise so I found a solution online but I do not understand it. Can someone explain how this code works?
#include<stdio.h>
#define TABINC 8
int main(void)
{
int nb,nt,pos,c;
nb = 0;
nt = 0;
for(pos=1;(c=getchar())!=EOF;++pos)
if( c == ' ')
{
if((pos % TABINC) != 0)
++nb;
else
{
nb = 0;
++nt;
}
}
else
{
for( ; nt > 0 ; --nt)
putchar('\t');
if( c == '\t')
nb = 0;
else
for( ; nb > 0; --nb)
putchar(' ');
putchar(c);
if(c == '\n')
pos = 0;
else if ( c == '\t')
pos = pos + ( TABINC - (pos -1) % TABINC) - 1;
}
return 0;
}
The code is to
put a tab ('\t') when a space () is encountered at a position that is a multiple of TABINC, i.e, the size of the tab.
when a tab is encountered, the number of spaces is reset. This is to prefer a tab to reach a tabstop
To illustrate:
- a space shown in *
- a tab is shown in
column: 1 2 3 4 5 6 7 8 9 10
input : * * * * h e l * * w
output: <tab>hel<tab>*w
In this example, when a space is encountered at every column position which is divisible by the TABINC, i.e 4 (in this case), a tab '\t' is inserted. Otherwise space.
Hope this will give you some idea.

Segmentation fault/Dev C crashing

Hey guys so Im trying to do a homework and I cant find the fatal error on my program all day long.Let me explain :
Firstly,you give the number of rows,col then the cells of the array (only "." for free spaces and "*" for mines, all in one row without spaces) then the crashing happens.
main(){
int i,col,row,count,N,M,j;
char **p;
printf("Give number of rows\n");
scanf("%d",&N);
printf("Give number of columns\n");
scanf("%d\n",&M);
p=malloc(N*sizeof(char *)); //Saving room for the array
if (p==NULL)
return -1;
for (i=0;i < N ; ++i){
p[i] = malloc (M * sizeof(char));
if (*(p+i) == NULL)
return -1;
}
for (i=0; i< N;++i){
for ( j = 0 ; j < M ;++j)
scanf("%c",&p[i][j]); //Insert "*" for mines and the rest with "."
}
for (row=1; row<= N;++row){ //Here the things get messy
for ( col = 1 ; col <= M ;++col){
if(p[row][col]=='.'){
count = 0 ;
if(p[row][col+1]=='*' && col < M)
count=count+1;
if(p[row][col-1]=='*' && col > 1)
count=count+1;
if(p[row+1][col]=='*' && row < N)
count=count+1;
if(p[row-1][col]=='*' && row > 1)
count=count+1;
if(p[row+1][col+1]=='*' && (row < N && col < M))
count=count+1;
if(p[row+1][col-1]=='*' && (row < N && col > 1))
count=count+1;
if(p[row-1][col+1]=='*' && ( row > 1 && col < M))
count=count+1;
if(p[row-1][col-1]=='*' && ( row > 1 && col > 1))
count=count+1;
printf("%d ", count);
}
printf("* ");
}
printf("\n");
}
printf("\n");
for (i=0; i< N;++i){
for ( j = 0 ; j < M ;++j)
printf("%c ",p[i][j]);
printf("\n");
}
for (i = 0 ; i <N ; ++i)
free(p[i]);
free(p);
}
Firstly, here's what I did to debug (actually I saw the problem in the code and just verified this way, but this will be useful to you).
Add #include <stdio.h> and #include <stdlib.h> at the head of the file.
gcc -Wall -O0 -g x.c -o x to compile with debug and no optimisation.
I then used following to run within gdb:
gdb x
...
(gdb) run
Starting program: /home/amb/so/x
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
Give number of rows
1
Give number of columns
1
.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004007d4 in main () at x.c:25
25 if(p[row][col]=='.'){
(gdb) print row
$1 = 1
(gdb) print col
$2 = 1
(gdb)
See how in less than 10 seconds it showed me where the error was?
You have two problems:
for (row=1; row<= N;++row){ //Here the things get messy
for ( col = 1 ; col <= M ;++col){
if(p[row][col]=='.'){
The SEGV appears here as you access p[N][M], but the indices of p can only go from 0 to N-1 and 0 to M-1 respectively. This loop should probably read:
for (row=0; row < N;++row){ //Here the things get messy
for ( col = 0 ; col < M ;++col){
if(p[row][col]=='.'){
(note change to start at row=0, and row < N not row <= M and similarly for col).
The second problem you have is to do with what to do at the edges:
Lines like this:
if (p[row][col-1]=='*' && col > 1)
count=count+1;
should have the col > 1 condition first so they don't evaluate the array element unless the condition is true. Also, as col goes 0..M-1, you want
if ((col > 0) && (p[row][col-1]=='*'))
count=count+1;
Note I've put in some brackets to avoid any ambiguity.
The same applies when looking at the other edges:
if (p[row][col+1]=='*' && col < M)
count=count+1;
should be:
if ((col < M-1) && (p[row][col+1]=='*'))
count=count+1;
That should get you going. But learn to use a debugger.

Resources