void test_valid_move_from_maneuvre_stack_to_maneuvre_stacks() { struct stack *maneuvre_stacks[7]; for (int i = 0; i < 7; i++) { stack_malloc(&maneuvre_stacks[i]); stack_init(maneuvre_stacks[i]); } card_set(maneuvre_stacks[0]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_0_BEGIN_X); card_set(maneuvre_stacks[1]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_1_BEGIN_X); card_set(maneuvre_stacks[2]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_2_BEGIN_X); card_set(maneuvre_stacks[3]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_3_BEGIN_X); card_set(maneuvre_stacks[4]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_4_BEGIN_X); card_set(maneuvre_stacks[5]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_5_BEGIN_X); card_set(maneuvre_stacks[6]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_6_BEGIN_X); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == j) { assert(!valid_move(maneuvre_stacks[i], maneuvre_stacks[j])); } else { assert(valid_move(maneuvre_stacks[i], maneuvre_stacks[j])); } } } for (int i = 0; i < 7; i++) { stack_free(maneuvre_stacks[i]); } }
/* Basically the same code as minimax. It initiates the move making process. */ void AI::make_move(int current_player, Board* game_board) { //Defines max and min possible scores. int alpha = -2000; int beta = 2000; //The depth is initially 0. This will be incremented after every recursive call to minimax. int depth = 0; //Defines the best possible score so far and a default position. int best_score; int position = 4; //If player is X. if (current_player == 1) { //We try to get a better score than alpha, so we default to alpha in the beginning. best_score = alpha; //We basically perform all 7 (at most) possible moves. for (int i = 1; i < 8; ++i) { //Only if i is a valid move. if (valid_move(i)) { //It plays the move i in the vector and simply recursively calls minimax to maximize (or minimize) its score and revert all moves. play(current_player, i); int score = minimax(best_score, beta, -current_player, game_board, depth); if (score > best_score) { //Score and position are stored. best_score = score; position = i; } //Move is reverted. revert(current_player, i); //Here we perform alpha beta pruning, which enables us to discard large sections of the Search Tree. if (beta <= best_score) { break; } } } } //Same process as with 1. else if (current_player == -1) { best_score = beta; for (int i = 1; i < 8; ++i) { if (valid_move(i)) { play(current_player, i); int score = minimax(alpha, best_score, -current_player, game_board, depth); if (score < best_score) { best_score = score; position = i; } revert(current_player, i); if (best_score <= alpha) { break; } } } } //After determining the best position (from the best score), it makes that move. play(current_player, position); }
static int check_nomove() { unsigned char c; if (_othello->state != NO_MOVE && _othello->state != GAME_OVER) return 0; for (c = 0; c < 64; c++) { if (valid_move(&_othello->board, &_othello->b_set, S_WHITE, c)) return 0; if (valid_move(&_othello->board, &_othello->b_set, S_BLACK, c)) return 0; } _othello->state = GAME_OVER; return 1; }
void test_valid_move_from_waste_pile_to_waste_pile() { struct stack *waste_pile_0, *waste_pile_1; stack_malloc(&waste_pile_0); stack_malloc(&waste_pile_1); stack_init(waste_pile_0); stack_init(waste_pile_1); card_set(waste_pile_0->card, ACE, SPADES, EXPOSED, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X); card_set(waste_pile_1->card, KING, HEARTS, EXPOSED, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X); assert(!valid_move(waste_pile_0, waste_pile_0)); assert(!valid_move(waste_pile_0, waste_pile_1)); assert(!valid_move(waste_pile_1, waste_pile_0)); assert(!valid_move(waste_pile_1, waste_pile_1)); stack_free(waste_pile_0); stack_free(waste_pile_1); }
void test_valid_move_from_stock_to_maneuvre_stacks() { struct stack *stock, *maneuvre_stacks[7]; stack_malloc(&stock); stack_init(stock); card_set(stock->card, ACE, SPADES, EXPOSED, STOCK_BEGIN_Y, STOCK_BEGIN_X); for (int i = 0; i < 7; i++) { stack_malloc(&maneuvre_stacks[i]); stack_init(maneuvre_stacks[i]); } card_set(maneuvre_stacks[0]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_0_BEGIN_X); card_set(maneuvre_stacks[1]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_1_BEGIN_X); card_set(maneuvre_stacks[2]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_2_BEGIN_X); card_set(maneuvre_stacks[3]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_3_BEGIN_X); card_set(maneuvre_stacks[4]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_4_BEGIN_X); card_set(maneuvre_stacks[5]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_5_BEGIN_X); card_set(maneuvre_stacks[6]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_6_BEGIN_X); for (int i = 0; i < 7; i++) { assert(!valid_move(stock, maneuvre_stacks[i])); } stack_free(stock); for (int i = 0; i < 7; i++) { stack_free(maneuvre_stacks[i]); } }
void test_valid_move_from_stock_to_stock() { struct stack *stock_0, *stock_1; stack_malloc(&stock_0); stack_malloc(&stock_1); stack_init(stock_0); stack_init(stock_1); card_set(stock_0->card, ACE, SPADES, EXPOSED, STOCK_BEGIN_Y, STOCK_BEGIN_X); card_set(stock_1->card, KING, HEARTS, EXPOSED, STOCK_BEGIN_Y, STOCK_BEGIN_X); assert(!valid_move(stock_0, stock_0)); assert(!valid_move(stock_0, stock_1)); assert(!valid_move(stock_1, stock_0)); assert(!valid_move(stock_1, stock_1)); stack_free(stock_0); stack_free(stock_1); }
void test_valid_move_from_maneuvre_stack_to_foundation_stacks() { struct stack *foundation_stacks[4]; struct stack *maneuvre_stacks[7]; for (int i = 0; i < 4; i++) { stack_malloc(&foundation_stacks[i]); stack_init(foundation_stacks[i]); } card_set(foundation_stacks[0]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_0_BEGIN_X); card_set(foundation_stacks[1]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_1_BEGIN_X); card_set(foundation_stacks[2]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_2_BEGIN_X); card_set(foundation_stacks[3]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_3_BEGIN_X); for (int i = 0; i < 7; i++) { stack_malloc(&maneuvre_stacks[i]); stack_init(maneuvre_stacks[i]); } card_set(maneuvre_stacks[0]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_0_BEGIN_X); card_set(maneuvre_stacks[1]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_1_BEGIN_X); card_set(maneuvre_stacks[2]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_2_BEGIN_X); card_set(maneuvre_stacks[3]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_3_BEGIN_X); card_set(maneuvre_stacks[4]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_4_BEGIN_X); card_set(maneuvre_stacks[5]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_5_BEGIN_X); card_set(maneuvre_stacks[6]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_6_BEGIN_X); for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; j++) { assert(valid_move(maneuvre_stacks[i], foundation_stacks[j])); } } for (int i = 0; i < 4; i++) { stack_free(foundation_stacks[i]); } for (int i = 0; i < 7; i++) { stack_free(maneuvre_stacks[i]); } }
void test_valid_move_from_maneuvre_stack_to_waste_pile() { struct stack *waste_pile, *maneuvre_stacks[7]; stack_malloc(&waste_pile); stack_init(waste_pile); card_set(waste_pile->card, ACE, SPADES, EXPOSED, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X); for (int i = 0; i < 7; i++) { stack_malloc(&maneuvre_stacks[i]); stack_init(maneuvre_stacks[i]); } card_set(maneuvre_stacks[0]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_0_BEGIN_X); card_set(maneuvre_stacks[1]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_1_BEGIN_X); card_set(maneuvre_stacks[2]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_2_BEGIN_X); card_set(maneuvre_stacks[3]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_3_BEGIN_X); card_set(maneuvre_stacks[4]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_4_BEGIN_X); card_set(maneuvre_stacks[5]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_5_BEGIN_X); card_set(maneuvre_stacks[6]->card, ACE, SPADES, EXPOSED, MANEUVRE_BEGIN_Y, MANEUVRE_6_BEGIN_X); for (int i = 0; i < 7; i++) { assert(!valid_move(maneuvre_stacks[i], waste_pile)); } stack_free(waste_pile); for (int i = 0; i < 7; i++) { stack_free(maneuvre_stacks[i]); } }
// Player's turn void player_turn(int board[][BOARD_SIZE], int player) { char turn; int x; int y; if (player == 1) { turn = 'X'; } if (player == -1) { turn = 'O'; } while(1) { printf("Player %c, enter a move: ", turn); scanf("%d %d", &x, &y); if (valid_move(x, y, board) == 1) break; else printf("Sorry, invalid move!\n"); } make_move(x, y, board, player); }
//Almost identical to make_move, except we increment depth since it is being called recursively. int AI::minimax(int alpha, int beta, int current_player, Board* game_board, int depth) { if (game_board->checkWin()) return current_player * -1000; else if (game_board->checkDraw()) return 0; if (depth == 7) { if (player == -1) return evaluate(game_board); else if (player == 1) return -(evaluate(game_board)); } ++depth; int best_score; if (current_player == 1) { best_score = alpha; for (int i = 1; i < 8; ++i) { if (valid_move(i)) { play(current_player, i); int score = minimax(best_score, beta, -current_player, game_board, depth); if (score > best_score) best_score = score; revert(current_player, i); if (beta <= best_score) { break; } } } } else if (current_player == -1) { best_score = beta; for (int i = 1; i < 8; ++i) { if (valid_move(i)) { play(current_player, i); int score = minimax(alpha, best_score, -current_player, game_board, depth); if (score < best_score) best_score = score; revert(current_player, i); if (best_score <= alpha) { break; } } } } return best_score; }
take_move() { // take keyboard input for opponents move char opToPos[2] = std_in; // test opponents move for validity if( !valid_move( opPos, opToPos ) ) fail("Opponent made invalid move"); make_move() }
std::vector<Move> Board::get_available_moves(bool is_black) { std::vector<Move> result; for (std::size_t i = 0; i < board.size(); i++) { for (std::size_t j = 0; j < board.size(); j++) { if (valid_move(i, j, is_black)) { Move tmp(i, j, is_black); result.push_back(tmp); } } } return result; }
//checks a specific move from specific location on the board. If move viable and doesn't lead to duplicate board, //new board shows this move and 1 is returned. If no moves found, returns 0 int check_move (movement direction, int i, int j, hash *hash_array, Node *start, Node *latest_node, int parent_board [BOARD_HEIGHT][BOARD_WIDTH], int new_board[BOARD_HEIGHT][BOARD_WIDTH]){ if (valid_move (direction, i, j, new_board)){ move_piece (direction, i, j, new_board); latest_node->identifier = allocate_board_identifier (new_board); if (insert_hash (hash_array, latest_node, latest_node->identifier, new_board) == 1){ copy_board (new_board, parent_board); } else{ return 1; } } return 0; }
void test_valid_move_from_waste_pile_to_stock() { struct stack *stock, *waste_pile; stack_malloc(&stock); stack_malloc(&waste_pile); stack_init(stock); stack_init(waste_pile); card_set(stock->card, ACE, SPADES, EXPOSED, STOCK_BEGIN_Y, STOCK_BEGIN_X); card_set(waste_pile->card, KING, HEARTS, EXPOSED, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X); assert(!valid_move(waste_pile, stock)); stack_free(stock); stack_free(waste_pile); }
void test_valid_move_from_foundation_stack_to_foundation_stacks() { struct stack *foundation_stacks[4]; for (int i = 0; i < 4; i++) { stack_malloc(&foundation_stacks[i]); stack_init(foundation_stacks[i]); } card_set(foundation_stacks[0]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_0_BEGIN_X); card_set(foundation_stacks[1]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_1_BEGIN_X); card_set(foundation_stacks[2]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_2_BEGIN_X); card_set(foundation_stacks[3]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_3_BEGIN_X); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (i == j) { assert(!valid_move(foundation_stacks[i], foundation_stacks[j])); } else { assert(valid_move(foundation_stacks[i], foundation_stacks[j])); } } } for (int i = 0; i < 4; i++) { stack_free(foundation_stacks[i]); } }
void Game::move(Pile *from, Pile *to, int num) { assert(valid_move(from, to, num)); to->move_from(*from, num); /* Flip tableau card if necessary */ for (int i = 0; i < NUM_TABLEAU; i++) { if (from == tableau[i]) { if (VERBOSE) std::cout << "visibility check tableau found" << std::endl; if (!from->get_card(0).visible) { if (VERBOSE) std::cout << "Flipping card" << std::endl; from->get_card(0).visible = true; } } } }
bool move(char op) { if(__on_lift) { cerr << "the game is already over." << endl; assert(false); } // step++; __last_op = op; if(op == 'A') { score += 25 * got; return true; } if(!valid_move(op)) return false; Pos np = __next_pos(op); int diff_x = np.x - pos.x, diff_y = np.y - pos.y; if(at(np.x, np.y, step) == ROCK) { set(np.x + diff_x, np.y + diff_y, step, ROCK); } else if(at(np.x, np.y, step) == LAMBDA) { got++; score += 25; got_lambda = true; } else { got_lambda = false; } set(pos.x, pos.y, step, __on_lift ? LIFT : EMPTY); if(at(np.x, np.y, step) == LIFT) { score += 50 * got; __on_lift = true; } else { __on_lift = false; } set(np.x, np.y, step, ROBOT); pos = np; score--; return true; }
void player_move() { int pos, valid = 1; int ch, flag = 0; // for invalid characters in scanf do { if(!valid && !flag){ printf("Invalid move! Try Again.\n"); } printf("\n\nEnter position you want to play: "); if(scanf("%d", &pos) <= 0) { valid = 1; while ((ch = getchar()) != '\n' && ch != EOF); printf("Weird character encountered!!!\n"); flag = 1; continue; } flag = 0; }while(!(valid = valid_move(pos, 1))); }
static signed char best_move(uint64_t *bo, uint64_t *bs, char side) { uint64_t t_bo, t_bs; unsigned char c, bc = 0; int best = NOMOVE; int pts; for (c = 0; c < 64; c++) { if (!valid_move(bo, bs, side, c)) continue; memcpy(&t_bo, bo, sizeof(uint64_t)); memcpy(&t_bs, bs, sizeof(uint64_t)); pts = move_piece(&t_bo, &t_bs, side, c); if (pts > best) { best = pts; bc = c; } } return (best != NOMOVE) ? bc : NOMOVE; }
void test_valid_move_from_stock_to_foundation_stacks() { struct stack *stock, *foundation_stacks[4]; stack_malloc(&stock); stack_init(stock); card_set(stock->card, ACE, SPADES, EXPOSED, STOCK_BEGIN_Y, STOCK_BEGIN_X); for (int i = 0; i < 4; i++) { stack_malloc(&foundation_stacks[i]); stack_init(foundation_stacks[i]); } card_set(foundation_stacks[0]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_0_BEGIN_X); card_set(foundation_stacks[1]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_1_BEGIN_X); card_set(foundation_stacks[2]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_2_BEGIN_X); card_set(foundation_stacks[3]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_3_BEGIN_X); for (int i = 0; i < 4; i++) { assert(!valid_move(stock, foundation_stacks[i])); } stack_free(stock); for (int i = 0; i < 4; i++) { stack_free(foundation_stacks[i]); } }
void test_valid_move_from_foundation_stack_to_waste_pile() { struct stack *waste_pile, *foundation_stacks[4]; stack_malloc(&waste_pile); stack_init(waste_pile); card_set(waste_pile->card, ACE, SPADES, EXPOSED, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X); for (int i = 0; i < 4; i++) { stack_malloc(&foundation_stacks[i]); stack_init(foundation_stacks[i]); } card_set(foundation_stacks[0]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_0_BEGIN_X); card_set(foundation_stacks[1]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_1_BEGIN_X); card_set(foundation_stacks[2]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_2_BEGIN_X); card_set(foundation_stacks[3]->card, ACE, SPADES, EXPOSED, FOUNDATION_BEGIN_Y, FOUNDATION_3_BEGIN_X); for (int i = 0; i < 4; i++) { assert(!valid_move(foundation_stacks[i], waste_pile)); } stack_free(waste_pile); for (int i = 0; i < 4; i++) { stack_free(foundation_stacks[i]); } }
void _droidzebra_redo_turn(int *side_to_move) { int target_disks_played = 0; int curr_move; if (!_droidzebra_can_redo()) return; target_disks_played = _droidzebra_undo_stack_pop(); droidzebra_message_debug("redo: score_sheet_row %d, disks_played %d, new_disks_played %d", score_sheet_row, disks_played, target_disks_played); while (disks_played < target_disks_played) { generate_all(*side_to_move); if (move_count[disks_played] > 0) { curr_move = get_stored_move(disks_played); if (curr_move == ILLEGAL || !valid_move(curr_move, *side_to_move)) { fatal_error("Invalid move %c%c in redo sequence", TO_SQUARE(curr_move)); } (void) make_move(*side_to_move, curr_move, TRUE); } else { curr_move = PASS; } droidzebra_message_debug( "redo: score_sheet_row %d, curr_move %d, side_to_move %d, disks_played %d", score_sheet_row, curr_move, *side_to_move, disks_played); if (*side_to_move == BLACKSQ) black_moves[score_sheet_row] = curr_move; else { white_moves[score_sheet_row] = curr_move; } *side_to_move = OPP(*side_to_move); if (*side_to_move == BLACKSQ) score_sheet_row++; } }
//keyboard function - gameplay implementation void keyboard(unsigned char ch, int x, int y) { float aux_x = player_x; float aux_y = player_y; if (!finished) { switch(ch) { case 27: //esc exit(0); break; //move forward case 'w': aux_x += -sin((3.14 * player_r) / 180) * 0.05; aux_y += cos((3.14 * player_r) / 180) * 0.05; if (valid_move(aux_x, aux_y)) { player_x = aux_x; player_y= aux_y; } break; //move backward case 's': aux_x -= -sin((3.14 * player_r) / 180) * 0.05; aux_y -= cos((3.14 * player_r) / 180) * 0.05; if (valid_move(aux_x, aux_y)) { player_x = aux_x; player_y= aux_y; } break; //move right case 'd': aux_y += sin((3.14 * player_r) / 180) * 0.05; aux_x += cos((3.14 * player_r) / 180) * 0.05; if (valid_move(aux_x, aux_y)) { player_x = aux_x; player_y= aux_y; } break; //move left case 'a': aux_y -= sin((3.14 * player_r) / 180) * 0.05; aux_x -= cos((3.14 * player_r) / 180) * 0.05; if (valid_move(aux_x, aux_y)) { player_x = aux_x; player_y= aux_y; } break; //modify direction in the trigonometric sens case 'q': player_r += 3; if (player_r == 360) player_r = 0; break; //modify direction in the opposite sense case 'e': player_r -= 3; if (player_r == 0) player_r = 360; break; //move forward at high speed case 'x': aux_x += -sin((3.14 * player_r) / 180) * 0.2; aux_y += cos((3.14 * player_r) / 180) * 0.2; if (valid_move(aux_x, aux_y)) { player_x = aux_x; player_y= aux_y; } break; //change camera up case '0': cam = 0; break; //change camera first-person case '1': cam = 1; break; //change camera third-person case '2': cam = 2; break; default: break; } if (cam == 2) switch (ch) { case '3': break; case '4': break; case '5': break; case '6': break; case '7': break; case '8': break; } if ((abs(player_x - portal_x) < 0.20) && (abs(player_y - portal_y) < 0.20)) finished = 1; } //give a signal if you won if (finished) Beep(2000, 200); glutPostRedisplay(); }
std::vector<tripoint> map::route( const tripoint &f, const tripoint &t, const pathfinding_settings &settings, const std::set<tripoint> &pre_closed ) const { /* TODO: If the origin or destination is out of bound, figure out the closest * in-bounds point and go to that, then to the real origin/destination. */ std::vector<tripoint> ret; if( f == t || !inbounds( f ) ) { return ret; } if( !inbounds( t ) ) { tripoint clipped = t; clip_to_bounds( clipped ); return route( f, clipped, settings, pre_closed ); } // First, check for a simple straight line on flat ground // Except when the line contains a pre-closed tile - we need to do regular pathing then static const auto non_normal = PF_SLOW | PF_WALL | PF_VEHICLE | PF_TRAP; if( f.z == t.z ) { const auto line_path = line_to( f, t ); const auto &pf_cache = get_pathfinding_cache_ref( f.z ); // Check all points for any special case (including just hard terrain) if( std::all_of( line_path.begin(), line_path.end(), [&pf_cache]( const tripoint & p ) { return !( pf_cache.special[p.x][p.y] & non_normal ); } ) ) { const std::set<tripoint> sorted_line( line_path.begin(), line_path.end() ); if( is_disjoint( sorted_line, pre_closed ) ) { return line_path; } } } // If expected path length is greater than max distance, allow only line path, like above if( rl_dist( f, t ) > settings.max_dist ) { return ret; } int max_length = settings.max_length; int bash = settings.bash_strength; int climb_cost = settings.climb_cost; bool doors = settings.allow_open_doors; bool trapavoid = settings.avoid_traps; const int pad = 16; // Should be much bigger - low value makes pathfinders dumb! int minx = std::min( f.x, t.x ) - pad; int miny = std::min( f.y, t.y ) - pad; int minz = std::min( f.z, t.z ); // TODO: Make this way bigger int maxx = std::max( f.x, t.x ) + pad; int maxy = std::max( f.y, t.y ) + pad; int maxz = std::max( f.z, t.z ); // Same TODO as above clip_to_bounds( minx, miny, minz ); clip_to_bounds( maxx, maxy, maxz ); pathfinder pf( minx, miny, maxx, maxy ); // Make NPCs not want to path through player // But don't make player pathing stop working for( const auto &p : pre_closed ) { if( p.x >= minx && p.x < maxx && p.y >= miny && p.y < maxy ) { pf.close_point( p ); } } // Start and end must not be closed pf.unclose_point( f ); pf.unclose_point( t ); pf.add_point( 0, 0, f, f ); bool done = false; do { auto cur = pf.get_next(); const int parent_index = flat_index( cur.x, cur.y ); auto &layer = pf.get_layer( cur.z ); auto &cur_state = layer.state[parent_index]; if( cur_state == ASL_CLOSED ) { continue; } if( layer.gscore[parent_index] > max_length ) { // Shortest path would be too long, return empty vector return std::vector<tripoint>(); } if( cur == t ) { done = true; break; } cur_state = ASL_CLOSED; const auto &pf_cache = get_pathfinding_cache_ref( cur.z ); const auto cur_special = pf_cache.special[cur.x][cur.y]; // 7 3 5 // 1 . 2 // 6 4 8 constexpr std::array<int, 8> x_offset{{ -1, 1, 0, 0, 1, -1, -1, 1 }}; constexpr std::array<int, 8> y_offset{{ 0, 0, -1, 1, -1, 1, -1, 1 }}; for( size_t i = 0; i < 8; i++ ) { const tripoint p( cur.x + x_offset[i], cur.y + y_offset[i], cur.z ); const int index = flat_index( p.x, p.y ); // @todo: Remove this and instead have sentinels at the edges if( p.x < minx || p.x >= maxx || p.y < miny || p.y >= maxy ) { continue; } if( layer.state[index] == ASL_CLOSED ) { continue; } // Penalize for diagonals or the path will look "unnatural" int newg = layer.gscore[parent_index] + ( ( cur.x != p.x && cur.y != p.y ) ? 1 : 0 ); const auto p_special = pf_cache.special[p.x][p.y]; // @todo: De-uglify, de-huge-n if( !( p_special & non_normal ) ) { // Boring flat dirt - the most common case above the ground newg += 2; } else { int part = -1; const maptile &tile = maptile_at_internal( p ); const auto &terrain = tile.get_ter_t(); const auto &furniture = tile.get_furn_t(); const vehicle *veh = veh_at_internal( p, part ); const int cost = move_cost_internal( furniture, terrain, veh, part ); // Don't calculate bash rating unless we intend to actually use it const int rating = ( bash == 0 || cost != 0 ) ? -1 : bash_rating_internal( bash, furniture, terrain, false, veh, part ); if( cost == 0 && rating <= 0 && ( !doors || !terrain.open ) && veh == nullptr && climb_cost <= 0 ) { layer.state[index] = ASL_CLOSED; // Close it so that next time we won't try to calculate costs continue; } newg += cost; if( cost == 0 ) { if( climb_cost > 0 && p_special & PF_CLIMBABLE ) { // Climbing fences newg += climb_cost; } else if( doors && terrain.open && ( !terrain.has_flag( "OPENCLOSE_INSIDE" ) || !is_outside( cur ) ) ) { // Only try to open INSIDE doors from the inside // To open and then move onto the tile newg += 4; } else if( veh != nullptr ) { part = veh->obstacle_at_part( part ); int dummy = -1; if( doors && veh->part_flag( part, VPFLAG_OPENABLE ) && ( !veh->part_flag( part, "OPENCLOSE_INSIDE" ) || veh_at_internal( cur, dummy ) == veh ) ) { // Handle car doors, but don't try to path through curtains newg += 10; // One turn to open, 4 to move there } else if( part >= 0 && bash > 0 ) { // Car obstacle that isn't a door // @todo: Account for armor int hp = veh->parts[part].hp(); if( hp / 20 > bash ) { // Threshold damage thing means we just can't bash this down layer.state[index] = ASL_CLOSED; continue; } else if( hp / 10 > bash ) { // Threshold damage thing means we will fail to deal damage pretty often hp *= 2; } newg += 2 * hp / bash + 8 + 4; } else if( part >= 0 ) { if( !doors || !veh->part_flag( part, VPFLAG_OPENABLE ) ) { // Won't be openable, don't try from other sides layer.state[index] = ASL_CLOSED; } continue; } } else if( rating > 1 ) { // Expected number of turns to bash it down, 1 turn to move there // and 5 turns of penalty not to trash everything just because we can newg += ( 20 / rating ) + 2 + 10; } else if( rating == 1 ) { // Desperate measures, avoid whenever possible newg += 500; } else { // Unbashable and unopenable from here if( !doors || !terrain.open ) { // Or anywhere else for that matter layer.state[index] = ASL_CLOSED; } continue; } } if( trapavoid && p_special & PF_TRAP ) { const auto &ter_trp = terrain.trap.obj(); const auto &trp = ter_trp.is_benign() ? tile.get_trap_t() : ter_trp; if( !trp.is_benign() ) { // For now make them detect all traps if( has_zlevels() && terrain.has_flag( TFLAG_NO_FLOOR ) ) { // Special case - ledge in z-levels // Warning: really expensive, needs a cache if( valid_move( p, tripoint( p.x, p.y, p.z - 1 ), false, true ) ) { tripoint below( p.x, p.y, p.z - 1 ); if( !has_flag( TFLAG_NO_FLOOR, below ) ) { // Otherwise this would have been a huge fall auto &layer = pf.get_layer( p.z - 1 ); // From cur, not p, because we won't be walking on air pf.add_point( layer.gscore[parent_index] + 10, layer.score[parent_index] + 10 + 2 * rl_dist( below, t ), cur, below ); } // Close p, because we won't be walking on it layer.state[index] = ASL_CLOSED; continue; } } else if( trapavoid ) { // Otherwise it's walkable newg += 500; } } } } // If not visited, add as open // If visited, add it only if we can do so with better score if( layer.state[index] == ASL_NONE || newg < layer.gscore[index] ) { pf.add_point( newg, newg + 2 * rl_dist( p, t ), cur, p ); } } if( !has_zlevels() || !( cur_special & PF_UPDOWN ) || !settings.allow_climb_stairs ) { // The part below is only for z-level pathing continue; } const maptile &parent_tile = maptile_at_internal( cur ); const auto &parent_terrain = parent_tile.get_ter_t(); if( settings.allow_climb_stairs && cur.z > minz && parent_terrain.has_flag( TFLAG_GOES_DOWN ) ) { tripoint dest( cur.x, cur.y, cur.z - 1 ); dest = vertical_move_destination<TFLAG_GOES_UP>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } if( settings.allow_climb_stairs && cur.z < maxz && parent_terrain.has_flag( TFLAG_GOES_UP ) ) { tripoint dest( cur.x, cur.y, cur.z + 1 ); dest = vertical_move_destination<TFLAG_GOES_DOWN>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } if( cur.z < maxz && parent_terrain.has_flag( TFLAG_RAMP ) && valid_move( cur, tripoint( cur.x, cur.y, cur.z + 1 ), false, true ) ) { auto &layer = pf.get_layer( cur.z + 1 ); for( size_t it = 0; it < 8; it++ ) { const tripoint above( cur.x + x_offset[it], cur.y + y_offset[it], cur.z + 1 ); pf.add_point( layer.gscore[parent_index] + 4, layer.score[parent_index] + 4 + 2 * rl_dist( above, t ), cur, above ); } } } while( !done && !pf.empty() ); if( done ) { ret.reserve( rl_dist( f, t ) * 2 ); tripoint cur = t; // Just to limit max distance, in case something weird happens for( int fdist = max_length; fdist != 0; fdist-- ) { const int cur_index = flat_index( cur.x, cur.y ); const auto &layer = pf.get_layer( cur.z ); const tripoint &par = layer.parent[cur_index]; if( cur == f ) { break; } ret.push_back( cur ); // Jumps are acceptable on 1 z-level changes // This is because stairs teleport the player too if( rl_dist( cur, par ) > 1 && abs( cur.z - par.z ) != 1 ) { debugmsg( "Jump in our route! %d:%d:%d->%d:%d:%d", cur.x, cur.y, cur.z, par.x, par.y, par.z ); return ret; } cur = par; } std::reverse( ret.begin(), ret.end() ); } return ret; }
int compute_move( int side_to_move, int update_all, int my_time, int my_incr, int timed_depth, int book, int mid, int exact, int wld, int search_forced, EvaluationType *eval_info ) { FILE *log_file; EvaluationType book_eval_info, mid_eval_info, end_eval_info; char *eval_str; double midgame_diff; enum { INTERRUPTED_MOVE, BOOK_MOVE, MIDGAME_MOVE, ENDGAME_MOVE } move_type; int i; int curr_move, midgame_move; int empties; int midgame_depth, interrupted_depth, max_depth; int book_move_found; int endgame_reached; int offset; log_file = NULL; if ( use_log_file ) log_file = fopen( log_file_path, "a" ); if ( log_file ) display_board( log_file, board, side_to_move, FALSE, FALSE, FALSE ); /* Initialize various components of the move system */ piece_count[BLACKSQ][disks_played] = disc_count( BLACKSQ ); piece_count[WHITESQ][disks_played] = disc_count( WHITESQ ); init_moves(); generate_all( side_to_move ); determine_hash_values( side_to_move, board ); calculate_perturbation(); if ( log_file ) { fprintf( log_file, "%d %s: ", move_count[disks_played], MOVE_GEN_TEXT ); for ( i = 0; i < move_count[disks_played]; i++ ) fprintf( log_file, "%c%c ", TO_SQUARE( move_list[disks_played][i] ) ); fputs( "\n", log_file ); } if ( update_all ) { reset_counter( &evaluations ); reset_counter( &nodes ); } for ( i = 0; i < 100; i++ ) evals[disks_played][i] = 0; max_depth_reached = 1; empties = 60 - disks_played; reset_buffer_display(); determine_move_time( my_time, my_incr, disks_played + 4 ); if ( !get_ponder_move() ) clear_ponder_times(); remove_coeffs( disks_played ); /* No feasible moves? */ if ( move_count[disks_played] == 0 ) { *eval_info = create_eval_info( PASS_EVAL, UNSOLVED_POSITION, 0.0, 0.0, 0, FALSE ); set_current_eval( *eval_info ); if ( echo ) { eval_str = produce_eval_text( *eval_info, FALSE ); send_status( "--> " ); send_status( "%-8s ", eval_str ); display_status( stdout, FALSE ); free( eval_str ); } if ( log_file ) { fprintf( log_file, "%s: %s\n", BEST_MOVE_TEXT, PASS_TEXT ); fclose( log_file ); } last_time_used = 0.0; clear_pv(); return PASS; } /* If there is only one move available: Don't waste any time, unless told so or very close to the end, searching the position. */ if ( (empties > DISABLE_FORCED_MOVES) && (move_count[disks_played] == 1) && !search_forced ) { /* Forced move */ *eval_info = create_eval_info( FORCED_EVAL, UNSOLVED_POSITION, 0.0, 0.0, 0, FALSE ); set_current_eval( *eval_info ); if ( echo ) { eval_str = produce_eval_text( *eval_info, FALSE ); send_status( "--> " ); send_status( "%-8s ", eval_str ); free( eval_str ); send_status( "%c%c ", TO_SQUARE( move_list[disks_played][0] ) ); display_status( stdout, FALSE ); } if ( log_file ) { fprintf( log_file, "%s: %c%c (%s)\n", BEST_MOVE_TEXT, TO_SQUARE(move_list[disks_played][0]), FORCED_TEXT ); fclose( log_file ); } last_time_used = 0.0; return move_list[disks_played][0]; } /* Mark the search as interrupted until a successful search has been performed. */ move_type = INTERRUPTED_MOVE; interrupted_depth = 0; curr_move = move_list[disks_played][0]; /* Check the opening book for midgame moves */ book_move_found = FALSE; midgame_move = PASS; if ( forced_opening != NULL ) { /* Check if the position fits the currently forced opening */ curr_move = check_forced_opening( side_to_move, forced_opening ); if ( curr_move != PASS ) { book_eval_info = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, TRUE ); midgame_move = curr_move; book_move_found = TRUE; move_type = BOOK_MOVE; if ( echo ) { send_status( "--> Forced opening move " ); if ( get_ponder_move() ) send_status( "{%c%c} ", TO_SQUARE( get_ponder_move() ) ); send_status( "%c%c", TO_SQUARE( curr_move ) ); display_status( stdout, FALSE ); } clear_pv(); pv_depth[0] = 1; pv[0][0] = curr_move; } } if ( !book_move_found && play_thor_match_openings ) { /* Optionally use the Thor database as opening book. */ int threshold = 2; database_search( board, side_to_move ); if ( get_match_count() >= threshold ) { int game_index = (my_random() >> 8) % get_match_count(); curr_move = get_thor_game_move( game_index, disks_played ); if ( valid_move( curr_move, side_to_move ) ) { book_eval_info = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, TRUE ); midgame_move = curr_move; book_move_found = TRUE; move_type = BOOK_MOVE; if ( echo ) { send_status( "--> %s ", THOR_TEXT ); if ( get_ponder_move() ) send_status( "{%c%c} ", TO_SQUARE( get_ponder_move() ) ); send_status( "%c%c", TO_SQUARE( curr_move ) ); display_status( stdout, FALSE ); } clear_pv(); pv_depth[0] = 1; pv[0][0] = curr_move; } else fatal_error( "Thor book move %d is invalid!", curr_move ); }
JNIEXPORT void JNIFn(zebra, ZebraEngine, zePlay)(JNIEnv *env, jobject thiz, jint providedMoveCount, jbyteArray providedMoves) { EvaluationType eval_info; const char *black_name; const char *white_name; const char *opening_name; const char *op; double move_start, move_stop; int i; int side_to_move; int curr_move; int timed_search; int black_hash1, black_hash2, white_hash1, white_hash2; ui_event_t evt; int provided_move_count; int provided_move_index; int provided_move[65]; int silent = FALSE; int use_book = s_use_book; DROIDZEBRA_JNI_SETUP; force_exit = 0; if (skill[BLACKSQ] < 0 || skill[WHITESQ] < 0) { fatal_error("Set Player Info first"); } /* copy provided moves */ provided_move_index = 0; provided_move_count = 0; if (providedMoveCount > 0 && providedMoves) { jbyte *providedMovesJNI; provided_move_count = providedMoveCount; i = (*env)->GetArrayLength(env, providedMoves); if (provided_move_count > i) fatal_error("Provided move count is greater than array size %d>%d", provided_move_count, i); if (provided_move_count > 64) fatal_error("Provided move count is greater that 64: %d", provided_move_count); providedMovesJNI = (*env)->GetByteArrayElements(env, providedMoves, 0); if (!providedMovesJNI) fatal_error("failed to get provide moves (jni)"); for (i = 0; i < provided_move_count; i++) { provided_move[i] = providedMovesJNI[i]; } (*env)->ReleaseByteArrayElements(env, providedMoves, providedMovesJNI, 0); } /* Set up the position and the search engine */ game_init(NULL, &side_to_move); setup_hash(TRUE); clear_stored_game(); set_slack(floor(s_slack * 128.0)); set_perturbation(floor(s_perturbation * 128.0)); toggle_human_openings(s_human_opening); set_forced_opening(s_forced_opening_seq); opening_name = NULL; reset_book_search(); set_deviation_value(0, 0, 0.0); if (skill[BLACKSQ] == 0) black_name = "Player"; else black_name = "Zebra"; if (skill[WHITESQ] == 0) white_name = "Player"; else white_name = "Zebra"; set_names(black_name, white_name); set_move_list(black_moves, white_moves, score_sheet_row); set_evals(0.0, 0.0); for (i = 0; i < 60; i++) { black_moves[i] = PASS; white_moves[i] = PASS; } black_hash1 = my_random(); black_hash2 = my_random(); white_hash1 = my_random(); white_hash2 = my_random(); droidzebra_msg_game_start(); AGAIN: curr_move = PASS; while (game_in_progress() && !force_exit) { force_return = 0; silent = (provided_move_index < provided_move_count); droidzebra_enable_messaging(!silent); droidzebra_msg_move_start(side_to_move); remove_coeffs(disks_played); clear_evaluated(); if (SEPARATE_TABLES) { /* Computer players won't share hash tables */ if (side_to_move == BLACKSQ) { hash1 ^= black_hash1; hash2 ^= black_hash2; } else { hash1 ^= white_hash1; hash2 ^= white_hash2; } } generate_all(side_to_move); if (side_to_move == BLACKSQ) score_sheet_row++; // echo droidzebra_msg_candidate_moves(); set_move_list(black_moves, white_moves, score_sheet_row); set_times(floor(player_time[BLACKSQ]), floor(player_time[WHITESQ])); op = find_opening_name(); if (op != NULL && (!opening_name || strcmp(op, opening_name))) { opening_name = op; } droidzebra_msg_opening_name(opening_name); droidzebra_msg_last_move(disks_played > 0 ? get_stored_move(disks_played - 1) : PASS); display_board(stdout, board, side_to_move, TRUE, TRUE, TRUE); // echo if (move_count[disks_played] != 0) { move_start = get_real_timer(); clear_panic_abort(); if (provided_move_index >= provided_move_count) { if (skill[side_to_move] == 0) { curr_move = -1; if (auto_make_forced_moves && move_count[disks_played] == 1) { curr_move = move_list[disks_played][0]; } else { // compute evaluations if (s_practice_mode) { _droidzebra_compute_evals(side_to_move); if (force_exit) break; if (force_return) force_return = 0; // interrupted by user input } // wait for user event droidzebra_msg_get_user_input(side_to_move, &evt); if (evt.type == UI_EVENT_EXIT) { force_exit = 1; break; } else if (evt.type == UI_EVENT_MOVE) { curr_move = evt.evt_move.move; _droidzebra_undo_stack_clear(); // once player makes the move undo info is stale } else if (evt.type == UI_EVENT_UNDO) { _droidzebra_undo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; continue; } else if (evt.type == UI_EVENT_REDO) { _droidzebra_redo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; continue; } else if (evt.type == UI_EVENT_SETTINGS_CHANGE) { _droidzebra_on_settings_change(); // repeat move on settings change if (side_to_move == BLACKSQ) score_sheet_row--; // adjust for increment at the beginning of the game loop continue; } else { fatal_error("Unsupported UI event: %d", evt.type); } } assert(curr_move >= 0); } else { start_move(player_time[side_to_move], player_increment[side_to_move], disks_played + 4); determine_move_time(player_time[side_to_move], player_increment[side_to_move], disks_played + 4); timed_search = (skill[side_to_move] >= 60); toggle_experimental(FALSE); curr_move = compute_move(side_to_move, TRUE, player_time[side_to_move], player_increment[side_to_move], timed_search, use_book, skill[side_to_move], exact_skill[side_to_move], wld_skill[side_to_move], FALSE, &eval_info); if (side_to_move == BLACKSQ) set_evals(produce_compact_eval(eval_info), 0.0); else set_evals(0.0, produce_compact_eval(eval_info)); } } else { curr_move = provided_move[provided_move_index]; if (!valid_move(curr_move, side_to_move)) fatal_error("Invalid move %c%c in move sequence", TO_SQUARE(curr_move)); } move_stop = get_real_timer(); if (player_time[side_to_move] != INFINIT_TIME) player_time[side_to_move] -= (move_stop - move_start); store_move(disks_played, curr_move); (void) make_move(side_to_move, curr_move, TRUE); if (side_to_move == BLACKSQ) black_moves[score_sheet_row] = curr_move; else { white_moves[score_sheet_row] = curr_move; } } else { // this is where we pass if (side_to_move == BLACKSQ) black_moves[score_sheet_row] = PASS; else white_moves[score_sheet_row] = PASS; if (!auto_make_forced_moves && skill[side_to_move] == 0) { droidzebra_msg_pass(); } } droidzebra_msg_move_end(side_to_move); side_to_move = OPP(side_to_move); provided_move_index++; } droidzebra_enable_messaging(TRUE); if (side_to_move == BLACKSQ) score_sheet_row++; set_move_list(black_moves, white_moves, score_sheet_row); set_times(floor(player_time[BLACKSQ]), floor(player_time[WHITESQ])); droidzebra_msg_opening_name(opening_name); display_board(stdout, board, side_to_move, TRUE, TRUE, TRUE); /* double node_val, eval_val; adjust_counter( &total_nodes ); node_val = counter_value( &total_nodes ); adjust_counter( &total_evaluations ); eval_val = counter_value( &total_evaluations ); printf( "\nBlack: %d White: %d\n", disc_count( BLACKSQ ), disc_count( WHITESQ ) ); printf( "Nodes searched: %-10.0f\n", node_val ); printf( "Positions evaluated: %-10.0f\n", eval_val ); printf( "Total time: %.1f s\n", total_time ); */ if (!force_exit) droidzebra_msg_game_over(); // loop here until we are told to exit so the user has a chance to undo while (!force_exit) { droidzebra_msg_get_user_input(side_to_move, &evt); if (evt.type == UI_EVENT_EXIT) { force_exit = 1; break; } else if (evt.type == UI_EVENT_UNDO) { _droidzebra_undo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; goto AGAIN; } else if (evt.type == UI_EVENT_SETTINGS_CHANGE) { _droidzebra_on_settings_change(); } } DROIDZEBRA_JNI_CLEAN; }
int main() { FILE* bFile; char *board = malloc(sizeof(char) * 128); int cars[26][3]; char car = '\0'; // car to move char dir = '\0'; // direction of move int amount = -1; // number of spaces to move int temp = 0; print_heading(3, "The Traffic Game"); bFile = fopen("board.txt", "r"); if(bFile == NULL) { printf("Could not open file board.txt.\n"); return -1; } scan_board(bFile, board, cars); fclose(bFile); printf("Welcome to the traffic game!\n\n"); printf("Move the vehicles so that the Red car (RR) can\n"); printf("exit the board to the right. Each move should be\n"); printf("of the form: CDN where C is the vehicle to\n"); printf("be moved, D ids the direction (u for up, d for down,\n"); printf("l for left or r for right), and N is the number of\n"); printf("squares to move it. For example GR2 means move the\n"); printf("G vehicle to the right 2 squares. Lower-case input\n"); printf("such as gr2 is also accepted. Entre x to exit the\n"); printf("program.\n"); while(1) { print_board(board); do { get_input(&car, &dir, &amount); // printf("\n%c%c%d\n", car, dir, amount); //for testing if(car == 'X') { printf("Thanks for playing! Exiting...\n"); free(board); return 0; } temp = valid_move(car, dir, amount, cars, board); if(! temp) { printf("Move not valid. try again.\n"); } }while(! temp); if(make_move(car, dir, amount, cars, board)) { print_board(board); printf("\nCongradulations!! You Win!!!\n\n"); printf("Thanks for playing! Exiting...\n"); free(board); return 0; } } }