带有DFS的钉单人纸牌解决方案会导致分段错误

时间:2020-10-30 19:16:44

标签: c algorithm segmentation-fault depth-first-search

算法

Algorithm Pseducode:

钉接龙(Pegsol)的每个可能配置都是由以下各项组成的元组:m×m网格 板, 光标的位置以及是否已选择光标下方的钉。这个元组是 叫 一个状态。隐式定义了Pegsol图G = 。顶点集V定义为 的 可能的配置(状态),连接两个顶点的边E由 合法跳跃 动作(右,左,上,下)。 您的任务是找到通向最佳解决方案的路径,即通向顶点(状态)的路径 的 剩余钉子最少。路径是一系列动作。您将要使用 深度优先 搜索以找到最佳解决方案,最大预算为扩展/探索节点 (的节点 您已经生成了它的子级)。 调用AI解算器(算法1)时,它应该探索所有可能的路径( 跳 行动)遵循深度优先搜索(DFS)策略,直到消耗预算或 路径 找到解决游戏的方法。请注意,搜索中不包括重复状态。如果一个 状态为 已经生成的,我们将不再将其再次包含在堆栈中(第21行)。该算法应 返回 找到最好的解决方案,导致剩余钉子数量最少的路径。这条路会 然后 由游戏引擎执行。 您可能有多种解决方案。您的算法应考虑 通过按以下顺序扫描电路板可能采取的措施:移动坐标x = 0,.....,m首先,并且 然后y = 0,…,m寻找可以跳跃的钉子,然后选择左跳跃动作, 对,向上或向下 确保妥善管理内存。完成算法运行后, 释放所有 内存中的节点,否则您将发生内存泄漏。您会注意到 算法 扩展数百万个节点后,内存可能很快就会耗尽。 当您套用动作时,您必须建立一个新节点

  1. 指向父级,
  2. 使用所选操作更新状态,
  3. 更新节点的深度。
  4. 更新用于创建节点的操作

我正在使用以下代码实现此算法:

#include <time.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>

#include "ai.h"
#include "utils.h"
#include "hashtable.h"
#include "stack.h"


void copy_state(state_t* dst, state_t* src){
    
    //Copy field
    memcpy( dst->field, src->field, SIZE*SIZE*sizeof(int8_t) );

    dst->cursor = src->cursor;
    dst->selected = src->selected;
}

/**
 * Saves the path up to the node as the best solution found so far
*/
void save_solution( node_t* solution_node ){
    node_t* n = solution_node;
    while( n->parent != NULL ){
        copy_state( &(solution[n->depth]), &(n->state) );
        solution_moves[n->depth-1] = n->move;

        n = n->parent;
    }
    solution_size = solution_node->depth;
}


node_t* create_init_node( state_t* init_state ){
    node_t * new_n = (node_t *) malloc(sizeof(node_t));
    new_n->parent = NULL;   
    new_n->depth = 0;
    copy_state(&(new_n->state), init_state);
    return new_n;
}

/**
 * Apply an action to node n and return a new node resulting from executing the action
*/
node_t* applyAction(node_t* n, position_s* selected_peg, move_t action ){

    node_t* new_node = NULL;
    
    //printf("PASS#");
    //FILL IN MISSING CODE
    
    new_node = create_init_node( &(n->state));
    
    new_node->parent = n;
    
    n->depth = n->depth + 1;

    execute_move_t( &(new_node->state), &(new_node->state.cursor), action );
    
    return new_node;

}


// From here my implementation starts
/**
 * Find a solution path as per algorithm description in the handout
 */

void find_solution( state_t* init_state  ){

    HashTable table;
    int8_t x,y;
    int remainingPegs;

    // Choose initial capacity of PRIME NUMBER 
    // Specify the size of the keys and values you want to store once 
    ht_setup( &table, sizeof(int8_t) * SIZE * SIZE, sizeof(int8_t) * SIZE * SIZE, 16769023);

    // Initialize Stack
    initialize_stack();

    //Add the initial node
    node_t* n = create_init_node( init_state );
    node_t* new_node = NULL;
    
    //FILL IN THE GRAPH ALGORITHM
    stack_push(n);
    remainingPegs = num_pegs(&(n->state));
    while(!is_stack_empty())
    {
        
        n = stack_top();
        
        expanded_nodes = expanded_nodes + 1;
        if(num_pegs(&(n->state)) < remainingPegs )
        {
            save_solution(n);
            remainingPegs = num_pegs(&(n->state));
            
        }
        
        for (x=0;x<SIZE;x++) {
            for (y=0;y<SIZE;y++) {
                 enum moves_e a = left;
                    
                if(can_apply(&(n->state),&(n->state.cursor),a)){
                    printf("World cup");
                    node_t* new_node = applyAction(n,&(n->state.cursor),a);
                    generated_nodes = generated_nodes + 1;
                    //printf("%d",generated_nodes);
                }
                a = right;
                if(can_apply(&(n->state),&(n->state.cursor),a)){
                    printf("World cup");
                    node_t* new_node = applyAction(n,&(n->state.cursor),a);
                    generated_nodes = generated_nodes + 1;
                    //printf("%d",generated_nodes);
                }
                a = up;
                if(can_apply(&(n->state),&(n->state.cursor),a)){
                    printf("World cup");
                    node_t* new_node = applyAction( n,&(n->state.cursor),a);
                    generated_nodes = generated_nodes + 1;
                    //printf("%d",generated_nodes);
                }
                a = down;
                if(can_apply(&(n->state),&(n->state.cursor),a)){
                    node_t* new_node = applyAction( n,&(n->state.cursor),a);
                    generated_nodes = generated_nodes + 1;
                    //printf("%d",generated_nodes);
                }
                //Comment line number 134 here where segmentation fault occured
                if (won(&(new_node->state)))
                {
                    //save_solution(new_node);
                    //remainingPegs = num_pegs(&(new_node->state));
                    //free_stack();
                    break;
                }
                
                if(new_node->depth == 0)
                {
                    stack_push(new_node);
                }
                
                if(expanded_nodes >= budget)
                    break;
                
            }
        }
        
            
    }
}

下面提到了util.c中存在的另一个辅助方法:

#include "utils.h"
#include "layouts.h"

void execute_move_t(state_t* state, position_s* selected_peg, move_t jump) {
    int8_t x = selected_peg->x;
    int8_t y = selected_peg->y;

    
    switch (jump) {
    case up:          //Jump up
        state->field[x][y-2] = 'o';
        state->field[x][y-1] = '.';
        state->field[x][y-0] = '.';
        state->cursor.y = y-2;
        break;

    case down:         //Jump down
        state->field[x][y+0] = '.';
        state->field[x][y+1] = '.';
        state->field[x][y+2] = 'o';
        state->cursor.y = y+2;
        break;

    case left:         //Jump left
        state->field[x-2][y] = 'o';
        state->field[x-1][y] = '.';
        state->field[x-0][y] = '.';
        state->cursor.x = x-2;
        break;

    case right:          //Jump right
        state->field[x+0][y] = '.';
        state->field[x+1][y] = '.';
        state->field[x+2][y] = 'o';
        state->cursor.x = x+2;
        break;

    }
    
}

bool can_apply(state_t *board, position_s* selected_peg, move_t jump){
    
    
    //printf("%d",jump);
    // Can select a Peg
    
    if ( board->field[ selected_peg->x ][ selected_peg->y ] !='o')  return false;
    
    //Determine if move is legal
    switch (jump) {
        case up:    
            //printf("Up");
            if(  selected_peg->y < 2) return false;
            if( board->field[ selected_peg->x ][ selected_peg->y - 1 ] !='o')  return false;
            if( board->field[ selected_peg->x ][ selected_peg->y - 2 ] !='.')  return false;
            printf("Up");
            break;
            
        case down:    
            //printf("Down");
            if( selected_peg->y > SIZE - 3 ) return false;
            if( board->field[ selected_peg->x ][ selected_peg->y + 1 ] !='o')  return false;
            if( board->field[ selected_peg->x ][ selected_peg->y + 2 ] !='.')  return false;
            printf("Down");
            break;

        case left:    
            //printf("Left");
            if( selected_peg->x < 2) return false;
            if( board->field[ selected_peg->x - 1 ][ selected_peg->y ] !='o')  return false;
            if( board->field[ selected_peg->x - 2 ][ selected_peg->y ] !='.')  return false;
            break;

        case right:   
            //printf("Right");
            if( selected_peg->x > SIZE - 3) return false;
            if( board->field[ selected_peg->x + 1 ][ selected_peg->y ] !='o')  return false;
            if( board->field[ selected_peg->x + 2 ][ selected_peg->y ] !='.')  return false;
            printf("Right");
            break;
    }
    // Can Jump

    
    return true;

}


bool won(state_t *board) {
    int8_t x,y;
    int8_t count=0;

    for (x=0;x<SIZE;x++) {
        for (y=0;y<SIZE;y++) {
            if (board->field[x][y]=='o') {
                count++;
             
            }
            // If more than one peg is left, you haven't won yet
            if( count > 1) return false;
        }
    }
    //If only one is left
    return count == 1;

}

int num_pegs( state_t *board ){
    int count = 0;
    for (int y=0;y<SIZE;y++) {
        for (int x=0;x<SIZE;x++) {
            count+=board->field[x][y]=='o';
        }
    }
    return count;
}


void rotateBoard(state_t *board) {
    int8_t i,j,n=SIZE;
    int8_t tmp;
    for (i=0; i<n/2; i++){
        for (j=i; j<n-i-1; j++){
            tmp = board->field[i][j];
            board->field[i][j] = board->field[j][n-i-1];
            board->field[j][n-i-1] = board->field[n-i-1][n-j-1];
            board->field[n-i-1][n-j-1] = board->field[n-j-1][i];
            board->field[n-j-1][i] = tmp;
        }
    }
    i = board->cursor.x;
    j = board->cursor.y;

    board->cursor.x = -(j-n/2)+n/2;
    board->cursor.y = (i-n/2)+n/2;
}

bool select_peg(state_t *board) {
    int8_t x,y,(*field)[SIZE];
    bool selected;

    x = board->cursor.x;
    y = board->cursor.y;
    field = board->field;
    selected = board->selected;

    if (field[x][y]!='o') return false;
    board->selected = !selected;
    return true;
}

bool moveUp(state_t *board) {
    int8_t x,y,(*field)[SIZE];
    bool selected;

    x = board->cursor.x;
    y = board->cursor.y;
    field = board->field;
    selected = board->selected;

    if (selected) {
        if (y<2) return false;
        if (field[x][y-2]!='.') return false;
        if (field[x][y-1]!='o') return false;
        if (field[x][y-0]!='o') return false;
        field[x][y-2] = 'o';
        field[x][y-1] = '.';
        field[x][y-0] = '.';
        board->cursor.y = y-2;
        board->selected = false;
    } else {
        if (y<1) return false;
        if (field[x][y-1]==' ') return false;
        board->cursor.y = y-1;
    }
    return true;
}

bool moveLeft(state_t *board) {
    bool success;
    rotateBoard(board);
    success = moveUp(board);
    rotateBoard(board);
    rotateBoard(board);
    rotateBoard(board);
    return success;
}

bool moveDown(state_t *board) {
    bool success;
    rotateBoard(board);
    rotateBoard(board);
    success = moveUp(board);
    rotateBoard(board);
    rotateBoard(board);
    return success;
}

bool moveRight(state_t *board) {
    bool success;
    rotateBoard(board);
    rotateBoard(board);
    rotateBoard(board);
    success = moveUp(board);
    rotateBoard(board);
    return success;
}


int8_t validMovesUp(state_t *board) {
    int8_t x,y;
    int8_t count=0;
    for (x=0;x<SIZE;x++) {
        for (y=SIZE-1;y>1;y--) {
            if (board->field[x][y]=='o') {
                if (board->field[x][y-1]=='o') {
                    if (board->field[x][y-2]=='.') {
                        count++;
                    }
                }
            }
        }
    }
    return count;
}

bool gameEndedForHuman(state_t *board) {
    int8_t i,count=0;
    for (i=0;i<4;i++) {
        count+=validMovesUp(board);
        rotateBoard(board);
    }
    return count==0;
}

void initialize(state_t *board, int8_t layout) {
    int8_t x,y;

    if( layout > NUM_LAYOUTS - 1) layout = 0;
    
    board->cursor.x = 4;
    board->cursor.y = 4;
    board->selected = false;

    memset(board->field,0,sizeof(board->field));
    for (y=0;y<SIZE;y++) {
        for (x=0;x<SIZE;x++) {
            board->field[x][y]=configuration[layout][y][x*2];
        }
    }
}


void drawBoard(state_t *board) {
    int8_t x,y,count=0;

    // move cursor to home position
    printf("\033[H");

    for (y=0;y<SIZE;y++) {
        for (x=0;x<SIZE;x++) {
            count+=board->field[x][y]=='o';
        }
    }
    printf("peg-solitaire.c %7d pegs\n",count);
    printf("                             \n");

    for (y=0;y<SIZE;y++) {
        for (x=0;x<14-SIZE;x++) {
            printf(" ");
        }
        for (x=0;x<SIZE;x++) {
            if (board->cursor.x == x && board->cursor.y == y) {
                if (board->selected) {
                    printf("\b|\033[7m%c\033[27m|",board->field[x][y]);
                } else {
                    printf("\033[7m%c\033[27m ",board->field[x][y]);
                }
            } else {
                printf("%c ",board->field[x][y]);
            }
        }
        for (x=0;x<14-SIZE;x++) {
            printf(" ");
        }
        printf("\n");
    }
    printf("                            \n");
    printf("   arrow keys, q or enter   \n");
    printf("\033[A"); // one line up
}

char* action_cstr(move_t move){

    switch (move) {
        case up:  
            return "Up";
        break;

        case down: 
            return "Down";
        break;

        case left:    
            return "Left";
        break;

        case right:  
            return "Right";
        break;

    }
    return " ";
}

void print_solution(){

    for(int i=0; i< solution_size; i++)
        printf("    %d - %s                              \n", i+1, action_cstr(solution_moves[i]));
        
}

void play_solution(){
    for(int i=0; i <= solution_size; i++){
        drawBoard(&(solution[i]));
        usleep(500000);
        
        if( i < solution_size){
            //Reverse action
            switch ( solution_moves[i] ) {
                case up:          
                    solution[i].cursor.y = solution[i+1].cursor.y+2;
                    solution[i].cursor.x = solution[i+1].cursor.x;
                    break;
                case down:          
                    solution[i].cursor.y = solution[i+1].cursor.y-2;
                    solution[i].cursor.x = solution[i+1].cursor.x;
                    break;
                case left:         
                    solution[i].cursor.x = solution[i+1].cursor.x+2;
                    solution[i].cursor.y = solution[i+1].cursor.y;
                    break;
                case right:          
                    solution[i].cursor.x = solution[i+1].cursor.x-2;
                    solution[i].cursor.y = solution[i+1].cursor.y;
                    break;
                }
            solution[i].selected = true;
            drawBoard(&(solution[i]));
            usleep(500000);
        }
    }
}

这会导致分段错误。请任何人帮助我解决此问题。

0 个答案:

没有答案