I have gotten some insight on how to deal with multidimensional array columns.
Below is some compilable code that runs and performs okay for the most part.
I want to use the very logic I am using right now, and it seems sound to me (as a novice at least), however I am getting very nasty output.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
Here I initialize an empty array which you will see later in main:
void initializeGrid(int row, int col, int grid[][col])
{
int count = 1;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
grid[i][j] = count;
count++;
}
}
}
Here I print the initial case of the grid that will later be
manipulated. This should be reused:
void printGrid(int row, int col, int grid[][col])
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%3d", grid[i][j]);
}
printf("\n");
}
}
Here I get the location of a specific value by its row and its column
and I store it to the pointers r, and c:
bool findUnit(int unit, int row, int col, int grid[][col], int *r, int *c)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (grid[i][j] == unit)
{
*r = i;
*c = j;
return true;
}
}
}
return false;
}
Here I shift up using very elementary array mechanics and I felt so
confident about it until seeing my output:
bool shiftUp(int unit, int row, int col, int grid[][col])
{
int r = 0;
int c = 0;
if (findUnit(unit, row, col, grid, &r, &c))
{
int i;
int temp = grid[0][c];
for (i = 1; i <= row; i++)
{
grid[i - 1][c] = grid[i][c];
}
grid[r][c] = temp;
return true;
}
return false;
}
Here I run the shift up command or I quit. Assume that run can make
array move in other directions as well. It does not work for any
direction yet, but I assume if I can fix one, I can fix all:
bool run(char cmd[10], int row, int col, int grid[][col])
{
int unit = 0;
printf("$: ");
scanf(" %s %d", cmd, &unit);
if (strcmp(cmd, "up") == 0)
{
shiftUp(unit, row, col, grid);
return true;
}
if (strcmp(cmd, "quit") == 0)
{
return false;
}
return false;
}
Here I execute the code:
int main()
{
int row = 4;
int col = 4;
int grid[row][col];
char cmd[32];
initializeGrid(row, col, grid);
printGrid(row, col, grid);
while (run(cmd, row, col, grid))
{
printGrid(row, col, grid);
}
return 0;
}
This is all one file. Here also is the disturbing output I am getting and the expected output.
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
$: up 9
5 2 3 4
9 6 7 8
1 10 11 12
1347447432 14 15 16
$: quit
^C
Notice even when I type quit it does not quit.
Expected output should be something like (in a smaller grid i.e. 3x3):
1 2 3 1 5 3
4 5 6 --(up 5)--> 4 8 6
7 8 9 7 2 9
at this part
for (i = 1; i <= row; i++)
{
grid[i - 1][c] = grid[i][c];
}
When i == row, grid[i][c] occurs out-of-bounds error.
In C, the array index starts at 0,
When there is an array like this
Type array[n];
the maximum index available is n-1.
As an example,
you can simplify the process by using a 1D array instead of a 2D array.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
//When there is no strlwr
#ifndef STRLWR
#include <ctype.h>
char *strlwr(char *s){
for(char *p = s; *p; ++p)
*p = tolower((unsigned char)*p);
return s;
}
#endif
static inline void clear_input_buff(void){
while(getchar() != '\n');
}
typedef enum {
QUIT, UP, DOWN, LEFT, RIGHT
} Command;
Command getCommand(const char *prompt){
while(true){
char cmd[8] = "";
fputs(prompt, stdout);fflush(stdout);
scanf("%7s", cmd);
strlwr(cmd);
if(!strcmp(cmd, "quit"))
return QUIT;
else if(!strcmp(cmd, "up"))
return UP;
else if(!strcmp(cmd, "down"))
return DOWN;
else if(!strcmp(cmd, "left"))
return LEFT;
else if(!strcmp(cmd, "right"))
return RIGHT;
printf(
"invalid input for command\n"
"input again\n"
);
clear_input_buff();
}
}
bool findUnit(int unit, int row, int col, int grid[], int *r, int *c){
for(*r = 0; *r < row; ++*r)
for(*c = 0; *c < col; ++*c)
if(*grid++ == unit)
return true;
return false;
}
void moveHelper(int n, int array[], Command dir, int distance){
int temp;
int last = (n-1) * distance;
if(dir == LEFT){
temp = array[0];
for(int i = distance; i <= last; i += distance){
array[i - distance] = array[i];
}
array[last] = temp;
} else if(dir == RIGHT){
temp = array[last];
for(int i = last; i > 0; i -= distance)
array[i] = array[i - distance];
array[0] = temp;
}
}
bool move(int unit, int row, int col, int grid[], Command cmd){
int r, c;
if(findUnit(unit, row, col, grid, &r, &c)){
switch(cmd){
case UP:
case DOWN:
cmd = (cmd == UP) ? LEFT : RIGHT;
moveHelper(row, &grid[c ], cmd, col);
break;
case LEFT:
case RIGHT:
moveHelper(col, &grid[r * col], cmd, 1);//1: 1 element
break;
}
return true;
}
printf("Can't found [%d]. So you can't move.\n", unit);
return false;
}
bool run(int row, int col, int grid[]){
Command cmd;
while((cmd = getCommand("$: ")) != QUIT){
int unit = 0;
if(scanf("%d", &unit) != 1){//get operand as unit
printf("invalid input for unit.\n");
clear_input_buff();
continue;
}
return move(unit, row, col, grid, cmd);
}
return false;
}
void initializeGrid(int n, int grid[n]){
int value = 1;
while(n--)
*grid++ = value++;
}
void printGrid(int row, int col, int *grid, int width){
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++)
printf("[%*d]", width, *grid++);
putchar('\n');
}
}
static inline int width(int value){
return snprintf(NULL, 0, "%d", value);
}
int main(void){
int row = 4, col = 4;
int n = row * col;//number of elements
int grid[n];
initializeGrid(n, grid);
int w = width(grid[n-1]);//width of max value
printGrid(row, col, grid, w);
while(run(row, col, grid)){
printGrid(row, col, grid, w);
}
return 0;
}
Example of execution:
[ 1][ 2][ 3][ 4]
[ 5][ 6][ 7][ 8]
[ 9][10][11][12]
[13][14][15][16]
$: up 9
[ 5][ 2][ 3][ 4]
[ 9][ 6][ 7][ 8]
[13][10][11][12]
[ 1][14][15][16]
$: right 11
[ 5][ 2][ 3][ 4]
[ 9][ 6][ 7][ 8]
[12][13][10][11]
[ 1][14][15][16]
$: down 15
[ 5][ 2][15][ 4]
[ 9][ 6][ 3][ 8]
[12][13][ 7][11]
[ 1][14][10][16]
$: left 15
[ 2][15][ 4][ 5]
[ 9][ 6][ 3][ 8]
[12][13][ 7][11]
[ 1][14][10][16]
$: quit
in C, the range of indexes into an array are 0...number of entries in array-1. so this code block:
for (i = 1; i <= row; i++)
{
grid[i - 1][c] = grid[i][c];
}
will (amongst other problems) be setting the grid[i-1][c] (when i is > row-1) from some unknown value located past the end of the array. That is undefined behavior and can lead to a seg fault event.
Related
I have been working on a problem I solved but I'm not sure if it is the best way to do it.
I m working in windows 10 with visual studio. I know I'm using a c++ compiler but the code needs to be in C.
The problem:
On mars surface there are N city connected by M roads, humans want to destroy roads, but only strategic roads. A road is strategic if and only if without that road a pair of cities is no longer connected. Because humans are going to destroy some roads they are constructing Q new road.
Input:
a .txt file, on the first line there are 3 number N, M, Q, the following M line are the link on mars surface, the next Q lines contains the roads martians are going to build.
input.txt
5 4 2
5 1
3 2
2 5
4 2
1 2
5 3
Output:
Q line which contain the number of strategic roads after adding each line.
output example:
2
1
I tought to create a dynamic array and add a city if it is connected with another city in the array, if at the the end of the loop 2 city are not in the array the road which links those two city is not strategic.
#include<assert.h>
#include<stdio.h>
#include<malloc.h>
#define MAX_LINKS (250000)
typedef struct {
int a;
int b;
} link_t;
int N, M, Q, L, i;
link_t links[MAX_LINKS];
int find(int, int*, int);
bool strategic(link_t);
int main() {
freopen("input.txt", "r", stdin);
assert(scanf("%d%d%d", &N, &M, &Q)==3);
for (i = 0; i < M; ++i) {
assert(scanf("%d%d", &links[i].a, &links[i].b)==2);
++L;
}
int strategic_roads;
for (i = 0; i < Q; ++i) {
assert(scanf("%d%d", &links[M + i].a, &links[M + i].b) == 2);
++L;
strategic_roads = 0;
for (int j = 0; j < L; ++j) {
if (strategic(links[j])) {
++strategic_roads;
}
}
printf("%d\n", strategic_roads);
}
}
int find(int val, int* array, int size) {
for (int i = 0; i < size; ++i) {
if (array[i] == val) {
return i;
}
}
return -1;
}
bool strategic(link_t link) {
int counter = 1, size = 1, *arr;
int find_a = 0, find_b = 0;
arr = (int*)malloc(size * sizeof(int));
arr[0] = link.a;
bool still_working;
do {
still_working = false;
for (int i = 0; i < L; ++i) {
if ((links[i].a == link.a && links[i].b == link.b) || (links[i].a == link.b && links[i].b == link.a)) {
continue;
}
find_a = find(links[i].a, arr, size);
find_b = find(links[i].b, arr, size);
if (find_a < 0 && find_b >= 0) {
++size;
arr = (int*) realloc(arr, size * sizeof(int));
arr[counter] = links[i].a;
++counter;
still_working = true;
}
else if (find_a >= 0 && find_b < 0) {
++size;
arr = (int*)realloc(arr, size * sizeof(int));
arr[counter] = links[i].b;
++counter;
still_working = true;
}
}
} while (still_working);
return (find(link.b, arr, size) < 0);
}
Do you know another better way to solve it?
I'm trying to write a piece of code which generates for me a valid sudoku puzzle.
My algorithm:
initiate all fields with 0
respect the rules and set 20 random values from 1-9 to random fields
solve the puzzle with the back tracking algorithm
My problems:
Sometimes it generates a valid sudoku puzzle in under 1 second.
Sometimes it can't generate a valid sudoku and I get an error, which is ok because I can go back to step 1 in my algorithm.
Sometimes it can't generate a valid sudoku and I get an error but it takes about 2-3Minutes, which is not ok.
How can I solve my problems?
Especially problem 3.
Can I just count the seconds and if it takes more than 5 seconds just go back to step 1 of my algorithm?
Or does anyone have a better idea?
thanks in advance.
this is my code:
#include <stdio.h>
#include <stdlib.h>
#define N 9
#define UNASSIGNED 0
typedef enum {false, true} bool;
typedef struct {
char number;
bool editable;
} GRID;
void print_sudoku(GRID **g){
char row=0, col=0;
for(row=0; row<N; row++){
for(col=0; col<N; col++){
printf("%d ", g[row][col].number);
}
printf("\n");
}
}
GRID ** create_sudoku_grid(){
char i, row, col;
GRID **g = (GRID **) malloc(N * sizeof(GRID *));
for (i=0; i<N; i++) {
g[i] = (GRID *) malloc(N * sizeof(GRID));
}
for(row=0; row<N; row++){
for(col=0; col<N; col++){
g[row][col].number = UNASSIGNED;
g[row][col].editable = true;
}
}
return g;
}
bool find_unassigned_field(GRID **g, int *row, int *col){
for (*row = 0; *row < N; (*row)++) {
for (*col = 0; *col < N; (*col)++) {
if (g[*row][*col].number == UNASSIGNED){
return true;
}
}
}
return false;
}
bool validate_row(GRID **g, int row, int num) {
for (int col = 0; col < N; col++) {
if (g[row][col].number == num) {
return false;
}
}
return true;
}
bool validate_col(GRID **g, int col, int num) {
for (int row = 0; row < N; row++) {
if (g[row][col].number == num) {
return false;
}
}
return true;
}
bool validate_box(GRID **g, int row, int col, int num) {
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
if (g[r+row][c+col].number == num) {
return false;
}
}
}
return true;
}
bool validate_field(GRID **g, int row, int col, int num){
bool valrow, valcol, valbox, valunassigned;
valrow = validate_row(g, row, num);
valcol = validate_col(g, col, num);
valbox = validate_box(g, row - row%3 , col - col%3, num);
valunassigned = g[row][col].number==UNASSIGNED;
return (valrow && valcol && valbox && valunassigned);
}
bool generate_sudoku(GRID **g) {
int row, col;
// If there is no unassigned location, we are done
if (!find_unassigned_field(g, &row, &col)) {
return true; // success!
}
// consider digits 1 to 9
for (int num = 1; num <= 9; num++) {
// if looks promising
if (validate_field(g, row, col, num)) {
// make tentative assignment
g[row][col].number = num;
// return, if success, yay!
if (generate_sudoku(g)) {
return true;
}
// failure, unmake & try again
g[row][col].number = UNASSIGNED;
}
}
return false; // this triggers backtracking
}
void random_init_grid(GRID **g){
int row, col, num;
srand(time(0));
for(int cntr=0; cntr<20;){
row = rand() % N;
col = rand() % N;
num = rand() % N + 1;
if(g[row][col].number == UNASSIGNED){
if(validate_field(g, row, col, num)){
g[row][col].number = num;
cntr++;
}
}
}
}
int main(int argc, char *argv[]) {
GRID **g = create_sudoku_grid();
random_init_grid(g);
if(generate_sudoku(g)){
printf("OK\n\n");
} else {
printf("\nNOT OK\n\n");
}
print_sudoku(g);
}
Sudoko is a computationally hard problem possibly in the order of 10^100 using brute force and ignorance. It could take a lot longer than 2-3 minutes! Sometimes, because of number layout, it is easier than that.
In one approach, you could count your iterations, and give up if it exceeds them. Your key bit is the block where you recursively call generate_soduko() -- if you end up in here too many times you are in trouble.
To that end, I changed your program put a 1s alarm on its execution, counter the number of times in that block; and if the alarm expires, print the counter and exit; if it doesn't print the counter for reference at the end. On my machine, 1s == 500,000 iterations.
*** sud.c~ 2019-12-06 14:30:21.000000000 -0500
--- sud.c 2019-12-06 14:30:57.000000000 -0500
***************
*** 1,10 ****
#include <stdio.h>
#include <stdlib.h>
#define N 9
#define UNASSIGNED 0
-
typedef enum {false, true} bool;
typedef struct {
char number;
--- 1,21 ----
#include <stdio.h>
#include <stdlib.h>
+ #include <signal.h>
+ #include <unistd.h>
+ #include <time.h>
+
+ volatile long counter;
+ void alrm(int signo) {
+ char buf[64];
+ int n;
+ n = sprintf(buf, "failed after %ld iter\n", counter);
+ write(2, buf, n);
+ _exit(1);
+ }
#define N 9
#define UNASSIGNED 0
typedef enum {false, true} bool;
typedef struct {
char number;
***************
*** 106,111 ****
--- 117,123 ----
for (int num = 1; num <= 9; num++) {
// if looks promising
if (validate_field(g, row, col, num)) {
+ counter++;
// make tentative assignment
g[row][col].number = num;
***************
*** 139,145 ****
}
int main(int argc, char *argv[]) {
! GRID **g = create_sudoku_grid();
random_init_grid(g);
if(generate_sudoku(g)){
--- 151,161 ----
}
int main(int argc, char *argv[]) {
!
! GRID **g;
! signal(SIGALRM, alrm);
! alarm(1);
! g = create_sudoku_grid();
random_init_grid(g);
if(generate_sudoku(g)){
***************
*** 148,151 ****
--- 164,168 ----
printf("\nNOT OK\n\n");
}
print_sudoku(g);
+ printf("iter = %ld\n", counter);
}
I have to create a program for an assignment that solves a sudoku puzzle. User needs to enter the name of a binary file (NOT a true binary file, it just has a .bin extension, it can be opened with notepad, notepad++ etc. as well) that contains numbers. Those numbers represent coordinates on the puzzle as well as the number contained in those coordinates e.g 432 means 4th row 3rd column contains number 2. After filling out the puzzle i need to solve it and print it on screen. After executing the program it crashed, so I decided to use MSVC 2017 debugger which is among the best according to some developers to find and fix the bug. Here is my code:
Sudoku.c
#include <stdio.h>
#include <stdlib.h>
#include "stdafx.h"
#include "sudokulib.h"
#define MALLOC_ERROR 0xFF
#define FILE_NOT_FOUND 0xFFF
#define ROWS 9
#define COLUMNS 9
int main(int argc, char ** argv)
{
char **matrix;
int i, args;
int row, column, num;
FILE * fp;
char * filename;
char * importedData;
matrix = (char **)malloc(ROWS * sizeof(char *));
if (!matrix)
exit(MALLOC_ERROR);
for (i = 0; i<ROWS; ++i)
{
matrix[i] = (char *)malloc(COLUMNS * sizeof(char));
if (!matrix[i])
exit(MALLOC_ERROR);
}
initSudoku(matrix);
printf ("Give me the name of data file: ");
filename = (char *)malloc(100 * sizeof(char));
if (!filename)
exit(MALLOC_ERROR);
scanf("%99s", filename);
fp = fopen(filename, "rb");
if (!fp)
{
printf ("File not found\n");
exit(FILE_NOT_FOUND);
}
importedData = (char *)malloc(sizeof(char)*ROWS*COLUMNS * 3);
if (!importedData)
exit (MALLOC_ERROR);
args = fread(importedData, 1, 243, fp);
i = 0;
while (importedData[i] != ' ' && importedData[i + 1] != ' ' && importedData[i + 2] != ' ' && importedData[i] >= '1' && importedData[i + 1] >= '1' && importedData[i + 2] >= '1' && importedData[i] <= '9' && importedData[i + 1] <= '9' && importedData[i + 2] <= '9' && i < 243)
{
row = importedData[i] - '0' - 1; /* Convert from ascii code to number */
column = importedData[i + 1] - '0' - 1;
num = importedData[i + 2] - '0';
matrix[row][column] = num;
i = i + 3;
}
printf("Sudoku after importing data:\n\n");
printSudoku(matrix);
system("pause");
if (solvePuzzle(matrix))
{
printSudoku(matrix);
}
else
printf ("Puzzle has no solution\n");
fclose(fp);
free(filename);
for (i = 0; i<9; ++i)
{
free(matrix[i]);
}
free(matrix);
return 0;
}
Sudokulib.h
#pragma once
#include <stdlib.h>
#include <stdio.h>
/* Function Prototypes Begin Here */
void printSudoku(char **);
void initSudoku(char **);
int checkRow(char **, int, int);
int checkCol(char **, int, int);
int check3x3(char **, int, int, int);
int checkIfEmpty(char **, int*, int*);
int solvePuzzle (char **);
/* Function Prototypes End Here */
void printSudoku(char ** Mat)
{
int i, j;
for (i = 0; i<9; ++i)
{
printf ("-------------------\n");
printf("|");
for (j = 0; j<9; ++j)
{
printf("%d|", Mat[i][j]);
}
printf("\n");
}
printf ("-------------------\n");
}
void initSudoku(char ** Mat)
{
int i, j;
for (i = 0; i<9; ++i)
for (j = 0; j<9; ++j)
Mat[i][j] = 0;
}
int checkRow (char ** Mat, int row, int num) // if row is free returns 1 else returns 0
{
int col;
for (col = 0; col < 9; col++)
{
if (Mat[row][col] == num)
{
return 0;
}
}
return 1;
}
int checkCol (char ** Mat, int col, int num) // if column is free returns 1 else returns 0
{
int row;
for (row = 0; row < 9; row++)
{
if (Mat[row][col] == num)
{
return 0;
}
}
return 1;
}
int check3x3 (char ** Mat, int row, int col, int num) // if number doesnt exist in the 3x3 grid returns 1 else returns 0
{
row = (row / 3) * 3; // set to first row in the grid
col = (col / 3) * 3; // set to first col in the grid
int i;
int j;
for (i = 0; i < 3; i++) // grid is 3x3
{
for (j = 0; j < 3; j++)
{
if (Mat[row + i][col + j] == num)
{
return 0;
}
}
}
return 1;
}
int isValid (char ** Mat, int row, int col, int num)
{
return (checkRow(Mat, row, num) && checkCol(Mat, col, num) && check3x3(Mat, row, col, num));
}
int checkIfPuzzleSolved (char ** Mat, int *row, int *col) // if function finds a box empty (puzzle not solved) returns 0 else returns 1
{
for (*row = 0; *row < 9; *row++)
{
for (*col = 0; *col < 9; *col++)
{
printf("ROW: %d COL: %d\n",*row,*col);
if (Mat[*row][*col] == 0)
{
return 0;
}
}
}
return 1;
}
int solvePuzzle (char ** Mat)
{
int row;
int col;
if (checkIfPuzzleSolved(Mat, &row, &col))
{
return 1;
}
int num;
for (num = 1; num <= 9; num++)
{
//if (checkRow (Mat,row,num) && checkCol (Mat,col,num) && check3x3 (Mat,row,col,num))
if (isValid(Mat, row, col, num))
{
Mat[row][col] = num;
if (solvePuzzle(Mat))
return 1;
Mat[row][col] = 0;
}
}
return 0;
}
The debugger found a bug at this function:
int checkIfPuzzleSolved (char ** Mat, int *row, int *col) // if function finds a box empty (puzzle not solved) returns 0 else returns 1
{
for (*row = 0; *row < 9; *row++)
{
for (*col = 0; *col < 9; *col++)
{
printf("ROW: %d COL: %d\n",*row,*col);
if (Mat[*row][*col] == 0) /* DEBUGGER ERROR CODE 0xC0000005: Access violation reading location 0xCDCA247C
{
return 0;
}
}
}
return 1;
}
Two things that confused me:
1) I don't understand the reason solvePuzzle gets stuck brute forcing the first box in the puzzle (1st row 1st column). It seems that checkIfPuzzleSolved thinks that the first box is empty (containing 0), even though using printSudoku I can see the algorithm modifying that box toggles its value between 3 and 4 and obviously 0 != 3 and 0 != 4.
2) In checkIfPuzzleSolved, printf prints on screen row and column number and it constantly produces the following result:
ROW: 0 COL: 0
ROW: 0 COL: 0
ROW: 0 COL: -858993460
Also double checked this with the debugger and the values are indeed those mentioned.
My train of thought was the following:
1) Use checkIfEmpty to determine if a box of the puzzle contained 0, that would mean that the puzzle would not be solved yet. Row and col variables are sent into the function by reference, so when function finds an empty box and returns, row and col would save the coordinates of the empty box.
2) In the loop, call checkRow, checkCol and check3x3 to check if a number can be put into the desired box without breaking the sudoku rules. isValid is there for readability purposes.
3) Call solvePuzzle recursively until the puzzle is solved, meanwhile if a number is wrong, reset it to 0.
I have tried everything i could think of to solve this problem, wasting hours reading again and again my code to find a logical error, but everything seems okay. Any ideas?
EDIT: On request of Michael Beer, here is a sample binary file:
data.bin
142156177191216228257289311329364375418422441484534546562579625663682698739743787794824855883896917933951968
*row++; parses as *(row++);, which is equivalent to just row++. You're incrementing the pointer, not the counter.
– melpomene
I see. So am I incrementing the pointer by sizeof(int) and not increasing the value that it refers to by 1? If so what is the correct way of writing "increment the value of the address you are pointing to by 1" regarding the syntax?
(*row)++ or ++(*row) or ++*row or *row += 1.
– melpomene
I'm tryingto compare chars from a matrix, but it's not adding any values and i don't know why
so here's my code:
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINES 1000
#define MAX_LINE_LENGTH 1000
//---------------------
//READING & WRITING
//---------------------
char *ints_new(int n)
{
return (char *) malloc(n * sizeof(char));
}
char **ints2_new(int rows, int cols)
{
char **result = (char **) malloc(rows * sizeof(char *));
char *p = ints_new(rows * cols);
for (int i = 0; i < rows; i++, p += cols)
result[i] = p;
return result;
}
int str_readline(FILE *f, char *s)
{
int result = EOF;
char *p = fgets(s, INT_MAX, f);
if (p != NULL)
{
result = (int) strlen(s);
if (result > 0 && s[result-1] == '\n')
s[--result] = '\0';
}
return result;
}
char *str_dup(const char *s)
{
char *result = (char *) malloc(strlen(s) + 1);
strcpy(result, s);
return result;
}
int strings_read(FILE *f, char **a)
{
int result = 0;
char line[MAX_LINE_LENGTH + 2];
while (str_readline(f, line) != EOF)
a[result++] = str_dup(line);
return result;
}
// --------------------
// Problema A
// --------------------
void values_to_m(char **m, int rows, int cols, char **readings)
{
int i;
int j;
int k = 0;
int l = 0;
for(i = 0; i < rows; i++)
{
for(j = 0; j < cols; j++)
{
m[i][j] = readings[k][l];
l++;
}
k++;
l = 0;
}
}
int count_points(char **m, int i, int j, int rows, int cols)
{
int result = 0;
if(i < rows-2)
{
if(m[i][j] == m[i+1][j] == m[i+2][j])
result++;
if(j < cols-2)
{
if(m[i][j] == m[i][j+1] == m[i][j+2])
result++;
if(m[i][j] == m[i+1][j+1] == m[i+2][j+2])
result++;
}
if(j > 1)
{
if(m[i][j] == m[i+1][j-1] == m[i+2][j-2])
result++;
}
}
else
{
if(j < cols-2)
{
if(m[i][j] == m[i][j+1] == m[i][j+2])
result++;
}
}
printf("%d\n", result);
return result;
}
void points(char **m, int rows, int cols)
{
int i;
int j;
int player1 = 0; //O's
int player2 = 0; //X's
for(i = 0; i < rows; i++)
{
for(j = 0; j < cols; j++)
{
int count;
count = count_points(m, i, j, rows, cols); //counts points
if (m[i][j] == 'X') //if values i'm couning are X, points go to player 2
player2 += count;
else if(m[i][j] == 'O') //if O go to player 1
player1 += count;
}
}
printf("%d %d\n", player1, player2);
}
// --------------------
// --------------------
void test_problem_A()
{
char **readings = malloc((MAX_LINES * MAX_LINE_LENGTH) * sizeof(char) + 1);
int rows = strings_read(stdin, readings); //to read from console
int cols = strlen(readings[0]);
printf("%d\n%d\n", rows, cols); //just to make sure nr of rows and cols is right
char **m = ints2_new(rows, cols); //create matrix
values_to_m(m, rows, cols, readings); //put the values to matrix
points(m, rows, cols); //calculate points
ints2_printf(m, rows, cols, "%c");
}
// --------------------
// --------------------
int main(int argc, char **argv)
{
test_problem_A();
return 0;
}
My programm has to read a bunch of 'X', 'O' and '.'.
If there are 3 'X' in a row(vertical, horizontal or diagonal) player 2 gets 1 point, if the same happens to 'O', player 1 gets 1 point. '.' don't count any points.
my matrix had to have minimum 3 rows and cols and maximum 1000 rows and cols.
example:
If i put in console
XXO
OXO
OXO
player 1 and 2 each get 1 point
if i put:
XXXXXO //(int this line Player 2 get 3 points because there are 3 times 3 X in a row)
OXOXOO
OXOOXO
OXOXOO
player 1 gets 5 points
and player 2 gets 6 points
So my problema is with function "count_points" it's not counting any points, when I print "result" it always gives me 0 points.
Can't I compare 2 chars if they belong in a matrix?
Thanks
In count_points, you try to compare three values with expressions like
if (a == b == c) ...
This doesn't do what you think it does. You treat it like a comparison in mathematical notation, but C interprets it as:
if ((a == b) == c) ...
The comparison a == b yields either 0 or 1. That result is then compared with c.
You could rewrite your desired expression as
if (a == b && b == c) ...
Given that your a, b and c are compound expressions, you could write a small function for that:
static int eq3(int a, int b, int c)
{
return (a == b && b == c);
}
int count_points(char **m, int i, int j, int rows, int cols)
{
int result = 0;
if (i < rows-2) {
if (eq3(m[i][j], m[i+1][j], m[i+2][j]))
result++;
if (j < cols - 2) {
if (eq3(m[i][j], m[i][j+1], m[i][j+2]))
result++;
if (eq3(m[i][j], m[i+1][j+1], m[i+2][j+2]))
result++;
}
if (j > 1) {
if (eq3(m[i][j], m[i+1][j-1], m[i+2][j-2]))
result++;
}
} else {
if (j < cols-2) {
if (eq3(m[i][j], m[i][j+1], m[i][j+2]))
result++;
}
}
return result;
}
As for the allocation of your matrix, see alk's answer. Your method of allocation - one char ** for the rows and then string duplication for the row data, could leave you with a ragged array and you may not safely access m[j + 1][i] for some cases where i is a valid index for row j, but not for row j + 1.
For starters, here you want to allocate pointers to char:
char **readings = malloc((MAX_LINES * MAX_LINE_LENGTH) * sizeof(char) + 1);
So do so:
char **readings = malloc((MAX_LINES * MAX_LINE_LENGTH) * sizeof(char*) + 1);
or even better:
char **readings = malloc((MAX_LINES * MAX_LINE_LENGTH) * sizeof *readings + 1);
I need to create a program which would ask from user to input a string and then function in program needs to separate it to 2 strings of same size (user always inputs even number of chars) and after that it has to "shuffle" them...
So it should basically do this:
user inputs: A1B1C1D1
code should make 2 same sized strings: A1B1 and C1D1 and after that it should "shuffle" them to look like this: A1C1B1D1.
So it needs to take first 2 elements of first string, then first 2 elements of second string and so on…
My problem is that when I input A1B1C1D1, after I run the program, I get AC1BD1 (it leaves out 2nd char from first array).
#include<stdio.h>
#include<string.h>
#define N 100
void shuffle(char *cards) {
int i, n, x=0, c1=0, c2=0, j=0;
char tmp1[N]={0}, tmp2[N]={0};
n=strlen(cards);
//divide to 2 arrays with same number of elements
for(i=0; i<n; i++){
if(i<(n/2)){
tmp1[i]=cards[i];}
else{
tmp2[x]=cards[i];
x++;
}
}
//storing 2 elements from first array, then 2 elements from second array and so on
for(i=0; i<n; i++){
if(j>3){
j=0;
}
if(j<=1){ // store 2 elements from 1st array
cards[i]=tmp1[c1];
c1++;
j++;
}
if(j>=2){ // store 2 elements from 2nd array
cards[i]=tmp2[c2];
c2++;
j++;
}
}
printf("1st half:%s\n2nd half:%s", tmp1, tmp2);
printf("\n\t%s",cards);
return;
}
int main() {
char cards[N];
scanf("%s", cards);
shuffle(cards);
return 0;
}
The problem is here
if(j<=1){ // store 2 elements from 1st array
cards[i]=tmp1[c1];
c1++;
j++;
}
if(j>=2){ // store 2 elements from 2nd array
cards[i]=tmp2[c2];
c2++;
j++;
}
Make the second if as an "else if" (just an "else" is also enough)
What happens is that after you increment j from 1 to 2, you go into the second if statement, and rewrite on the same index on cards.
If you don't mind an alternative suggestion for "shuffling your deck of cards" in a much simpler way:
void shuffle(char *cards)
{
char tmp[N]={0};
int n = strlen(cards);
for (int i=0; i<n/2; i++)
tmp[i*2+0] = cards[i];
for (int i=0; i<n/2; i++)
tmp[i*2+1] = cards[i+n/2];
for (int i=0; i<n; i++)
cards[i] = tmp[i];
}
You call it shuffle and cards.
Wouldnt it be better to make a card structure that has two elements?
I thinky your j in the for loop is behaving wrong.
I will double check this and edit this answer if it wasnt j.
EDIT:
Your cradcount was off by a bit and you wrote the wrong index.
Here is some working code:
j = 0;
i = 0;
while(i<n)
{
++j;
if(j == 1 || j == 2)
{ // store 2 elements from 1st array
cards[i++]=tmp1[c1++];
}
else if(j == 3 || j == 4)
{ // store 2 elements from 2nd array
cards[i++]=tmp2[c2++];
}
else
{
j = 0;
}
}
In general you can use the debugger to see whats happening with your index. I assume this is homework and you have to write "optimal code". In general it would be beneficial to use varaiblaenames with more meaning.
EDIT2:
There is a nice solution below that illustrates time optimized code.
I wanted to add some code that i think is easier to read and maintain.
#include<stdio.h>
#include<string.h>
#define DECK_MAX 100
typedef struct
{
char group;
int number;
}Tcard;
typedef struct
{
Tcard card[DECK_MAX];
int count;
}Tdeck;
int ReadDeck(Tdeck * deck, const char *cardstring);
int DeckAddCopy(Tdeck * deck, Tcard * card);
int PrintDeck(Tdeck * deck, const char *deckname);
int InterleaveDecksCopy(Tdeck * target, Tdeck * source[], int sourcecount);
int SplitDeckCopy(Tdeck * source, Tdeck * target[], int targetcount);
int main() {
int e = 0;
char cardstring[100];
Tdeck deck, stackA, stackB, interleaved;
Tdeck * stacks[] = {&stackA, &stackB};
printf("Please input a cardstring: ");
scanf("%s", cardstring);
e |= ReadDeck(&deck, cardstring);
e |= PrintDeck(&deck, "cardstring");
e |= SplitDeckCopy(&deck, stacks, sizeof(stacks) / sizeof(Tdeck*) );
e |= PrintDeck(&stackA, "1st half");
e |= PrintDeck(&stackB, "2nd half");
e |= InterleaveDecksCopy(&interleaved, stacks, sizeof(stacks) / sizeof(Tdeck*) );
e |= PrintDeck(&interleaved, "interleaved");
if( e != 0) printf("There was an error dureing execution.\n");
return e;
}
int ReadDeck(Tdeck * deck, const char *cardstring)
{
int e = 0;
int varCount, n, total = 0;
Tcard card;
memset(deck, 0, sizeof(Tdeck));
do{
n = 0;
varCount = sscanf(&cardstring[total], "%c%i%n", &card.group, &card.number, &n);
total += n;
if( varCount == 2 )
{
//check if card is valid?
e |= DeckAddCopy(deck, &card);
}
else
{
if(strlen(cardstring) != total)
{
//string was not read completely
e |= 1;
}
}
}while(varCount == 2);
return e;
}
int DeckAddCopy(Tdeck * deck, Tcard * card)
{
int e = 0;
if(deck->count >= DECK_MAX)
{
e |= 1;
}
else
{
memcpy(&deck->card[deck->count++], card, sizeof(Tcard));
}
return e;
}
int PrintDeck(Tdeck * deck, const char *deckname)
{
int c;
printf("%s contains %i cards%s", deckname, deck->count, (deck->count == 0)? ".\n":": ");
for(c = 0; c < deck->count; ++c)
{
printf("%c%i%s", deck->card[c].group, deck->card[c].number, ( c+1 < deck->count) ? ", ":".\n");
}
return 0;
}
int InterleaveDecksCopy(Tdeck * target, Tdeck * source[], int sourcecount)
{
int c, s, e = 0;
memset(target, 0, sizeof(Tdeck));
for(c = 0; c < DECK_MAX; ++c)
{
for(s = 0; s < sourcecount ; ++s)
{
if(c < source[s]->count)
{
e |= DeckAddCopy(target, &source[s]->card[c]);
}
}
}
return e;
}
int SplitDeckCopy(Tdeck * source, Tdeck * target[], int targetcount)
{
int c, t, e = 0;
for(t = 0; t < targetcount ; ++t)
{
memset(target[t], 0, sizeof(Tdeck));
}
c = 0;
for(t = 0; t < targetcount ; ++t)
{
int cMax = (source->count) - (((source->count)/targetcount) * targetcount - t - 1 );
for( ; c < (t+1)*(source->count)/targetcount ; ++c)
{
e |= DeckAddCopy(target[t], &source->card[c]);
}
}
return e;
}