I try to implement the minimax-algorithm into my connect-four game.
I want to implement it with recursion. However I think i dont explore the whole gametree with my function:
for(i=0;i<COLS;i++) {
if(can_throw(c, i) == 0) {
throw(f, i);
if((is_winner(c) == 0) && (is_board_full(f) == 0)) { //no winner, board not full
minimax(f);
}
else if(is_winner(c) == 1) { //there is a winner
evaluate_turn();
undo_turn();
}
else if(is_winner(c) == 0 && (is_board_full(f) == 1)) { //no winner, board full
evaluate_turn();
undo_turn();
}
}
}
Does someone has a solution how to explore the whole gametree with recursion?
The evaluation is just 1 for win, 0 for draw, -1 for loss.
I`m not sure either whats the best way to compare the evaluations against each other, to have the right values on the "top-level" without introducing a datastructure (which would exceed memory). Does someone know how to do that either?
Related
Does anyone know if a function is supposed to end after it returns something?
I have my recursion function written below, but whenever it reaches the else statement and after it returns a value (steps),
it runs the "if (new_number % 2 == 1)" statement,
which does not make sense since the function should end when it reaches the else statement and should not repeat.
It works fine until it returns "steps" for the first time.
This is what happens after the first return:
It doesn't even fully run the "if (new_number % 2 == 1)" statement, it just jumps to that line and decreases the value of "steps" and "input_steps" by 1. "new_number" and "number" just get completely random values
Then it returns "steps", then it jumps to "if (new_number % 2 == 1)" statement and decreases the value of "steps" and "input_steps" by 1. "new_number" and "number" just get completely random values again.
It repeats that cycle until "new_steps" and "steps" equal 0, then it returns 0 (because "steps" = 0) and ends the function.
Does anyone know why it does this????
Here is my code:
int step_recursion(int number, int input_steps)
{
int new_number = number;
int steps = input_steps;
if (new_number != 1)
{
if (new_number % 2 == 0)
{
if (new_number != 1)
{
step_recursion(new_number / 2, steps + 1);
}
}
if ((new_number % 2) == 1)
{
if (new_number != 1)
{
step_recursion(new_number * 3 + 1, steps + 1);
}
}
}
return steps;
}
I was expecting the function to end after returning "steps," but for some reason it doesn't. I already described the problem fully so go read that.
As far as I can see you are trying to implement the famous "Collatz conjecture". Below is a working version...
int step_recursion(int number, int steps) {
if (number == 1) {
return steps;
}
if (number % 2 == 0) {
return step_recursion(number / 2, steps + 1);
} else {
return step_recursion(number * 3 + 1, steps + 1);
}
return steps;
}
In your code you are checking twice if the number is not equal to 1. Its better if you have an "early return"
You don't return the value of the recursion calls, you are just calling the function
Let's go inline for a moment, then we'll cover your question, which seems excessively verbose and difficult to digest (and I'll explain that when I come back to it). Note the comments I added to this excerpt of your code...
if (new_number % 2 == 0)
{
if (new_number != 1)
{
// if your intent is to control flow such that execution doesn't continue beyond here, you'd surely want a `return` statement here...
/* return step_recursion(new_number / 2, steps + 1); */
step_recursion(new_number / 2, steps + 1);
}
}
if ((new_number % 2) == 1)
{
if (new_number != 1)
{
/* ditto here */
step_recursion(new_number * 3 + 1, steps + 1);
}
}
I already described the problem fully so go read that.
My issue with your question is that it's rather lengthy, full of erroneous premises (which are kind of questions disguised as erroneous statements of fact) and unnecessary (English) boilerplate, which ought to be asked as different questions. For example:
Which book are you reading that teaches you "the function should end when it reaches the else statement"? This is a fundamental misunderstanding of C. Just to be clear, the else statement doesn't cause a function to return.
It works fine until it returns "steps" for the first time.
In other words, "it works fine until it doesn't work", which is an entirely superfluous statement that we could attach to almost any question on this network. That doesn't add meaning, though, does it? Hopefully your future questions are easier to digest, with less of this meaningless fluff.
Does anyone know why it does this????
The absence of a full problem description isn't the only reason for closure; sometimes we close questions because they have multiple built-in questions... The answer to this question is yes, but that single word answer doesn't help you understand.
Does anyone know if a function is supposed to end after it returns something?
... and to be clear, asking if something is a different question to asking why something. The answer to this different question is also yes.
TLDR; take this with a pinch of salt, but when you come here you really need to think about what information you're asking for and how to ask for that exact information without asking other questions (or injecting invalid assertions) at the same time.
I try to implement the minimax algorithm into my connect four game.
I´m done with the evaluation-function and halfway done with the algorithm-function.
I just can`t find the solution for the "last" problem. Here are my functions:
void minimax(field f){
int i;
field c;
convert_1D_to_2D(f, c);
for(i=0;i<COLS;i++) {
if(can_throw(c, i) == 0) {
throw(f, i);
convert_1D_to_2D(f, c);
if((is_winner(c) == 0) && (is_board_full(f) == 0)) { //no winner, board not full
minimax(f);
}
else if(is_winner(c) == 1) { //there is a winner
evaluate_turn(f);
//compare evaluation
undo_turn(f);
}
else if(is_winner(c) == 0 && (is_board_full(f) == 1)) { //no winner, board full
evaluate_turn(f);
//compare evaluation
undo_turn(f);
}
}
}
The field is an array with f[COLS*ROWS+1], where f[0] is the depth and the other elements save in which columns were thrown. the "c"-board represents the "graphical" board with 0 for free, 1 for player 1 and 2 for player 2.
static int evaluate_turn(field f) {
field c;
convert_1D_to_2D(f, c);
if (((f[0] % 2) == 1) && (current_player == 1) && (is_winner(c) == 1) ) { //player 1 won, max for him || +1
return 1;
}
else if (((f[0] % 2) == 2) && (current_player == 2) && (is_winner(c) == 1) ) { //player 2 won, max for him || +1
return 1;
}
if (((f[0] % 2) == 1) && (current_player == 2) && (is_winner(c) == 1) ) { //player 2 won, counting for 1 || -1
return -1;
}
else if (((f[0] % 2) == 2) && (current_player == 1) && (is_winner(c) == 1) ) { //player 1 won, counting for 2 || -1
return -1;
}
else if ((is_board_full(f) == 1) && (is_winner(c) == 0)) { //draw || 0
return 0;
}
So my problem is, that i can't think of a clean solution to compare the evaluation bottom to top. I really think, that I don't need to introduce a new datastructure (which would get way too big). It's like the solution is right in front of me but i can't grab it.
Is it possible to just compare the evaluation on the "way back" of the recursion? If yes, how?
Or do I really need to introduce something new more complex? Or maybe I'm missing off something completely?
Thanks!
Or do I really need to introduce something new more complex? Or maybe
I'm missing off something completely?
Unfortunately the answer is the latter. Minimax is not a void function. It returns the value of the node that it represents. That is how evaluation is compared. You are also missing another fundamental concept. Your function only considers terminal nodes to be those where the game is won or the board is full. While this is technically true, no real minimax function works that way. The number of nodes would be around 7^48, so your function would literally take upwards of ten years to terminate on a modern pc. What real world minimax functions do is set a maximum depth for the search to reach (unless you add tree pruning expect this to be 5 or 6), and consider all nodes at that depth to be terminal and evaluate them using a heuristic (inexact guess) evalation function. In connect four this could be based on something like the number of three in a rows. Another mistake you made is calling your eval function if you know there is a winner. If you know which player won than return the proper value straight out, no need to call the expensive eval function. You also cannot stream line your function for both min and max as you did. You must either create a seperate function for min and max, or use the negamax variant.
My advise: It seems you don't really understand how the algorithm should be implemented. Read up on minimax and negamax psuedocode.
This is just a general question really.
I wrote this originally
do
{
scanf("%i", &Carselect);
if (Carselect == 1)
{
mass = 1100;
velomax = 200;
}
else if (Carselect == 2)
{
mass = 1888;
velomax = 415
}
else if (Carselect == 3)
{
mass = 18000;
velomax = 129;
}
else
{
printf("Error in input. Please enter 1, 2 or 3.\n");
}
}
while (Carselect != 1 || Carselect != 2 || Carselect != 3);
And I got stuck in the loop. I put breaks in the statements for the valid conditions and that allowed me to get out, like this
do
{
scanf("%i", &Carselect);
if (Carselect == 1)
{
mass = 1100;
velomax = 200;
break;
}
else if (Carselect == 2)
{
mass = 1888;
velomax = 415;
break;
}
else if (Carselect == 3)
{
mass = 18000;
velomax = 129;
break;
}
else
{
printf("Error in input. Please enter 1, 2 or 3.\n");
}
}
while (Carselect != 1 || Carselect != 2 || Carselect != 3);
but I thought that the conditions for while were repeat conditions, so as soon as Carselect equals 1, 2 or 3 it will exit the loop. If you have to put breaks in the if statements, why do we need to bother with conditions in the while operation?
What is there, on the machine level or otherwise, that requires this seemingly trivial bit of logic?
Edit (as the question's title is changed):
The checking condition in the while/do-while loop is the one that is primarily checked to determine if the program is to stay in or to get out of the while/do-while loop - not the break statement.
The break statement is normally used if:
you want to get out of the while/do-while block before it is executing every statement in the block or
when certain exceptional termination condition is reached before you loop through your entire loop iteration or
You create an infinite loop and you capture an error which makes you unable to continue the loop or
Some other other cases which I might not be aware of...
Essentially, break-statement is not normally used to terminate the while/do-while block as long as the program follows (for lack of better term) "standard/main" path in the loop block.
In contrast, condition in the while/do-while loop is used to terminate the loop when the program follows "standard/main" path in the loop block.
Original:
You should change your inequality check (!=) into NOT equality check (==).
while (!(Carselect == 1 || Carselect == 2 || Carselect == 3));
This is because what you really want is for the loop to continue as long as
the Carselect is not (1 or 2 or 3)
Alternatively, you could change the or operator (||) to and operator (&&) which results in the same logic:
while (Carselect != 1 && Carselect != 2 && Carselect != 3);
the Carselect is not 1 and not 2 and not 3
In C break takes you to the statement immediately following } of the containing block, and continue takes you to to the statement immediately following { of the containing block. Both are useful in a long block, for example if an error condition occurs, or if a simpler input is detected, and not all the processing of the complete block is required, but you want to continue and get the next input.
I've tried searching for anything similar about my issue on several websites, including this one, but none I've found so far are similar. After searching about the term 1.#QO, I found something about quiet NaN, but I'm new to C in general, so I don't really understand the issue .
I'm trying to take the x and y values of a joystick, and when then use a formula for distance to find the distance between the joystick's position, and the joystick's natural resting position (0,0).
If it matters, I'm trying to do this in RobotC.
#pragma config(Hubs, S1, HTMotor, none, none, none)
#pragma config(Sensor, S1, , sensorI2CMuxController)
#pragma config(Motor, mtr_S1_C1_1, DriveMotor, tmotorTetrix, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
#include "JoystickDriver.c"
int calculateDrivePower(int joyStickX, int joyStickY)
{
if (joyStickX != 0 & joyStickY != 0)
{
int joyDistance = (sqrt(pow((joyStickX - 0),2)+ pow((-joyStickY - 0),2)));
joyDistance = ((joyDistance/127)*100);
return (joyDistance);
}
else
{
return 0;
}
}
task main()
{
int previousJoySlope = 0;
int TurnSpeed = 70;
while (true)
{
getJoystickSettings(joystick);
if (abs(joystick.joy1_x1) > 10 || abs(joystick.joy1_y1) > 10)
{
writeDebugStreamLine("Test successful.");
motor[DriveMotor] = calculateDrivePower(joystick.joy1_x1,joystick.joy1_y1);
}
}
}
If anyone could provide any insight, that'd be fantastic, thanks.
if (joyStickX != 0 & joyStickY != 0)
{
int joyDistance = (sqrt(pow((joyStickX - 0),2)+ pow((-joyStickY - 0),2)));
joyDistance = ((joyDistance/127)*100);
return (joyDistance);
}
The first issues that appears is the conditional within the if statement. The you have a single & that most likely should be &&:
if (joyStickX != 0 && joyStickY != 0)
(note: likely should be is used above because you can provide a conditional using a logical & of the tests joystickx != 0, but in this case it provides the same result. In that case, I would suggest the more readable && be used)
The next part of the code is simply the vector distance between 0,0 and the present position of the joystick. Of the general form dist^2 = (x2-x1)^2 + (y2-y1)^2 in your case x1,y1 = 0,0. Taking the square root of both sides provides dist = sqrt((x2-x1)^2 + (y2-y1)^2), or in C notation:
dist = (sqrt(pow((joyStickX - 0),2)+ pow((-joyStickY - 0),2)));
Next you have a scaling applied of dist = dist * 100/127 which provides the final distance returned. Hopefully this will help you understand what the code is doing.
basically I need to implement a pause feature in my game (which is a simplified version of frogger) which stops the logs scrolling, and ignores any other input until the character p is pressed again). The way I've started to implement this in a while loop is to end it once another p Is pressed.
if(serial_input == 'p' || serial_input == 'P') {
while(1){
//need to pause the game
if(serial_input == 'p' || serial_input == 'P')
break;
}
This is how my logs are currently scrolling:
/* The following statements change the scrolling speeds of the individual logs */
current_time = get_clock_ticks();
if(is_frog_alive() && current_time >= last_move_time1 + 1000) {
scroll_lane(0, 1);
last_move_time1 = current_time;
} else if(is_frog_alive() && current_time >= last_move_time2 + 600) {
scroll_lane(1, -1);
last_move_time2 = current_time;
} else if(is_frog_alive() && current_time >= last_move_time3 + 800) {
scroll_lane(2, 1);
last_move_time3 = current_time;
} else if(is_frog_alive() && current_time >= last_move_time4 + 900) {
scroll_log_channel(0, -1);
last_move_time4 = current_time;
} else if(is_frog_alive() && current_time >= last_move_time5 + 1200) {
scroll_log_channel(1, 1);
last_move_time5 = current_time;
And this is implemented by a timer as described:
* We update a global clock tick variable - whose value
* can be retrieved using the get_clock_ticks() function.
*/
Any suggestions would be greatly appreciated
The best practice would depend on the libraries and general architecture you're using. That being said a naive implementation which I sometimes use would go somewhat like this:
while( playing) {
if( !paused) {
logic();
}
rendering();
input();
}
When doing small game projects, inside the main while loop I scatter logic, rendering and input in to different parts. In the input part there's the button that toggles the pause flag. In the main loop, the logic is simply enclosed in an if statement.
If you still need to do something inside the logic, you could pass it as a parameter or make it visible in some other way. Additionally you can do some special when-paused-graphics in the rendering section.
Details would vary but I hope this would at least give you a nudge to the right direction. That being said it is a common thing to implement and shouldn't be too hard to google.