Commits

Shlomi Fish  committed 12a865f

Merge from trunk

git-svn-id: file:///home/shlomif/Backup/svn-dumps/google-code/svnsync-repos/fc-solve/branches/integrate-patsolve-atomic-moves-logic@2646 e7e8a897-7ba4-4ee7-b36f-f4c66519b19a

  • Participants
  • Parent commits c92c202
  • Branches integrate-patsolve-atomic-moves-logic, integrate-patsolve-atomic-moves-logic@3680

Comments (0)

Files changed (4)

File fc-solve/benchmarks/log.txt

 
 95.6929581165314s
 
+========================================================================
+
+r2640 ;
+./Tatzer -l p4b ; after strip ; ARGS="--worker-step 16 -l by" 
+PROG="./freecell-solver-fork-solve"
+2.6.33-desktop-0.rc8.1mnb
+Virtual Console
+
+Multiproc:
+
+94.044084072113s
+
+{{{{{{{{{{{{
+Started at 1266685041.258715
+Reached Board No. 4000 at 1266685052.702632 (total_num_iters=2232774)
+Reached Board No. 8000 at 1266685064.422297 (total_num_iters=4507587)
+Reached Board No. 12000 at 1266685075.570034 (total_num_iters=6693689)
+Reached Board No. 16000 at 1266685088.051940 (total_num_iters=9077159)
+Reached Board No. 20000 at 1266685099.088107 (total_num_iters=11274791)
+Reached Board No. 24000 at 1266685110.548054 (total_num_iters=13519808)
+Reached Board No. 28000 at 1266685122.337970 (total_num_iters=15802397)
+Unsolved Board No. 11982 at 1266685076.187721
+Finished at 1266685135.302799 (total_num_iters=18253266)
+}}}}}}}}}}}}
+

File fc-solve/source/CMakeLists.txt

     "\\\\.o$"
     "~$"
     "/board_gen/(pi-make-microsoft-freecell-board|make-microsoft-freecell-board|make-gnome-freecell-board|make-aisleriot-freecell-board)$"
-    "/(fc-solve|freecell-solver-range-parallel-solve|freecell-solver-fc-pro-range-solve|freecell-solver-multi-thread-solve)$"
+    "/(fc-solve|freecell-solver-range-parallel-solve|freecell-solver-fc-pro-range-solve|freecell-solver-multi-thread-solve|freecell-solver-fork-solve)$"
     "/lib(fcs|freecell-solver)\\\\.(a|la)$"
     "\\\\.so(\\\\.[0-9]+)*$"
     "/\\\\.svn/"
     )
 
 SET(FREECELL_SOLVER_EXECUTABLES )
-MACRO(FCS_ADD_EXEC target)
+MACRO(FCS_ADD_EXEC_NO_INSTALL target)
     SET(modules ${ARGV})
     LIST(REMOVE_AT modules 0)
     ADD_EXECUTABLE(${target} ${modules})
     LIST(APPEND FREECELL_SOLVER_EXECUTABLES ${target})
     TARGET_LINK_LIBRARIES (${target} ${MY_TARGET_LINK_LIBS})
+ENDMACRO(FCS_ADD_EXEC_NO_INSTALL target)
+
+MACRO(FCS_ADD_EXEC target)
+    FCS_ADD_EXEC_NO_INSTALL(${ARGV})
     INSTALL (TARGETS ${target} DESTINATION "bin")
-ENDMACRO(FCS_ADD_EXEC target)
+ENDMACRO(FCS_ADD_EXEC)
+
 
 FCS_ADD_EXEC(fc-solve main.c)
 FCS_ADD_EXEC(freecell-solver-range-parallel-solve test_multi_parallel.c)
     TARGET_LINK_LIBRARIES(freecell-solver-multi-thread-solve "pthread")
 ENDIF (CMAKE_USE_PTHREADS_INIT)
 
+IF (UNIX)
+    FCS_ADD_EXEC_NO_INSTALL(
+        freecell-solver-fork-solve "forking_range_solver.c"
+    )
+ENDIF (UNIX)
+
 IF (MY_LINK_FLAGS)
     SET_TARGET_PROPERTIES(
         ${FREECELL_SOLVER_LIBS} 

File fc-solve/source/forking_range_solver.c

+/* Copyright (c) 2000 Shlomi Fish
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ *  forking_range_solver.c - a range solver that solves different boards in 
+ *  several UNIX processes.
+ *
+ *  See also:
+ *      - fc_pro_range_solver.c
+ *      - test_multi_parallel.c
+ *      - threaded_range_solver.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#else
+#include <sys/types.h>
+#include <sys/timeb.h>
+#endif
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "fcs_user.h"
+#include "fcs_cl.h"
+#include "unused.h"
+#include "inline.h"
+#include "range_solvers_gen_ms_boards.h"
+
+struct fc_solve_display_information_context_struct
+{
+    int debug_iter_state_output;
+    int freecells_num;
+    int stacks_num;
+    int decks_num;
+    int parseable_output;
+    int canonized_order_output;
+    int display_10_as_t;
+    int display_parent_iter_num;
+    int debug_iter_output_on;
+    int display_moves;
+    int display_states;
+    int standard_notation;
+};
+
+typedef struct fc_solve_display_information_context_struct fc_solve_display_information_context_t;
+
+static void my_iter_handler(
+    void * user_instance,
+    int iter_num,
+    int depth,
+    void * ptr_state,
+    int parent_iter_num,
+    void * lp_context
+    )
+{
+    fc_solve_display_information_context_t * context;
+    context = (fc_solve_display_information_context_t*)lp_context;
+
+    fprintf(stdout, "Iteration: %i\n", iter_num);
+    fprintf(stdout, "Depth: %i\n", depth);
+    if (context->display_parent_iter_num)
+    {
+        fprintf(stdout, "Parent Iteration: %i\n", parent_iter_num);
+    }
+    fprintf(stdout, "\n");
+
+
+    if (context->debug_iter_state_output)
+    {
+        char * state_string =
+            freecell_solver_user_iter_state_as_string(
+                user_instance,
+                ptr_state,
+                context->parseable_output,
+                context->canonized_order_output,
+                context->display_10_as_t
+                );
+        printf("%s\n---------------\n\n\n", state_string);
+        free((void*)state_string);
+    }
+
+}
+
+struct pack_item_struct
+{
+    fc_solve_display_information_context_t display_context;
+    void * instance;
+};
+
+typedef struct pack_item_struct pack_item_t;
+
+
+static int cmd_line_callback(
+    void * instance,
+    int argc GCC_UNUSED,
+    char * argv[],
+    int arg,
+    int * num_to_skip,
+    int * ret GCC_UNUSED,
+    void * context
+    )
+{
+    pack_item_t * item;
+    fc_solve_display_information_context_t * dc;
+    item = (pack_item_t * )context;
+    dc = &(item->display_context);
+
+    *num_to_skip = 0;
+
+    if ((!strcmp(argv[arg], "-i")) || (!strcmp(argv[arg], "--iter-output")))
+    {
+        freecell_solver_user_set_iter_handler(
+            instance,
+            my_iter_handler,
+            dc
+            );
+        dc->debug_iter_output_on = 1;
+    }
+    else if ((!strcmp(argv[arg], "-s")) || (!strcmp(argv[arg], "--state-output")))
+    {
+        dc->debug_iter_state_output = 1;
+    }
+    else if ((!strcmp(argv[arg], "-p")) || (!strcmp(argv[arg], "--parseable-output")))
+    {
+        dc->parseable_output = 1;
+    }
+    else if ((!strcmp(argv[arg], "-c")) || (!strcmp(argv[arg], "--canonized-order-output")))
+    {
+        dc->canonized_order_output = 1;
+    }
+    else if ((!strcmp(argv[arg], "-t")) || (!strcmp(argv[arg], "--display-10-as-t")))
+    {
+        dc->display_10_as_t = 1;
+    }
+    else if ((!strcmp(argv[arg], "-m")) || (!strcmp(argv[arg], "--display-moves")))
+    {
+        dc->display_moves = 1;
+        dc->display_states = 0;
+    }
+    else if ((!strcmp(argv[arg], "-sn")) || (!strcmp(argv[arg], "--standard-notation")))
+    {
+        dc->standard_notation = 1;
+    }
+    else if ((!strcmp(argv[arg], "-sam")) || (!strcmp(argv[arg], "--display-states-and-moves")))
+    {
+        dc->display_moves = 1;
+        dc->display_states = 1;
+    }
+    else if ((!strcmp(argv[arg], "-pi")) || (!strcmp(argv[arg], "--display-parent-iter")))
+    {
+        dc->display_parent_iter_num = 1;
+    }
+    else
+    {
+        fprintf(stderr, "Unknown option %s!\n", argv[arg]);
+        exit(-1);
+        return 0;
+    }
+    *num_to_skip = 1;
+    return FCS_CMD_LINE_SKIP;
+}
+
+static char * known_parameters[] = {
+    "-i", "--iter-output",
+    "-s", "--state-output",
+    "-p", "--parseable-output",
+    "-t", "--display-10-as-t",
+    "-pi", "--display-parent-iter",
+    NULL
+    };
+
+#define BINARY_OUTPUT_NUM_INTS 16
+
+#define print_int_wrapper(i) { }
+
+static void print_help(void)
+{
+    printf("\n%s",
+"freecell-solver-range-parallel-solve start end print_step\n"
+"   [--binary-output-to filename] [--total-iterations-limit limit]\n"
+"   [fc-solve Arguments...]\n"
+"\n"
+"Solves a sequence of boards from the Microsoft/Freecell Pro Deals\n"
+"\n"
+"start - the first board in the sequence\n"
+"end - the last board in the sequence (inclusive)\n"
+"print_step - at which division to print a status line\n"
+"\n"
+"--total-iterations-limit  limit\n"
+"     Limits each board for up to 'limit' iterations.\n"
+          );
+}
+
+typedef struct {
+    int argc;
+    char * * argv;
+    int arg;
+    int stop_at;
+} context_t;
+
+static int total_iterations_limit_per_board = -1;
+
+#ifndef WIN32
+typedef long long very_long_int_t;
+#else
+typedef __int64 very_long_int_t;
+#endif
+
+static very_long_int_t total_num_iters = 0;
+
+#define READ_FD 0
+#define WRITE_FD 1
+typedef struct
+{
+    int child_to_parent_pipe[2];
+    int parent_to_child_pipe[2];
+} worker_t;
+
+typedef struct
+{
+    int board_num;
+    int quota_end;
+} request_t;
+
+typedef struct
+{
+    int num_iters;
+    int num_finished_boards;
+} response_t;
+
+int worker_func(int idx, worker_t w, void * instance)
+{
+    /* I'm one of the slaves */
+    request_t request;
+    response_t response;
+    int ret;
+    fcs_state_string_t state_string;
+    struct timeval tv;
+    struct timezone tz;
+
+    while(1)
+    {
+        response.num_iters = 0;
+        
+        read(w.parent_to_child_pipe[READ_FD], &request, sizeof(request));
+
+        if (request.board_num == -1)
+        {
+            break;
+        }
+
+        response.num_finished_boards =
+            request.quota_end - request.board_num + 1;
+
+#define board_num (request.board_num)
+#define total_num_iters_temp (response.num_iters)
+        for(;board_num<=request.quota_end;board_num++)
+        {
+            get_board(board_num, state_string);
+
+            freecell_solver_user_limit_iterations(instance, total_iterations_limit_per_board);
+
+            ret =
+                freecell_solver_user_solve_board(
+                    instance,
+                    state_string
+                    );
+
+            if (ret == FCS_STATE_SUSPEND_PROCESS)
+            {
+#ifndef WIN32
+                gettimeofday(&tv,&tz);
+                printf("Intractable Board No. %i at %li.%.6li\n",
+                    board_num,
+                    tv.tv_sec,
+                    tv.tv_usec
+                    );
+#else
+                _ftime(&tb);
+                printf("Intractable Board No. %i at %li.%.6i\n",
+                    board_num,
+                    tb.time,
+                    tb.millitm*1000
+                );
+#endif
+                fflush(stdout);
+                print_int_wrapper(-1);
+            }
+            else if (ret == FCS_STATE_IS_NOT_SOLVEABLE)
+            {
+#ifndef WIN32
+                gettimeofday(&tv,&tz);
+                printf("Unsolved Board No. %i at %li.%.6li\n",
+                    board_num,
+                    tv.tv_sec,
+                    tv.tv_usec
+                    );
+#else
+                _ftime(&tb);
+                printf("Unsolved Board No. %i at %li.%.6i\n",
+                    board_num,
+                    tb.time,
+                    tb.millitm*1000
+                );
+#endif
+                print_int_wrapper(-2);
+            }
+            else
+            {
+                print_int_wrapper(freecell_solver_user_get_num_times(user.instance));
+            }
+
+            total_num_iters_temp += freecell_solver_user_get_num_times(instance);
+
+            /*  TODO : implement at the master. */
+#if 0
+
+#endif
+
+            freecell_solver_user_recycle(instance);
+        }
+#undef board_num
+#undef total_num_iters_temp
+
+        write(w.child_to_parent_pipe[WRITE_FD], &response, sizeof(response));
+    }
+
+    /* Cleanup */
+    freecell_solver_user_free(instance);
+
+    close(w.child_to_parent_pipe[WRITE_FD]);
+    close(w.parent_to_child_pipe[READ_FD]);
+
+    return 0;
+}
+
+int main(int argc, char * argv[])
+{
+    int stop_at;
+    int parser_ret;
+#ifndef WIN32
+    struct timeval tv;
+    struct timezone tz;
+#else
+    struct _timeb tb;
+#endif
+
+    int num_workers = 3;
+    worker_t * workers;
+    int next_board_num;
+    int end_board;
+    int board_num_step = 1;
+    char * error_string;
+    pack_item_t user;
+
+    int arg = 1, start_from_arg, idx;
+
+    if (argc < 4)
+    {
+        fprintf(stderr, "Not Enough Arguments!\n");
+        print_help();
+        exit(-1);
+    }
+    next_board_num = atoi(argv[arg++]);
+    end_board = atoi(argv[arg++]);
+    stop_at = atoi(argv[arg++]);
+
+    for (;arg < argc; arg++)
+    {
+        if (!strcmp(argv[arg], "--total-iterations-limit"))
+        {
+            arg++;
+            if (arg == argc)
+            {
+                fprintf(stderr, "--total-iterations-limit came without an argument!\n");
+                print_help();
+                exit(-1);
+            }
+            total_iterations_limit_per_board = atoi(argv[arg]);
+        }
+        else if (!strcmp(argv[arg], "--num-workers"))
+        {
+            arg++;
+            if (arg == argc)
+            {
+                fprintf(stderr, "--num-workers came without an argument!\n");
+                print_help();
+                exit(-1);
+            }
+            num_workers = atoi(argv[arg]);
+        }
+        else if (!strcmp(argv[arg], "--worker-step"))
+        {
+            arg++;
+            if (arg == argc)
+            {
+                fprintf(stderr, "--worker-step came without an argument!\n");
+                print_help();
+                exit(-1);
+            }
+            board_num_step = atoi(argv[arg]);
+        }
+        else if (!strcmp(argv[arg], "--iters-update-on"))
+        {
+            arg++;
+            if (arg == argc)
+            {
+                fprintf(stderr, "--iters-update-on came without an argument!\n");
+                print_help();
+                exit(-1);
+            }
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    start_from_arg = arg;
+
+    /* for(board_num=1;board_num<100000;board_num++) */
+#ifndef WIN32
+    gettimeofday(&tv,&tz);
+    printf("Started at %li.%.6li\n",
+        tv.tv_sec,
+        tv.tv_usec
+        );
+#else
+    _ftime(&tb);
+    printf("Started at %li.%.6i\n",
+        tb.time,
+        tb.millitm*1000
+        );
+#endif
+    fflush(stdout);
+    
+    user.instance = freecell_solver_user_alloc();
+
+    parser_ret =
+        freecell_solver_user_cmd_line_parse_args(
+            user.instance,
+            argc,
+            argv,
+            arg,
+            known_parameters,
+            cmd_line_callback,
+            &user,
+            &error_string,
+            &arg
+        );
+
+    if (parser_ret == FCS_CMD_LINE_UNRECOGNIZED_OPTION)
+    {
+        fprintf(stderr, "Unknown option: %s", argv[arg]);
+        return -1;
+    }
+    else if (
+        (parser_ret == FCS_CMD_LINE_PARAM_WITH_NO_ARG)
+            )
+    {
+        fprintf(stderr, "The command line parameter \"%s\" requires an argument"
+                " and was not supplied with one.\n", argv[arg]);
+        return -1;
+    }
+    else if (
+        (parser_ret == FCS_CMD_LINE_ERROR_IN_ARG)
+        )
+    {
+        if (error_string != NULL)
+        {
+            fprintf(stderr, "%s", error_string);
+            free(error_string);
+        }
+        return -1;
+    }
+
+    workers = malloc(sizeof(workers[0])*num_workers);
+
+    for ( idx = 0 ; idx < num_workers ; idx++)
+    {
+        int fork_ret;
+
+        if (pipe(workers[idx].child_to_parent_pipe))
+        {
+            fprintf(stderr, "C->P Pipe for worker No. %i failed! Exiting.\n", idx);
+            exit(-1);
+        }
+        if (pipe(workers[idx].parent_to_child_pipe))
+        {
+            fprintf(stderr, "P->C Pipe for worker No. %i failed! Exiting.\n", idx);
+            exit(-1);
+        }
+        
+        
+        fork_ret = fork();
+
+        if (fork_ret == -1)
+        {
+            fprintf(stderr, "Fork for worker No. %i failed! Exiting.\n", idx);
+            exit(-1);
+        }
+
+        if (! fork_ret)
+        {
+            /* I'm the child. */
+            close(workers[idx].parent_to_child_pipe[WRITE_FD]);
+            close(workers[idx].child_to_parent_pipe[READ_FD]);
+            break;
+        }
+        else
+        {
+            /* I'm the parent. */
+            close(workers[idx].parent_to_child_pipe[READ_FD]);
+            close(workers[idx].child_to_parent_pipe[WRITE_FD]);
+        }
+    }
+
+    if (idx < num_workers)
+    {
+        worker_t w = workers[idx];
+        free(workers);
+        return worker_func(idx, w, user.instance);
+    }
+
+    freecell_solver_user_free(user.instance);
+
+    {
+        /* I'm the master. */
+        fd_set readers, initial_readers;
+        int select_ret;
+        int mymax = -1;
+        response_t response;
+        request_t request;
+        int total_num_finished_boards = 0;
+        int total_num_boards_to_check = end_board - next_board_num + 1;
+        int next_milestone = next_board_num + stop_at;
+
+        next_milestone -= (next_milestone % stop_at);
+
+        FD_ZERO(&initial_readers);
+
+        for(idx=0; idx<num_workers; idx++)
+        {
+            int fd = workers[idx].child_to_parent_pipe[READ_FD];
+            FD_SET(fd, &initial_readers);
+            if (fd > mymax)
+            {
+                mymax = fd;
+            }
+        }
+
+        mymax++;
+
+#define WRITE_REQUEST() \
+                        if (next_board_num > end_board) \
+                        { \
+                            request.board_num = -1; \
+                        } \
+                        else \
+                        { \
+                            request.board_num = next_board_num; \
+                            if ((next_board_num += board_num_step) > end_board) \
+                            { \
+                                next_board_num = end_board+1; \
+                            } \
+                            request.quota_end = next_board_num-1; \
+                        } \
+      \
+                        write( \
+                                workers[idx].parent_to_child_pipe[WRITE_FD], \
+                                &request, \
+                                sizeof(request) \
+                        )
+
+        for(idx=0; idx<num_workers; idx++)
+        {
+            WRITE_REQUEST();
+        }
+
+        while (total_num_finished_boards < total_num_boards_to_check)
+        {
+            if (total_num_finished_boards >= next_milestone)
+            {
+#ifndef WIN32
+                gettimeofday(&tv,&tz);
+                printf("Reached Board No. %i at %li.%.6li (total_num_iters=%lli)\n",
+                    next_milestone,
+                    tv.tv_sec,
+                    tv.tv_usec,
+                    total_num_iters
+                    );
+#else
+                _ftime(&tb);
+                printf(
+#ifdef __GNUC__
+                        "Reached Board No. %i at %li.%.6i (total_num_iters=%lli)\n",
+#else
+                        "Reached Board No. %i at %li.%.6i (total_num_iters=%I64i)\n",
+#endif
+                    next_milestone,
+                    tb.time,
+                    tb.millitm*1000,
+                    total_num_iters
+                );
+#endif
+                fflush(stdout);
+
+                next_milestone += stop_at;
+            }
+
+            readers = initial_readers;
+            /* I'm the master. */
+            select_ret = select (mymax, &readers, NULL, NULL, NULL);
+
+            if (select_ret == -1)
+            {
+                perror("select()");
+            }
+            else if (select_ret)
+            {
+                for(idx=0; idx<num_workers; idx++)
+                {
+                    int fd = workers[idx].child_to_parent_pipe[READ_FD];
+
+                    if (FD_ISSET(fd, &readers))
+                    {
+                        /* FD_ISSET can be set on EOF, so we check if
+                         * read failed. */
+                        if (read (fd, &response, sizeof(response)) < sizeof(response))
+                        {
+                            continue;
+                        }
+
+                        total_num_iters += response.num_iters;
+                        total_num_finished_boards += response.num_finished_boards;
+
+                        WRITE_REQUEST();
+
+                    }
+                }
+            }
+        }
+    }
+
+
+    {
+        int status;
+        for(idx=0; idx<num_workers; idx++)
+        {
+            wait(&status);
+        }
+    }
+#ifndef WIN32
+            gettimeofday(&tv,&tz);
+            printf("Finished at %li.%.6li (total_num_iters=%lli)\n",
+                tv.tv_sec,
+                tv.tv_usec,
+                total_num_iters
+                );
+#else
+            _ftime(&tb);
+            printf(
+#ifdef __GNUC__
+                    "Finished at %li.%.6i (total_num_iters=%lli)\n",
+#else
+                    "Finshed at %li.%.6i (total_num_iters=%I64i)\n",
+#endif
+                tb.time,
+                tb.millitm*1000,
+                total_num_iters
+            );
+#endif
+
+    free(workers);
+
+    return 0;
+}
+

File fc-solve/source/scripts/time-threads-num.bash

 #!/bin/bash
 
 RUN_SERIAL=false
+PROG="${PROG:-./freecell-solver-multi-thread-solve}"
+
+while getopts "sp" flag ; do
+    # Run the serial scan first.
+    if   [ "$flag" = "s" ] ; then
+        RUN_SERIAL=true
+    # Run the multi-process version instead of the multi-threaded version.
+    elif [ "$flag" = "p" ] ; then
+        PROG="./freecell-solver-fork-solve"
+    fi
+done
 
-PARAM1="$1"
-shift
-
-if test "$PARAM1" = "-s" ; then
-    RUN_SERIAL=true
-    PARAM1="$1"
+while [ $OPTIND -ne 1 ] ; do
     shift
-fi
+    let OPTIND--
+done
 
-PARAM2="$1"
+MIN="${1:-1}"
 shift
 
-MIN=1
-MAX=6
-
-if ! test -z "$PARAM2" ; then
-    MIN="$PARAM1"
-    MAX="$PARAM2"
-elif ! test -z "$PARAM1" ; then
-    MAX="$PARAM1"
-fi
+MAX="${1:-6}"
+shift
 
 OUT_DIR="${OUT_DIR:-.}"
 ARGS="${ARGS:--l gi}"
 
 for NUM in $(seq "$MIN" "$MAX") ; do
     echo "Testing $NUM"
-    ./freecell-solver-multi-thread-solve 1 32000 4000 \
+    $PROG 1 32000 4000 \
         --iters-update-on 10000000 \
         --num-workers "$NUM" \
         $ARGS \
         > "$(printf "$OUT_DIR/DUMPS/dump%.3i" "$NUM")"
 done
+