Every now and again I vow to learn C, and now seems like a good time to have another go.
My plan for learning C is always the same:
- Read K&R
- ?
- Profit
Where step 2 might as well be 'Don't use C and forget everything in K&R'. The problem is that I'm not a systems programmer, so everything I want to program is just easier to do in Java.
This time round I'm having a go with Learn C The Hard Way. It takes a way more modern and pragmatic approach than K&R, and introduces tools like make and valgrind early on.
I'm going to try and not fall back on more familiar languages, and see if I can knock out interesting things in C where appropriate, and blog about them to help me learn.
First off a simple Sudoku solver:
main.c
#include <stdio.h>
#include <stdlib.h>
#define _ 0
#define GRID_SIZE 9
#define SQUARE_SIZE 3
#define FALSE 0
#define TRUE !FALSE
void print(int grid[GRID_SIZE][GRID_SIZE]);
int complete(int grid[GRID_SIZE][GRID_SIZE]);
int contains(int array[GRID_SIZE], int value);
void row(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int row[GRID_SIZE]);
void column(int grid[GRID_SIZE][GRID_SIZE], int columnIndex, int column[GRID_SIZE]);
void square(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int columnIndex, int square[GRID_SIZE]);
int main(int argc, char** argv) {
int grid[GRID_SIZE][GRID_SIZE] ={
{_, 3, 6, _, 5, _, _, 8, 7},
{9, _, 1, 7, 8, _, _, 6, 2},
{_, _, 7, _, _, _, 1, 4, _},
{_, _, 5, _, 9, _, _, _, 3},
{_, _, _, _, 1, _, _, _, _},
{8, _, _, _, 7, _, 6, _, _},
{_, 2, 9, _, _, _, 5, _, _},
{5, 7, _, _, 2, 9, 8, _, 6},
{6, 1, _, _, 3, _, 2, 9, _}
};
int rowIndex;
int columnIndex;
int value;
int possibleValue;
int possibleValueCount;
int inRow;
int inColumn;
int inSquare;
int tmp[GRID_SIZE];
while (!complete(grid)) {
for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {
if (grid[rowIndex][columnIndex] != _) {
continue;
}
possibleValue = _;
possibleValueCount = 0;
for (value = 1; value <= GRID_SIZE; value++) {
row(grid, rowIndex, tmp);
inRow = contains(tmp, value);
if (inRow) {
continue;
}
column(grid, columnIndex, tmp);
inColumn = contains(tmp, value);
if (inColumn) {
continue;
}
square(grid, rowIndex, columnIndex, tmp);
inSquare = contains(tmp, value);
if (inSquare) {
continue;
}
possibleValue = value;
possibleValueCount++;
}
if (possibleValueCount == 1) {
grid[rowIndex][columnIndex] = possibleValue;
}
}
}
}
print(grid);
return (EXIT_SUCCESS);
}
void print(int grid[GRID_SIZE][GRID_SIZE]) {
int rowIndex;
int columnIndex;
for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {
if (columnIndex != 0) {
printf(", ");
}
printf("%d", grid[rowIndex][columnIndex]);
}
printf("\n");
}
}
int complete(int grid[GRID_SIZE][GRID_SIZE]) {
int tmp[GRID_SIZE];
int rowIndex;
int inRow;
for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
row(grid, rowIndex, tmp);
inRow = contains(tmp, _);
if (inRow) {
return FALSE;
}
}
return TRUE;
}
int contains(int array[GRID_SIZE], int value) {
int i;
for (i = 0; i < GRID_SIZE; i++) {
if (array[i] == value) {
return TRUE;
}
}
return FALSE;
}
void row(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int row[GRID_SIZE]) {
int columnIndex;
for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {
row[columnIndex] = grid[rowIndex][columnIndex];
}
}
void column(int grid[GRID_SIZE][GRID_SIZE], int columnIndex, int column[GRID_SIZE]) {
int rowIndex;
for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
column[rowIndex] = grid[rowIndex][columnIndex];
}
}
void square(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int columnIndex, int square[GRID_SIZE]) {
int i;
int j;
int x = SQUARE_SIZE * (rowIndex / SQUARE_SIZE);
int y = SQUARE_SIZE * (columnIndex / SQUARE_SIZE);
for (i = 0; i < SQUARE_SIZE; i++) {
for (j = 0; j < SQUARE_SIZE; j++) {
square[(i * SQUARE_SIZE) + j] = grid[x + i][y + j];
}
}
}