C programming: live console display of recursive function output (knight's tour) - c

I'm stuck at my first more complex coding task in C: developing a program that solves the knight's tour (chess, knight has to visit every field on the board only once) and it also should have a live display, showing which move the program is taking in real time.
The solution I came up with doesn't support live display though, as it is iterating through a for loop until the maximum number of moves has been reached, then prints the moves. How could I change this code to create real time output?
The displayBoard function is only printing a chessboard in the console output, with the current position of the knight as well as the field's name (e.g. A-1). Plan is to change this to a stream output for console, after my initial problem is solved.
(In conjunction to this question: how exactly does the function calling as if condition work? I stumbled upon this in the webs but sadly there was no explanation to it.)
int knight(int line, int row, int moveNumber)
{
int newLine, newRow, i;
//char cells[]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
//mark visited cell
board[line][row] = moveNumber;
//for-loop for every possible move
for(i = 0; i < 8; i++)
{
//new position
newLine = line + moves[i][0];
newRow = row + moves[i][1];
//is the move on the board?
if(newLine >= 1 && newLine <= N && newRow >= 1 && newRow <= N)
{
//has the cell been visited yet?
if(!board[newLine][newRow])
{
//recursion until 63th move
if(moveNumber == max_moves || knight(newLine, newRow, moveNumber+1))
{
printf("Move %d: from %c-%d to %c-%d ", moveNumber, cells[row-1], line, cells[newRow-1], newLine);
boardDisplay(newLine, newRow);
return 1;
}
}
}
}
// free last visited cell, if there's no move possible anymore
board[line][row] = 0;
return 0;
}

Related

How to read array in different directions?

I'm really new and bad at programming in C as I just started learning. Please be patient with me. I am currently trying to solve this puzzle: https://www.codingame.com/ide/puzzle/hidden-word. In the website, you can click on the three lines with three dots symbol on a box labeled "test cases" to view the test cases, then click on each test case to see the grid of letters and numbers in the left box, and then the expected output in the right box.
I know what I have to do which is to search through the grid of letters horizontally, vertically, diagonally, and the reverse of them, remove the numbers, don't print the repeated letters and combine the rest of the letters, print it out as the expected output.
I know how to write some of the other parts except for the one most important part, which is described in the title. I don't know how to check the letters horizontally, vertically, diagonally, and the reverse of them as the test cases have different numbers of column and rows. I figured I should use array but I am really bad at writing array codes.
Again, I am new and not a native English speaker so most of the stuff I just referenced on the internet and modified them. I probably shouldn't manually put the input in an array myself as the code is already written in the background (I don't know how to call it) and I don't know how to do this better.
Here is my current code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MAX_STR_LEN 41
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
char aWord[41];
scanf("%s", aWord);
}
int h;
int w;
scanf("%d%d", &h, &w);
for (int i = 0; i < h; i++) {
char line[41];
scanf("%s", line);
}
int i;
int F[7][3] = {
{'2', '\0', '\0'},
{'B', 'A', 'C'},
{'B', 'O', 'B'},
{'3', '\0', '3'},
{'B', 'A', 'C'},
{'B', 'O', 'B'},
{'R', 'E', 'D'}
};
for (i = 0; i < n; i++) {
int string;
scanf("%d", &F);
// remove numbers
// don't print repeated elements
// combine the rest of the elements
strcpy(string, F);
// print the combined elements
}
return 0;
}
As you can see, I have attempted but failed miserably. Can someone guide me through it? You don't really have to help me write the code, you could just tell me where and what to learn to write this type of code or teach me how to write them please. Thanks in advance.
You don't really have to help me write the code, you could just tell me where and what to learn to write this type of code or teach me how to write them please
Note: This is an abstract idea on how to solve the problem using a trie, combine them together to your own implementation
I have an idea on how to solve this. First, you need to know and be able to implement Trie datastructure in C. as you read the n number of words you have to build (append the words to) the trie.
For the grid, you have to create a 2d array of GridEntry as defined below
typedef struct {
char c;
bool crossed; //< #include <stdbool.h>
} GridEntry;
GridEntry grid[rows][columns]; //< don't just copy this, won't work
now you have to iterate each entry in the grid. if it's already crossed skip and go to the next entry, else try to match a word starting at that entry horizontally, vertically and diagonally using the trie. (how to match trie is given below)
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
if (grid[r][c].crossed) continue;
try_match_word(trie, grid, r, c);
}
}
How to match a word with trie? try_match_word function
first, check if any word in the trie start with the current entry character
if not, no matches found return (from try_match_word) otherwise
iteratively pick a direction (horizontally, vertically and diagonally) move towards that direction (here is how to pick a direction)
// your direction is (x, y) = {(1, 1), (1, 0), (0, -1), ...}
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (x == 0 && y == 0) continue;
// now (x, y) is the direction
int r_end = -1, c_end = -1; // end coordinate of the word
}
}
now you have to move through that direction until you find the grid edge or you match
The longest word when it doesn't match a word anymore. (here is how you move through a grid)
int i = 0;
while (true) {
int cx = c + i*x;
int cy = r + i*y; // (cx, cy) is the current position in the grid
// check boundary conditions here and break the loop;
i++;
}
now before you pick the direction you have to keep a current trie pointer to track the current character of the word as you move through the grid you have to update the trie pointer to the next character's trie.
Trie* curr = trie->chars[grid[r][c].c]; //< current trie
if (curr == NULL) return; //< no matching word
// and inside the move loop (where we've declared cx, cy)
Trie* next = curr->chars[grid[cy][cx].c];
if (next == NULL) {
if (curr->is_end) {
r_end = cy, c_end = cx; // word ends here
}
break;
}
curr = next;
once you match a word you'll know it if a r_end, c_end are != -1. and you have to cross those characters from (c, r) to (c_end, r_end). move through the coordinate and mark crossed grid[cy][cx].crossed = true;
once you matching words from each cell, you have to re iterate through the entries and collect the characters which are not crossed make a string, and return it.
char answer[256]; int i = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
if (grid[r][c].crossed) continue;
answer[i++] = grid[r][c].c;
}
}
answer[i] = '\0';
return answer;

Minimax algorithm and checking every option / keeping track of best move in C

I try to make a tic tac toe game using minimax algorithm, but I have a hard time with recursion and keeping track of best move.
Now, my function returns a score when there is a winner, and then deletes that move from a board. My question is, how to prevent it to search the same child node again?
int minimax(Board *board, int depth, char player, Position lastPosition)
{
Position avMoves;
int score = -2;
if (didTheGameEnd(*board, (player == 'X') ? 'O' : 'X', lastPosition) == 1) {
return (depth % 2 != 0) ? -10 : 10;
} else if (didTheGameEnd(*board, (player == 'X') ? 'O' : 'X', lastPosition) == -1) {
return 0;
}
if (board->numberOfBlanks != 0) {
avMoves = getAvaliableMoves(*board);
}
for (int i = 0; i < board->numberOfBlanks; i++) {
int newScore;
placeMark(board, player, avMoves);
newScore = minimax(board, depth+1, changePlayer(player), avMoves);
if (depth % 2 != 0) {
if (newScore > score) {
score = newScore;
}
} else {
if (newScore < score) {
score = newScore;
}
}
board->boardArr[avMoves.y][avMoves.x] = '-';
board->numberOfBlanks++;
board->numberOfOccupied--;
}
return score;
}
How to return the best move ?
EDIT I forgot to add, that I try to make this on N size board
it may be helpful to look at the source code for Tom Kerrigan's "simple chess program" below
basically the following code is part of the alpha-beta (minmax) function. It generates the moves and loops over the moves in the for loop checking if there are any legal moves to be made (this is necessary as chess uses pseudo-legal move generators) part of the key to returning the best variation is use of a "triangular array" that collects the best variation in pv[0][0..pv_length[0]]. pv_length keeps track of the length of the best variation at various depth of the gametree. Its a tedious indexing scheme but gets the job done.
gen();
if (follow_pv) /* are we following the PV? */
sort_pv();
f = FALSE;
/* loop through the moves */
for (i = first_move[ply]; i < first_move[ply + 1]; ++i) {
sort(i);
if (!makemove(gen_dat[i].m.b))
continue;
f = TRUE;
x = -search(-beta, -alpha, depth - 1);
takeback();
if (x > alpha) {
/* this move caused a cutoff, so increase the history
value so it gets ordered high next time we can
search it */
history[(int)gen_dat[i].m.b.from][(int)gen_dat[i].m.b.to] += depth;
if (x >= beta)
return beta;
alpha = x;
/* update the PV */
pv[ply][ply] = gen_dat[i].m;
for (j = ply + 1; j < pv_length[ply + 1]; ++j)
pv[ply][j] = pv[ply + 1][j];
pv_length[ply] = pv_length[ply + 1];
}
}
/* no legal moves? then we're in checkmate or stalemate */
if (!f) {
if (c)
return -10000 + ply;
else
return 0;
}
/* fifty move draw rule */
if (fifty >= 100)
return 0;
return alpha;
}
How to return the best move?
You check each possible move and return the one with the best score. Of course as soon as you found a winning move you can return it immediately.
What makes it difficult is the design of your function. You would have to make the move and then call the function with the move that was made, revert it and test the next one. If you redesign your function to take nextPosition instead of lastPosition as parameter and then execute that move inside the function things will be a little easier.
How to prevent the same positions to be searched again?
Use a lookup table. A position can easily be represented by 18 bits, a single integer, e.g. by using the first 9 bits to say where the X pieces are and the next 9 bits where the O pieces are. It would be possible with fewer bits but then you need complicated en- and decoding.
X X -
- O - = 110 000 000 000 010 001 = 196625
- - O
I also suggest to have a look at alpha-beta pruning, with good move ordering (try the promising ones first) you can cut off whole branches and save a lot of time. For tic tac toe it doesn't matter, but as soon as it gets a little more complex it helps a lot.

C, ncurses; if statement within while loop not functioning properly

I'm writing a function that draws # characters onto a console screen, and repeats itself until it draws upon a 'H' which has already been drawn. Basically a "bomb" function. I wrote the function with a while loop so that it may continue to draw the character as long as the space it is drawing upon does not equal 'H'. If it does equal 'H', i've put in an if statement to break the program. However even with the if statement, the program continues to run when it is drawn on an 'H'.
void bomb_until_hit(int home_radius) {
int x = 0, y = 0;
while (mvinch(y, x) != 'H') {
x = get_next_bomb_x();
y = get_next_bomb_y();
mvaddch(y, x, '#' );
refresh();
sleep(1);
if (mvinch(y, x) == 'H') {
break; }
}
}
mvinch is a function which basically checks the coordinates for characters before the new character is drawn.
Why is my if statement not working?
Your code draws an # and then checks for an H (twice). Obviously, it's not going to find an H since it just drew an #.
Let's look at what happens starting from when you move to a new position:
void bomb_until_hit(int home_radius) {
int x = 0, y = 0;
while (mvinch(y, x) != 'H') { // 5) Check for an H here
x = get_next_bomb_x(); // 1) Move to next X
y = get_next_bomb_y(); // 2) Move to next Y
mvaddch(y, x, '#' ); // 3) Put an # here
refresh();
sleep(1);
if (mvinch(y, x) == 'H') { // 4) Check for an H here
break; }
}
}
You need to rearrange the order of your statements so that once you move to a new spot, you check it before you write to it.

C String -- Sort by first-word length [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm self-studying C and doing an exercise that, among other things, asks me to sort a list of user-entered strings by length of the first word in the string. The other functions in the exercise (including sorting the string by entire length) were easy to write. I've been working on this one for over three hours and can't get it to work. I'm sorting an array of pointers-to-char, and then printing them with a for loop in the main() function.
There's probably a much easier way to do this, but even if so, I cannot understand why this function doesn't work. I've made about thirty changes to it and the sort still comes out pretty random.
void srtlengthw(char * strings[], int n)
{
int top, seek, ct, ct_temp, i;
int ar_ct[n]
char * temp;
bool inWord;
for (top = 0, ct = 0, i = 0, inWord = false; top < n - 1; top++)
{
while (strings[top][i])
{
if (!isblank(strings[top][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[top] = ct;
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
{
if (!isblank(strings[seek][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[seek] = ct;
if (ar_ct[top] > ar_ct[seek])
{
ct_temp = ar_ct[top];
ar_ct[top] = ar_ct[seek];
ar_ct[seek] = ct_temp;
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
}}
Example of wrong output, as requested:
Input:
Mary
had
a
little
lamb
that
was
sacrificed
to
Satan
=========
Output:
had
a
little
lamb
that
was
sacrificed
to
Mary
Satan
And here's an example of a much simpler function that worked properly. It's meant to sort the pointers by length of the entire string rather than just the first word. I tried to model the word-length sort function on this one, but I'm apparently having trouble dealing with my counter variables and maybe my bool flag right.
void srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (strlen(strings[top]) > strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
For Craig, hopefully this helps?
Input:
They say it's lonely at the top, and whatever you do
You always gotta watch m*********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
Output for me:
You always gotta watch m********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
They say it's lonely at the top, and whatever you do
If you're looking for output similar to that of the example code that you posted, then I suggest using it as a template for a version with your expected behavior. The key that I'm looking to point out is that it sorts by the return value of the strlen function.
strlen is a function in C's <string.h> library (I think?) that returns the length of a C-style string. In C, as you're probably aware, the end of a string is identified by a null terminator, which is represented as a '\0'.
While the precise strlen may vary from one library to another, here is one standard implementation (made easier to read):
int strlen(char * str){
char * l;
for(l = str; *l != '\0'; l++);
return l - str;
}
People will likely argue that there are problems with this and it isn't perfect, but it does hopefully show how the length of a string is determined.
Now that we understand that the last example sorts by the total string length, and we know how string length is determined, we can probably make our own version of strlen that stops after the first word, instead of stopping at the null terminator:
int blank_strlen(char * str){
char * l;
for(l = str; *l != '\0' && !isblank(*l); l++);
return l - str;
}
Now, using the example code given:
void blank_srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (blank_strlen(strings[top]) > blank_strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
millinon's answer is a much better way to do it, as it is simpler. However, if you are looking for the reason why your code isn't working, it is due to your variables only being reset outside of each loop.
This code:
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
only sets ct, i and inWord once, before the loop is first started. When the program loops around, the values of ct, i and inWord will be kept from the last iteration.
Moving the assignments inside the loop like this:
for (seek = top + 1; seek < n; seek++)
{
ct = 0;
i = 0;
inWord = false;
while(strings[seek][i])
will fix your problem (you have to do it in both places).

Word Wrap Program C

At the end of Chapter 1 of The C Programming Language, there are a few exercises to complete. The one I am doing now asks you to make a program that wraps a long string of text into multiple lines at a specific length. The following function works 100%, aside from the last line which does not get wrapped, no matter the specified maximum width of a line.
// wrap: take a long input line and wrap it into multiple lines
void wrap(char s[], const int wrapline)
{
int i, k, wraploc, lastwrap;
lastwrap = 0; // saves character index after most recent line wrap
wraploc = 0; // used to find the location for next word wrap
for (i = 0; s[i] != '\0'; ++i, ++wraploc) {
if (wraploc >= wrapline) {
for (k = i; k > 0; --k) {
// make sure word wrap doesn't overflow past maximum length
if (k - lastwrap <= wrapline && s[k] == ' ') {
s[k] = '\n';
lastwrap = k+1;
break;
}
}
wraploc = 0;
}
} // end main loop
for (i = 0; i < wrapline; ++i) printf(" ");
printf("|\n");
printf("%s\n", s);
}
I have found the issue to be with the variable wraploc, which is incremented until it is greater than wrapline (the maximum index of a line). Once it is greater than wrapline, a newline is inserted at the appropriate location and wraploc is reset to 0.
The problem is that on the last line, wraploc is never greater than wrapline, even when it should be. It increments perfectly throughout iteration of the string, until the last line. Take this example:
char s[] = "This is a sample string the last line will surely overflow";
wrap(s, 15);
$ ./a.out
|
this is a
sample string
the last line
will surely overflow
The line represents the location where it should be wrapped. In this case, wraploc has the value 14, when there are clearly more characters than that.
I have no idea why this is happening, can someone help me out?
(Also I'm a complete beginner to C and I have no experience with pointers so please stay away from those in your answers, thanks).
You increment wraploc with i until it reaches wrapline (15 in the example).
When you wrap, you backtrack from i, back to the last whitespace.
That means that in your next line you already have some characters between the lastwrap location and i, i.e., you can't reset wraploc to 0 there.
Try setting wraploc = i-lastwrap instead.
Anybody who might, like me, find this question and run into a problem with new-lines in the source string.
This is my answer:
inline int wordlen(const char * str){
int tempindex=0;
while(str[tempindex]!=' ' && str[tempindex]!=0 && str[tempindex]!='\n'){
++tempindex;
}
return(tempindex);
}
void wrap(char * s, const int wrapline){
int index=0;
int curlinelen = 0;
while(s[index] != '\0'){
if(s[index] == '\n'){
curlinelen=0;
}
else if(s[index] == ' '){
if(curlinelen+wordlen(&s[index+1]) >= wrapline){
s[index] = '\n';
curlinelen = 0;
}
}
curlinelen++;
index++;
}
}

Resources