/* Bridges Source Code          */

/* By Dick Christoph April 1998 */

/* dchristo@minn.net            */

/* www1.minn.net/~dchristo      */



import java.applet.*;

import java.awt.*;

import java.io.*;



public class Bridges extends Applet {

  public static final int MAXSCREENX = 340;

  public static final int MAXSCREENY = 340;

  public static final int MAXROWS = 17;

  public static final int MAXCOLS = 17;

  public static final int NOTOWER = 0;

  public static final int BLUETOWER = 1, BLUE = 1;

  public static final int REDTOWER = 2, RED = 2;

  public static final int ROW = 0;

  public static final int COL = 1;



  public static final int UP = 1;

  public static final int RIGHT = 2;

  public static final int LEFT = 3;

  public static final int DOWN = 4;



  public static int board[][], whoseTurn;

  static BridgeCanvas cnv1;

  static Label turnMsg, statusMsg;

  Button newGameButton;

  Panel p, p1;



  static boolean redWins, blueWins, debug;



  public static final int MAXSTEPS = 10000;

  public static final int MAXOPTIONS = 200;

  public static final int MAXPATHLIST = 32;

  public static boolean visited[][];

  public static boolean consider[][];

  public static Option optionList[];

  public static Step steps[];

  public static int minSteps[][];

  public static PathList bluePathList[], redPathList[];

  public static int optionTop, firstFreeStep, bluePathListTop, redPathListTop;

  public static double stepCounter;

  public static double maxSteps, maxOptions, maxPathList, maxMoves;



  public void init()

  { 

    setLayout(null);

    resize(MAXSCREENX,MAXSCREENY+60);

    addNotify();



    debug = false;

    cnv1 = new BridgeCanvas();

    add(cnv1);

    cnv1.reshape(0,0,MAXSCREENX, MAXSCREENY);



    p = new Panel();

    turnMsg = new Label("");

    turnMsg.setAlignment(Label.CENTER);

    p.add(turnMsg);

    whoseTurn = BLUE;

    toggleTurnMsg();

    p.reshape(0,MAXSCREENY,MAXSCREENX,30);

    add(p);

    p1 = new Panel();

    newGameButton = new Button("New Game");

    p1.add(newGameButton);

    if (debug)

    { statusMsg = new Label("");

      statusMsg.setAlignment(Label.CENTER);

      p1.add(statusMsg);

    }

    p1.reshape(0,MAXSCREENY+30,MAXSCREENX,30);

    add(p1);

    initBoard();

    setupMem();

    cnv1.repaint();

  }



  public boolean action(Event e, Object arg)

  { Object source = e.target;

    if (source == newGameButton)

    { initBoard();

      cnv1.repaint();

    }

    return true;

  }



  public void destroy() {

  }



  public void initBoard()

  { int r, c;

    redWins = false;

    blueWins = false;

    whoseTurn = BLUE;

    toggleTurnMsg();

    if (debug)

      statusMsg.setText("");

    maxSteps = 0;

    maxOptions = 0;

    maxPathList = 0;

    maxMoves = 0;



    board = new int[MAXROWS][MAXCOLS];



    for (r = 0; r < MAXROWS; r++)

    { for (c = 0; c < MAXCOLS; c++)

      { board[r][c] = NOTOWER;

        if ((r % 2) == 0)   /* even row */

        { if ((c % 2) == 1)   /* odd col */

          { board[r][c] = BLUETOWER;

        } }

        else  /* odd row */

        { if ((c % 2) == 0)   /* even col */

          { board[r][c] = REDTOWER;

    } } } }

  }



  public static void toggleTurnMsg()

  {

    if (whoseTurn == BLUE)

    { whoseTurn = RED;

      turnMsg.setText("Red - It is your Move");

    }

    else

    { whoseTurn = BLUE;

      turnMsg.setText("Blue - It is your Move");

    }

  }



  public static boolean toggleBox(int r, int c)

  { boolean rv;



    if (board[r][c] == NOTOWER)

    { rv = true;

      if (whoseTurn == BLUE)

      { board[r][c] = BLUETOWER;

        toggleTurnMsg();

        determineBlueProgress();

      }

      else

      { board[r][c] = REDTOWER;

        toggleTurnMsg();

        determineRedProgress();

      }

    }

    else

      rv = false;

    return(rv);

  }



  public static void determineBlueProgress()

  { int r,c, r1, c1, tryTop, tryPtr;

    int tries[][];



    visited = new boolean[MAXROWS][MAXCOLS];

    for (r = 0; r < MAXROWS; r++)

      for (c = 0; c < MAXCOLS; c++)

        visited[r][c] = false;



    tries = new int[MAXROWS*MAXCOLS][2];

    blueWins = false;



    r = 0;

    for (c = 1; c < MAXCOLS && (!blueWins); c = c + 2)

    { /* board[0][c] = BLUETOWER */

      if (!visited[0][c])

      { tryTop = 0;

        tryPtr = 0;

        tries[tryTop][ROW] = 0;

        tries[tryTop++][COL] = c;

        while ((tryPtr < tryTop) && (!blueWins))

        { r1 = tries[tryPtr][ROW];

          c1 = tries[tryPtr][COL];

          visited[r1][c1] = true;

          if (r1 == MAXROWS - 1)

            blueWins = true;

          else

          { if ((r1 - 1) >= 0)  /* check up */

            { if ((!visited[r1-1][c1]) && (board[r1-1][c1] == BLUETOWER))

              { tries[tryTop][ROW] = r1-1;

                tries[tryTop++][COL] = c1;

            } }

            /* check down */

            if ((!visited[r1+1][c1]) && (board[r1+1][c1] == BLUETOWER))

            { { tries[tryTop][ROW] = r1+1;

                tries[tryTop++][COL] = c1;

            } }

            if ((c1 - 1) >= 0)  /* check left */

            { if ((!visited[r1][c1-1]) && (board[r1][c1-1] == BLUETOWER))

              { tries[tryTop][ROW] = r1;

                tries[tryTop++][COL] = c1-1;

            } }

            /* check right */

            if ((c1 + 1) < MAXCOLS)  

            { if ((!visited[r1][c1+1]) && (board[r1][c1+1] == BLUETOWER))

              { tries[tryTop][ROW] = r1;

                tries[tryTop++][COL] = c1+1;

          } } }

          tryPtr++;

        }

      }

    }

    if (blueWins)

    { turnMsg.setText("Blue Wins");

      if (debug)

        statusMsg.setText("Blue Wins" + " MS: " + maxSteps + " MO: " + maxOptions + " MP: " + maxPathList + " MM: " + maxMoves);

    }

  }



  public static void determineRedProgress()

  { int r,c, r1, c1, tryTop, tryPtr;

    int tries[][];



    visited = new boolean[MAXROWS][MAXCOLS];

    for (r = 0; r < MAXROWS; r++)

      for (c = 0; c < MAXCOLS; c++)

        visited[r][c] = false;



    tries = new int[MAXROWS*MAXCOLS][2];

    redWins = false;



    c = 0;

    for (r = 1; r < MAXROWS && (!redWins); r = r + 2)

    { /* board[r][0] = REDTOWER */

      if (!visited[r][0])

      { tryTop = 0;

        tryPtr = 0;

        tries[tryTop][ROW] = r;

        tries[tryTop++][COL] = 0;

        while ((tryPtr < tryTop) && (!redWins))

        { r1 = tries[tryPtr][ROW];

          c1 = tries[tryPtr][COL];

          visited[r1][c1] = true;

          if (c1 == MAXCOLS - 1)

            redWins = true;

          else

          { if ((r1 - 1) >= 0)  /* check up */

            { if ((!visited[r1-1][c1]) && (board[r1-1][c1] == REDTOWER))

              { tries[tryTop][ROW] = r1-1;

                tries[tryTop++][COL] = c1;

            } }

            if ((r1 + 1) < MAXROWS)  /* check down */

            { if ((!visited[r1+1][c1]) && (board[r1+1][c1] == REDTOWER))

              { tries[tryTop][ROW] = r1+1;

                tries[tryTop++][COL] = c1;

            } }

            if ((c1 - 1) >= 0)  /* check left */

            { if ((!visited[r1][c1-1]) && (board[r1][c1-1] == REDTOWER))

              { tries[tryTop][ROW] = r1;

                tries[tryTop++][COL] = c1-1;

            } }

            /* check right */

            if ((c1 + 1) < MAXCOLS)  

            { if ((!visited[r1][c1+1]) && (board[r1][c1+1] == REDTOWER))

              { tries[tryTop][ROW] = r1;

                tries[tryTop++][COL] = c1+1;

          } } }

          tryPtr++;

        }

      }

    }

    if (redWins)

    { turnMsg.setText("Red Wins");

      if (debug)

        statusMsg.setText("Red Wins" + " MS: " + maxSteps + " MO: " + maxOptions + " MP: " + maxPathList + " MM: " + maxMoves);

  } }



  public static void setupMem()

  { int i;



    steps = new Step[MAXSTEPS];

    for (i = 0; i < MAXSTEPS; i++)

      steps[i] = new Step();



    optionList = new Option[MAXOPTIONS];

    for (i = 0; i < MAXOPTIONS; i++)

      optionList[i] = new Option();



    bluePathList = new PathList[MAXPATHLIST];

    for (i = 0; i < MAXPATHLIST; i++)

      bluePathList[i] = new PathList();



    redPathList = new PathList[MAXPATHLIST];

    for (i = 0; i < MAXPATHLIST; i++)

      redPathList[i] = new PathList();

  }



  public static void findBestMove()

  { int i, r, c, pth, stp, s, curStep, row, col;

    Point bestMove;



    stepCounter = 0;

    for (i = 0; i < MAXSTEPS; i++)

      steps[i].nextStep = i + 1;

    steps[MAXSTEPS-1].nextStep = -1;

    firstFreeStep = 0;



    visited = new boolean[MAXROWS][MAXCOLS];

    minSteps = new int[MAXROWS][MAXCOLS];

    consider = new boolean[MAXROWS][MAXCOLS];

    for (r = 0; r < MAXROWS; r++)

    { for (c = 0; c < MAXCOLS; c++)

      { visited[r][c] = false;

        minSteps[r][c] = MAXROWS * MAXCOLS;

        if ((r == 0) || (r == MAXROWS-1) || (c == 0) || (c == MAXCOLS-1))

          consider[r][c] = false;

        else

          consider[r][c] = true;

      }

    }



    optionTop = 0;

    bluePathListTop = 0;

    findShortestBluePaths();



    for (r = 0; r < MAXROWS; r++)

    { for (c = 0; c < MAXCOLS; c++)

      { visited[r][c] = false;

        minSteps[r][c] = MAXROWS * MAXCOLS;

        if ((r == 0) || (r == MAXROWS-1) || (c == 0) || (c == MAXCOLS-1))

          consider[r][c] = false;

        else

          consider[r][c] = true;

      }

    }

    optionTop = 0;

    redPathListTop = 0;

    findShortestRedPaths();

    if (debug)

      statusMsg.setText("BPLT: " + bluePathListTop + " RPLT: " + redPathListTop + " SC: " + stepCounter + " MS: " + maxSteps);

    bestMove = compareBlueAndRedLists();

    row = bestMove.y;

    col = bestMove.x;

    toggleBox(row,col);

    cnv1.repaint();

  }



  public static final int COUNT = 2, CLOSEST = 3;

  public static final int MAXDIST = MAXROWS * MAXCOLS;



  public static Point compareBlueAndRedLists()

  { int blueList[][], redList[][], tempBoard[][][], moveList[][];

    int blueTop, redTop, cmp, b, r, c, p, row, col, cp, lp, i, j;

    int close, closeCnt, lo, hi, mid, maxCount, count, moveListTop;



    boolean found, secureTop, secureBottom;

    Point rv;



    rv = new Point(0,0);



    secureTop = false;

    secureBottom = false;

    for (c = 1; c < MAXCOLS; c+=2)

    {  if (board[1][c] == BLUETOWER)

        secureTop = true;

      if (board[MAXROWS-2][c] == BLUETOWER)

        secureBottom = true;

    }

    if ((!secureTop) || (!secureBottom))

    { if (!secureTop)

      { for (b = 0; (b <= 6) && (!secureTop); b += 2)

        { for (c = 7-b; c <= 9+b; c += 2)

          { if (board[1][c] == NOTOWER)

            { rv.x = c;

              rv.y = 1;

              secureTop = true;

      } } } }

      else

      { for (b = 0; (b <= 6) && (!secureBottom); b += 2)

        { for (c = 7-b; c <= 9+b; c += 2)

          { if (board[MAXROWS-2][c] == NOTOWER)

            { rv.x = c;

              rv.y = MAXROWS-2;

              secureBottom = true;

    } } } } }

    else

    { 

      if ((redPathList[0].togo == 1) && (bluePathList[0].togo > 1))

      { /* Red has only one togo, must block it */

        cp = redPathList[0].firstStep;

        rv.x = -1;

        while ((cp != -1) && (rv.x == -1))

        { row = steps[cp].row;

          col = steps[cp].col;

          if (board[row][col] == NOTOWER)

          { rv.x = col;

            rv.y = row;

          }

          cp = steps[cp].nextStep;

        }

      }

      else

      { blueList = new int[MAXROWS*MAXCOLS][3];

        redList = new int[MAXROWS*MAXCOLS][4];

        tempBoard = new int[MAXROWS][MAXCOLS][2];  /* 0 = COUNT 1 = CLOSEST */

        moveList = new int[MAXROWS*MAXCOLS][2];

  

        for (r = 0; r < MAXROWS; r++)

        { for (c = 0; c < MAXCOLS; c++)

          { tempBoard[r][c][0] = 0;

            tempBoard[r][c][1] = 0;

        } }

  

        for (p = 0; p < bluePathListTop; p++)

        { cp = bluePathList[p].firstStep;

          while (cp != -1)

          { row = steps[cp].row;

            col = steps[cp].col;

            if (board[row][col] == NOTOWER)

            { tempBoard[row][col][0] += 1;

            }

            cp = steps[cp].nextStep;

        } }



        blueTop = 0;

        for (r = 0; r < MAXROWS; r++)

        { for (c = 0; c < MAXCOLS; c++)

          { if (tempBoard[r][c][0] != 0)

            { blueList[blueTop][ROW] = r;

              blueList[blueTop][COL] = c;

              blueList[blueTop++][COUNT] = tempBoard[r][c][0];

        } } }



        for (r = 0; r < MAXROWS; r++)

        { for (c = 0; c < MAXCOLS; c++)

          { tempBoard[r][c][0] = 0;

            tempBoard[r][c][1] = MAXDIST;

        } }

  

        lp = -1;

        for (p = 0; p < redPathListTop; p++)

        { cp = redPathList[p].firstStep;

          steps[cp].prevStep = -1;    /* This should have been taken care of elsewhere */

          closeCnt = MAXDIST;

          while (cp != -1)

          { row = steps[cp].row;

            col = steps[cp].col;

            if (board[row][col] == NOTOWER)

            { tempBoard[row][col][0] += 1;

              tempBoard[row][col][1] = Math.min(tempBoard[row][col][1], closeCnt++);

            }

            else

              closeCnt = 1;

            lp = cp;

            cp = steps[cp].nextStep;

          }

          closeCnt = MAXDIST;

          while (lp != -1)

          { row = steps[lp].row;

            col = steps[lp].col;

            if (board[row][col] == NOTOWER)

            { tempBoard[row][col][0] += 1;

              tempBoard[row][col][1] = Math.min(tempBoard[row][col][1], closeCnt++);

            }

            else

              closeCnt = 1;

            lp = steps[lp].prevStep;

          }

        }

  

        redTop = 0;

        for (r = 0; r < MAXROWS; r++)

        { for (c = 0; c < MAXCOLS; c++)

          { if (tempBoard[r][c][0] != 0)

            { redList[redTop][ROW] = r;

              redList[redTop][COL] = c;

              redList[redTop][COUNT] = tempBoard[r][c][0] / 2;

              redList[redTop++][CLOSEST] = tempBoard[r][c][1];

        } } }

  

  

        for (i = 0; i < blueTop-1; i++)

        { for (j = i; j < blueTop; j++)

          { cmp = compareRowCol(blueList[i][ROW], blueList[i][COL], blueList[j][ROW], blueList[j][COL]); 

            if (cmp == 1)

            { row = blueList[j][ROW];

              col = blueList[j][COL];

              count = blueList[j][COUNT];

              blueList[j][ROW] = blueList[i][ROW];

              blueList[j][COL] = blueList[i][COL];

              blueList[j][COUNT] = blueList[i][COUNT];

              blueList[i][ROW] = row;

              blueList[i][COL] = col;

              blueList[i][COUNT] = count;

        } } }

  

        for (i = 0; i < redTop-1; i++)

        { for (j = i; j < redTop; j++)

          { cmp = compareCloseRowCol(redList[i][CLOSEST], redList[i][ROW], redList[i][COL], redList[j][CLOSEST], redList[j][ROW], redList[j][COL]); 

            if (cmp == 1)

            { row = redList[j][ROW];

              col = redList[j][COL];

              count = redList[j][COUNT];

              close = redList[j][CLOSEST];

              redList[j][ROW] = redList[i][ROW];

              redList[j][COL] = redList[i][COL];

              redList[j][COUNT] = redList[i][COUNT];

              redList[j][CLOSEST] = redList[i][CLOSEST];

              redList[i][ROW] = row;

              redList[i][COL] = col;

              redList[i][COUNT] = count;

              redList[i][CLOSEST] = close;

        } } }



        r = 0;

        b = 0;

        found = false;

        rv.x = -1;

        maxCount = 0;

        close = MAXDIST;

        moveListTop = 0;

        while ((r < redTop) && (!found))

        { /* binsearch bluelist for redList[r][ROW]{COL] */

          lo = 0;

          hi = blueTop - 1;

          mid = 0;

          while ((lo <= hi) && (!found))

          { mid = (lo + hi) / 2;

            cmp = compareRowCol(redList[r][ROW], redList[r][COL], blueList[mid][ROW], blueList[mid][COL]);

            if (cmp > 0)

              lo = mid + 1;

            else

              if (cmp == 0)

                found = true;

              else

                hi = mid - 1;

          }

          if (found)

          { /* All those in moveList will have same Count and Closeness */

            if ( (blueList[mid][COUNT] + redList[mid][COUNT] >= maxCount)

               && (redList[r][CLOSEST] <= close))

            { if ( (blueList[mid][COUNT] + redList[mid][COUNT] > maxCount)

               || (redList[r][CLOSEST] < close))

                moveListTop = 0;

              moveList[moveListTop][ROW] = blueList[mid][ROW];

              moveList[moveListTop++][COL] = blueList[mid][COL];

              maxCount = blueList[mid][COUNT];

              close = redList[r][CLOSEST];

            }

            found = false;

          }

          r++;

        }

        if (moveListTop == 0)

        { for (b = 0; b < blueTop; b++)

          { if (blueList[b][COUNT] >= maxCount)

            { if (blueList[b][COUNT] > maxCount)

                moveListTop = 0;

              moveList[moveListTop][ROW] = blueList[b][ROW];

              moveList[moveListTop++][COL] = blueList[b][COL];

              maxCount = blueList[b][COUNT];

        } } }

        maxMoves = Math.max(moveListTop, maxMoves);

        b = (int) (Math.random() * moveListTop);

        rv.x = moveList[b][COL];

        rv.y = moveList[b][ROW];

    } }

    return(rv);

  }



  /* Returns -1 if row1,col1 < row2, col2 0 if equal +1 if greater */

  public static int compareCloseRowCol(int close1, int row1, int col1, int close2, int row2, int col2)

  { int rc1, rc2;



    rc1 = (close1 * 2000) + (row1 * 50) + col1;

    rc2 = (close2 * 2000) + (row2 * 50) + col2;

    if (rc1 == rc2)

      return(0);

    else

      if (rc1 < rc2)

        return(-1);

      else

        return(+1);



  }

  /* Returns -1 if row1,col1 < row2, col2 0 if equal +1 if greater */

  public static int compareRowCol(int row1, int col1, int row2, int col2)

  { int rc1, rc2;



    rc1 = (row1 * 100) + col1;

    rc2 = (row2 * 100) + col2;

    if (rc1 == rc2)

      return(0);

    else

      if (rc1 < rc2)

        return(-1);

      else

        return(+1);



  }



  public static int newStep()

  { int rv;

    rv = firstFreeStep;

    stepCounter++;

    maxSteps = Math.max(stepCounter, maxSteps);

    firstFreeStep = steps[firstFreeStep].nextStep;

    if (firstFreeStep == -1)

    { if (debug)

      { statusMsg.setText("Out of Memory for Steps.");

        System.out.println("StepCounter: " + stepCounter);

      }

      else

        turnMsg.setText("Out of Memory for Steps.");

    }

    steps[rv].nextStep = -1;

    return(rv);

  }



  public static void deleteStep(int stepNum)

  {

    stepCounter--;

    steps[stepNum].nextStep = firstFreeStep;

    firstFreeStep = stepNum;

  }

  

  public static void findShortestBluePaths()

  { int pathHead, pathHeadLength, pathHeadTogo, minTogo, c, row, col;

    int stepCnt, prevStep, nextStep, curStep, lastStep, targ, cp, lp;

    int row1, col1, ph, pathCnt, c1;



    minTogo = MAXROWS * MAXCOLS;



    pathCnt = 0;

    for (c = 1; c < MAXCOLS - 1; c+=2)

    { // System.out.println("Column: " + c);

      /* No need to consider row1 except for column c */

      for (c1 = 1; c1 < MAXCOLS - 1; c1+= 2)

      { if (c1 != c)

          consider[1][c1] = false;

        else

          consider[1][c1] = true;

      }

      if (board[1][c] != REDTOWER)

      { curStep = newStep();

        pathHead = curStep;

        steps[curStep].row = 1;

        steps[curStep].col = c;

        steps[curStep].stepCnt = 1;

        steps[curStep].direction = DOWN;

        steps[curStep].nextStep = -1;

        steps[curStep].prevStep = -1;

        pathHeadLength = 1;

        if (board[1][c] == NOTOWER)

          pathHeadTogo = 1;

        else

          pathHeadTogo = 0;

        visited[1][c] = true;

        optionTop = 0;

        row1 = 2;

        col1 = c;

        stepCnt = 2;

        /* check right */

        considerBlueMove(stepCnt, row1, col1+1, RIGHT);



        /* check LEFT */

        considerBlueMove(stepCnt, row1, col1-1, LEFT);



        /* check DOWN */

        considerBlueMove(stepCnt, row1+1, col1, DOWN);



        lastStep = curStep;

        stepCnt = 3;

        while (optionTop > 0)

        { optionTop--;

          /* makeMove(optionList[optionTop]); */

          while (optionList[optionTop].stepCnt <= steps[lastStep].stepCnt)

          { row = steps[lastStep].row;

            col = steps[lastStep].col;

            visited[row][col] = false;

            pathHeadLength--;

            if (board[row][col] != BLUETOWER)

              pathHeadTogo--;

            lastStep = steps[lastStep].prevStep;

            deleteStep(steps[lastStep].nextStep);

            steps[lastStep].nextStep = -1;

          }

          curStep = newStep();

          steps[lastStep].nextStep = curStep;

          steps[curStep].prevStep = lastStep;

          steps[curStep].row = optionList[optionTop].row;

          steps[curStep].col = optionList[optionTop].col;

          steps[curStep].stepCnt = optionList[optionTop].stepCnt;

          steps[curStep].direction = optionList[optionTop].direction;

          steps[curStep].nextStep = -1;

          pathHeadLength++;

          row = steps[curStep].row;

          col = steps[curStep].col;

          if (board[row][col] == NOTOWER)

            pathHeadTogo++;

          visited[row][col] = true;



          if ((steps[curStep].row == MAXROWS - 2)

           || (pathHeadTogo > minTogo)

           || (pathHeadTogo > minSteps[row][col]))

          { if ( (steps[curStep].row == MAXROWS - 2) 

              && (pathHeadTogo <= minTogo))

            { /* savePath(); */

              if (pathHeadTogo < minTogo) /* replace current shortest path(s) */

              { deleteBluePathList();

                targ = 0;

                bluePathListTop = 1;

                minTogo = pathHeadTogo;

              }

              else  /* path HeadTogo = minTogo */

              { if (bluePathListTop < MAXPATHLIST)  /* add to list of shortest path(s) */

                { targ = bluePathListTop++;

                  maxPathList = Math.max(bluePathListTop, maxPathList);

                }

                else

                  targ = MAXPATHLIST;

              }

              if (targ == MAXPATHLIST)

              { if (debug)

                  statusMsg.setText("Out of space for Blue PathList");

                else

                  turnMsg.setText("");

              }

              else

              { cp = newStep();

                bluePathList[targ].length = pathHeadLength;

                bluePathList[targ].togo = pathHeadTogo;

                bluePathList[targ].firstStep = cp;

                steps[cp].row = steps[pathHead].row;

                steps[cp].col = steps[pathHead].col;

                steps[cp].stepCnt = steps[pathHead].stepCnt;

                steps[cp].direction = steps[pathHead].direction;

                ph = steps[pathHead].nextStep;

                lp = cp;

                while (ph != -1)

                { cp = newStep();

                  steps[lp].nextStep = cp;

                  steps[cp].prevStep = lp;

                  steps[cp].row = steps[ph].row;

                  steps[cp].col = steps[ph].col;

                  steps[cp].stepCnt = steps[ph].stepCnt;

                  steps[cp].direction = steps[ph].direction;

                  ph = steps[ph].nextStep;

                  lp = cp;

                }

                steps[lp].nextStep = -1;

                /* Be sure pointers are left in right state for recursion */

            } }

/*          else   bailout */

          }

          else  /* keep going */

          { minSteps[row][col] = pathHeadTogo;

            switch (steps[curStep].direction)   /* ROW1, COL1 is location of initial BLUETOWER */

            { case UP:

                row1 = steps[curStep].row - 1;

                col1 = steps[curStep].col;

                break;

              case DOWN:

                row1 = steps[curStep].row + 1;

                col1 = steps[curStep].col;

                break;

              case LEFT:

                row1 = steps[curStep].row;

                col1 = steps[curStep].col-1;

                break;

              case RIGHT:

                row1 = steps[curStep].row;

                col1 = steps[curStep].col+1;

                break;

            }



            stepCnt = steps[curStep].stepCnt + 1;

            /* check UP */

            considerBlueMove(stepCnt, row1-1, col1, UP);



            /* check right */

            considerBlueMove(stepCnt, row1, col1+1, RIGHT);



            /* check LEFT */

            considerBlueMove(stepCnt, row1, col1-1, LEFT);



            /* check DOWN */

            considerBlueMove(stepCnt, row1+1, col1, DOWN);

          }

          lastStep = curStep;

        } /* End While (optionTop > 0) */

        while (lastStep != -1)

        { row = steps[lastStep].row;

          col = steps[lastStep].col;

          visited[row][col] = false;

          lp = steps[lastStep].prevStep;

          deleteStep(lastStep);

          lastStep = lp;

        }

      }   /* end if board[1][c] != REDTOWER */

    } /* End for c = 1 to MAXCOLS */

  }



  public static void deleteBluePathList()

  { int p, lp, cp;



    for (p = 0; p < bluePathListTop; p++)

    { cp = bluePathList[p].firstStep;

      while (cp != -1)

      { lp = cp;

        cp = steps[cp].nextStep;

        deleteStep(lp);

      }

    }

    bluePathListTop = 0;

  }



  public static void considerBlueMove(int stepCnt, int row2, int col2, int direction)

  {

    if ((consider[row2][col2])

     && (!visited[row2][col2])

     && (board[row2][col2] != REDTOWER) )

    { optionList[optionTop].stepCnt = stepCnt;

      optionList[optionTop].row = row2;

      optionList[optionTop].col = col2;

      optionList[optionTop].direction = direction;

      optionTop++;

      maxOptions = Math.max(optionTop, maxOptions);

    }

  }



  public static void findShortestRedPaths()

  { int pathHead, pathHeadLength, pathHeadTogo, minTogo, row, col;

    int stepCnt, prevStep, nextStep, curStep, lastStep, targ, cp, lp;

    int row1, col1, ph, pathCnt, r, r1;



    minTogo = MAXROWS * MAXCOLS;



    pathCnt = 0;

    for (r = 1; r < MAXROWS - 1; r+=2)

    { // System.out.println("Row: " + r);

      /* No need to consider col1 except for row r */

      for (r1 = 1; r1 < MAXROWS - 1; r1+= 2)

      { if (r1 != r)

          consider[r1][1] = false;

        else

          consider[r1][1] = true;

      }

      if (board[r][1] != BLUETOWER)

      { curStep = newStep();

        pathHead = curStep;

        steps[curStep].row = r;

        steps[curStep].col = 1;

        steps[curStep].stepCnt = 1;

        steps[curStep].direction = RIGHT;

        steps[curStep].nextStep = -1;

        steps[curStep].prevStep = -1;

        pathHeadLength = 1;

        if (board[r][1] == NOTOWER)

          pathHeadTogo = 1;

        else

          pathHeadTogo = 0;

        visited[r][1] = true;

        optionTop = 0;

        row1 = r;

        col1 = 2;

        stepCnt = 2;



        /* check UP */

        considerRedMove(stepCnt, row1-1, col1, UP);



        /* check DOWN */

        considerRedMove(stepCnt, row1+1, col1, DOWN);



        /* check right */

        considerRedMove(stepCnt, row1, col1+1, RIGHT);



        lastStep = curStep;

        stepCnt = 3;

        while (optionTop > 0)

        { optionTop--;

          /* makeMove(optionList[optionTop]); */

          while (optionList[optionTop].stepCnt <= steps[lastStep].stepCnt)

          { row = steps[lastStep].row;

            col = steps[lastStep].col;

            visited[row][col] = false;

            pathHeadLength--;

            if (board[row][col] != REDTOWER)

              pathHeadTogo--;

            lastStep = steps[lastStep].prevStep;

            deleteStep(steps[lastStep].nextStep);

            steps[lastStep].nextStep = -1;

          }

          curStep = newStep();

          steps[lastStep].nextStep = curStep;

          steps[curStep].prevStep = lastStep;

          steps[curStep].row = optionList[optionTop].row;

          steps[curStep].col = optionList[optionTop].col;

          steps[curStep].stepCnt = optionList[optionTop].stepCnt;

          steps[curStep].direction = optionList[optionTop].direction;

          steps[curStep].nextStep = -1;

          pathHeadLength++;

          row = steps[curStep].row;

          col = steps[curStep].col;

          if (board[row][col] == NOTOWER)

            pathHeadTogo++;

          visited[row][col] = true;



          if ((steps[curStep].col == MAXCOLS - 2)

           || (pathHeadTogo > minTogo)

           || (pathHeadTogo > minSteps[row][col]))

          { if ( (steps[curStep].col == MAXCOLS - 2) 

              && (pathHeadTogo <= minTogo))

            { /* savePath(); */

              if (pathHeadTogo < minTogo) /* replace current shortest path(s) */

              { deleteRedPathList();

                targ = 0;

                redPathListTop = 1;

                minTogo = pathHeadTogo;

              }

              else  /* path HeadTogo = minTogo */

              { if (redPathListTop < MAXPATHLIST)  /* add to list of shortest path(s) */

                { targ = redPathListTop++;

                  maxPathList = Math.max(redPathListTop, maxPathList);

                }

                else

                  targ = MAXPATHLIST;

              }

              if (targ == MAXPATHLIST)

              { if (debug)

                  statusMsg.setText("Out of space for Red PathList");

                else

                  turnMsg.setText("");

              }

              else

              { cp = newStep();

                redPathList[targ].length = pathHeadLength;

                redPathList[targ].togo = pathHeadTogo;

                redPathList[targ].firstStep = cp;

                steps[cp].row = steps[pathHead].row;

                steps[cp].col = steps[pathHead].col;

                steps[cp].stepCnt = steps[pathHead].stepCnt;

                steps[cp].direction = steps[pathHead].direction;

                ph = steps[pathHead].nextStep;

                lp = cp;

                while (ph != -1)

                { cp = newStep();

                  steps[lp].nextStep = cp;

                  steps[cp].prevStep = lp;

                  steps[cp].row = steps[ph].row;

                  steps[cp].col = steps[ph].col;

                  steps[cp].stepCnt = steps[ph].stepCnt;

                  steps[cp].direction = steps[ph].direction;

                  ph = steps[ph].nextStep;

                  lp = cp;

                }

                steps[lp].nextStep = -1;

                /* Be sure pointers are left in right state for recursion */

            } }

/*          else   bailout */

          }

          else  /* keep going */

          { minSteps[row][col] = pathHeadTogo;

            switch (steps[curStep].direction)   /* ROW1, COL1 is location of initial RedTOWER */

            { case UP:

                row1 = steps[curStep].row - 1;

                col1 = steps[curStep].col;

                break;

              case DOWN:

                row1 = steps[curStep].row + 1;

                col1 = steps[curStep].col;

                break;

              case LEFT:

                row1 = steps[curStep].row;

                col1 = steps[curStep].col-1;

                break;

              case RIGHT:

                row1 = steps[curStep].row;

                col1 = steps[curStep].col+1;

                break;

            }



            stepCnt = steps[curStep].stepCnt + 1;

            /* check LEFT */

            considerRedMove(stepCnt, row1, col1-1, LEFT);



            /* check UP */

            considerRedMove(stepCnt, row1-1, col1, UP);



            /* check DOWN */

            considerRedMove(stepCnt, row1+1, col1, DOWN);



            /* check right */

            considerRedMove(stepCnt, row1, col1+1, RIGHT);

          }

          lastStep = curStep;

//          if (pathCnt++ < 20)

//            displayPath(pathHead, pathHeadLength, pathHeadTogo);

        } /* End While (optionTop > 0) */

        while (lastStep != -1)

        { row = steps[lastStep].row;

          col = steps[lastStep].col;

          visited[row][col] = false;

          lp = steps[lastStep].prevStep;

          deleteStep(lastStep);

          lastStep = lp;

        }

      }   /* end if board[1][c] != BLUETOWER */

    } /* End for r = 1 to MAXROWS */

  }



  public static void deleteRedPathList()

  { int p, lp, cp;



    for (p = 0; p < redPathListTop; p++)

    { cp = redPathList[p].firstStep;

      while (cp != -1)

      { lp = cp;

        cp = steps[cp].nextStep;

        deleteStep(lp);

      }

    }

    redPathListTop = 0;

  }



  public static void considerRedMove(int stepCnt, int row2, int col2, int direction)

  {

    if ((consider[row2][col2])

     && (!visited[row2][col2])

     && (board[row2][col2] != BLUETOWER) )

    { optionList[optionTop].stepCnt = stepCnt;

      optionList[optionTop].row = row2;

      optionList[optionTop].col = col2;

      optionList[optionTop].direction = direction;

      optionTop++;

      maxOptions = Math.max(optionTop, maxOptions);

    }

  }



//  public static void main(String args[]) {

//    Bridges bridgeApp = null;

//    bridgeApp = new Bridges("Bridge Application");

//    bridgeApp.resize(MAXSCREENX, MAXSCREENY+75);

//    bridgeApp.show(true);

//  }



}

