home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 056.lha / Four / four.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  16KB  |  652 lines

  1. /*********************************************************************/
  2. /* Four in a Row    V1.0   8/14/87                                   */
  3. /* Copyright (C) 1987 by Pery Pearson                                */
  4. /*                                                                   */
  5. /* Note the 'readme' file.                                           */
  6. /* Feel free to modify the program if you like;  the computer player */
  7. /* ( my_move() and related routines ) really could use some type of  */
  8. /* strategy routine.                                                 */
  9. /*********************************************************************/
  10.  
  11.  
  12. #include <intuition/intuition.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <ctype.h>
  16.  
  17. #include <graphics/gfxbase.h>
  18.  
  19. #include "struct.c"    /* structures and definitions */
  20.  
  21.  
  22. int grid [MAXX] [MAXY];
  23. int on_pole[8];
  24. int polepick, turn, bead_count;
  25. int player2, finished, newgame;
  26. int first_turn, illegal;
  27. int inrow[4], empty[4], maybe[4], possibles[4];
  28.  
  29. /**************************************************************************
  30.  some variables used in making the computer's move(I hope they help):
  31.  
  32. * inrow[x]    : the number of beads in a row including the proposed bead;
  33.                 x is a direction (vertically, horizontally, & both
  34.                 diagonals).  Which direction depends upon how inrow was
  35.                 assigned.  i.e. inrow[0]=in_row(..., 1, 1,...) is in the
  36.                 positive slope diagonal.
  37. * maybe[x]    : Unused, but it is the number of WHO's beads in the direction
  38.                 being used which are separated from WHO's beads that are
  39.                 in-a-row by spaces only, no intervening enemy beads.  x is
  40.                 a direction here too.  (is that clear ?!? - I thought this
  41.                 might be useful for a stategy.)
  42. * empty[x]    : the number of spaces in the direction in question on both
  43.                 sides of WHO's in-a-row beads which are empty or contain
  44.                 other of WHO's beads.  This is bounded by the grid
  45.                 boundaries and enemy beads.  x is a direction.
  46. * possibles[x]: the number of possible 4-in-a-rows with (x+1) beads in a row
  47.                 already (including the hypothetical move in question).
  48. *************************************************************************/
  49.  
  50. /* make C happy by declaring functions */
  51.  
  52. void open_libraries(), done();
  53. void handle_message(), setup(), put_text();
  54. void handle_menu(), whose_move(), get_possibles();
  55. void up_gadgets(), set_ball(), main();
  56. void clear_grid(), draw_grid(), draw_base();
  57. void handle_proj(), handle_game(), initialize();
  58. void illegal_move(), my_move(), player_move();
  59. void reset_menu_item(), clear_square();
  60.  
  61.  
  62. void main()
  63. {
  64.    initialize();
  65.  
  66.    FOREVER {
  67.       if (newgame)   setup();
  68.       whose_move();
  69.       if (!finished && turn == ME && player2 == ME)   {
  70.          my_move();
  71.          whose_move();
  72.       }
  73.       if ((message = (struct IntuiMessage *)GetMsg(window1->UserPort))==NULL)
  74.       {
  75.         Wait(1<<window1->UserPort->mp_SigBit);
  76.         continue;
  77.       }
  78.       handle_message(message);
  79.    }
  80. }
  81.  
  82.  
  83. void whose_move()
  84. {
  85.    int xoff, yoff;
  86.  
  87.    xoff = XOFF-2*8-2;
  88.    yoff = YOFF+(MAXY+3)*ROWS+3;
  89.  
  90.    if (!finished) {
  91.       if (player2 == ME) {
  92.          if (turn == ME) {
  93.             put_text(xoff-4, yoff, "      My move      ", 4);
  94.          }
  95.          else {
  96.             put_text(xoff-4, yoff, "     Your move     ", 3);
  97.          }
  98.       }
  99.       else {
  100.          if (turn == YOU) {
  101.             put_text(xoff, yoff, "   White's move   ", 3);
  102.          }
  103.          else {
  104.             put_text(xoff, yoff, "   Brown's move   ", 4);
  105.          }
  106.       }
  107.    }
  108.    return;
  109. }
  110.  
  111.  
  112. void put_text(x, y, text, c)
  113. int x, y, c;
  114. char *text;
  115. {
  116.    SetAPen(window1->RPort, c);
  117.    TEXT(window1, x, y, text);
  118.    return;
  119. }
  120.  
  121.  
  122. void reset_menu_item(menuitem, newtext)
  123. struct MenuItem *menuitem;
  124. APTR newtext;
  125. {
  126.    ClearMenuStrip(window1);
  127.    menuitem-> ItemFill = newtext;
  128.    SetMenuStrip(window1, &menu1);
  129.  
  130.    return;
  131. }
  132.  
  133.  
  134. void handle_message(message)
  135. struct IntuiMessage *message;
  136. {
  137.    ULONG class;
  138.    USHORT code;
  139.  
  140.    class = message->Class;
  141.    code = message->Code;
  142.  
  143.    if (illegal) {
  144.       illegal = 0;
  145.       put_text(XOFF-2*8-2, YOFF+(MAXY+4)*ROWS+3, "                  ", 0);
  146.    }
  147.  
  148.    switch (class) {
  149.       case GADGETUP     :  up_gadgets();
  150.                            break;
  151.       case MOUSEBUTTONS :  break;
  152.       case CLOSEWINDOW  :  ReplyMsg(message);
  153.                            done(NULL);
  154.                            break;
  155.       case MENUPICK     :
  156.                            handle_menu(code, message);
  157.                            break;
  158.    }
  159.    ReplyMsg(message);
  160.    return;
  161. }
  162.  
  163.  
  164. void handle_menu(code, message)
  165. USHORT code;
  166. struct IntuiMessage *message;
  167. {
  168.    while (code != MENUNULL) {
  169.       switch (MENUNUM(code)) {
  170.          case PROJECT   :  handle_proj(code, message);
  171.                            break;
  172.          case GAME      :  handle_game(code);
  173.       }
  174.       code = ItemAddress(&menu1, code)->NextSelect;
  175.    }
  176.    return;
  177. }
  178.  
  179.  
  180. void handle_proj(code, message)
  181. USHORT code;
  182. struct IntuiMessage *message;
  183. {
  184.    switch (ITEMNUM(code)) {
  185.       case ABOUT  :
  186.                      (void)AutoRequest(window1 , &about1, &positive,
  187.                                        &negative, 0, 0, 38*8, 20*ROWS);
  188.                      break;
  189.       case QUIT   :  ReplyMsg(message);
  190.                      done(NULL);
  191.    }
  192.    return;
  193. }
  194.  
  195.  
  196. void handle_game(code)
  197. USHORT code;
  198. {
  199.    int menu_num;
  200.  
  201.    switch (ITEMNUM(code)) {
  202.       case NEWGAME      :  newgame = 1;
  203.                            put_text(XOFF-7, YOFF, "              ", 0);
  204.                            break;
  205.       case PLAYER2      :  menu_num = SHIFTMENU(GAME) +
  206.                                       SHIFTITEM(FIRSTPLAYER);
  207.                            if (player2 == ME) {
  208.                               player2 = YOU;
  209.                               reset_menu_item(&m2_item2,(APTR)&m2_text2b);
  210.                               OffMenu(window1, menu_num);
  211.                            }
  212.                            else {
  213.                               player2 = ME;
  214.                               reset_menu_item(&m2_item2, (APTR)&m2_text2a);
  215.                               OnMenu(window1, menu_num);
  216.                            }
  217.                            break;
  218.       case FIRSTPLAYER  :
  219.                            if (first_turn == ME) {
  220.                               first_turn = YOU;
  221.                               reset_menu_item(&m2_item3, (APTR)&m2_text3b);
  222.                            }
  223.                            else {
  224.                               first_turn = ME;
  225.                               reset_menu_item(&m2_item3, (APTR)&m2_text3a);
  226.                            }
  227.                            break;
  228.       case INSTRUCTIONS :
  229.                            (void)AutoRequest(window1 , &instr1, &positive,
  230.                                        &negative, 0, 0, 33*8, 10*ROWS);
  231.    }
  232.    return;
  233. }
  234.  
  235.  
  236. void up_gadgets()
  237.  
  238. {
  239.    struct Gadget *igad;
  240.    int   gadget_id;
  241.  
  242.    igad = (struct Gadget *)message -> IAddress;
  243.    gadget_id = igad -> GadgetID;
  244.    polepick = -1;
  245.    switch(gadget_id) {
  246.       case GAD1   :  polepick = 0;
  247.                      break;
  248.       case GAD2   :  polepick = 1;
  249.                      break;
  250.       case GAD3   :  polepick = 2;
  251.                      break;
  252.       case GAD4   :  polepick = 3;
  253.                      break;
  254.       case GAD5   :  polepick = 4;
  255.                      break;
  256.       case GAD6   :  polepick = 5;
  257.                      break;
  258.       case GAD7   :  polepick = 6;
  259.                      break;
  260.       case GAD8   :  polepick = 7;
  261.    }
  262.  
  263.    if ( !finished && polepick >= 0 )   player_move();
  264.  
  265.    return;
  266. }
  267.  
  268.  
  269. int count_em(who, x, y, empty, maybe, pole, onpole)
  270. int who, x, y, *empty, *maybe, pole, onpole;
  271. {
  272.    int count = 0,
  273.        xn, yn;
  274.  
  275.    xn = pole;
  276.    yn = on_pole[pole] - onpole;
  277.    while ( grid[yn += y][xn += x] == who && yn < MAXY && xn < MAXX
  278.            && yn >= 0 && xn >= 0) {
  279.       count++;
  280.    }
  281.    while ( (grid[yn][xn] == NOONE || grid[yn][xn] == who)
  282.            && yn < MAXY && xn < MAXX && yn >= 0 && xn >= 0) {
  283.       (*empty)++;
  284.       if (grid[yn][xn] == who)
  285.          (*maybe)++;
  286.       yn += y;
  287.       xn += x;
  288.    }
  289.  
  290.    return(count);
  291. }
  292.  
  293.  
  294. int in_row(who, x, y, empty, maybe, pole, onpole)
  295. int who, x, y, *empty, *maybe, pole, onpole;
  296. {
  297.    *empty = 0;
  298.    *maybe = 0;
  299.    return( count_em(who, x, y, empty, maybe, pole, onpole)
  300.            + count_em(who, -x, -y, empty, maybe, pole, onpole) + 1 );
  301. }
  302.  
  303.  
  304. int check_win()
  305. {
  306.    int tempret, win, who,
  307.        dum;   /* dummy var */
  308.  
  309.    dum = 0;   /* just to stop C's warning */
  310.    tempret = 0;
  311.    who = turn;
  312.    if (in_row(who, 1, 1, &dum, &dum, polepick, 1) >= 4)  win = 1;
  313.    else if (in_row(who, -1, 1, &dum, &dum, polepick, 1) >= 4)  win = 1;
  314.        else if (in_row(who, 1, 0, &dum, &dum, polepick, 1) >= 4)  win = 1;
  315.            else if(in_row(who, 0, 1, &dum, &dum, polepick, 1) >= 4)  win = 1;
  316.                else  win = 0;
  317.  
  318.    if (win) {
  319.       tempret = 1;
  320.       if (player2 == ME) {
  321.          if (turn == ME) {
  322.             put_text(XOFF+4*8-3, YOFF, "I win", 4);
  323.          }
  324.          else {
  325.             put_text(XOFF+3*8-3, YOFF, "You win", 3);
  326.          }
  327.       }
  328.       else {
  329.          if (turn == YOU) {
  330.             put_text(XOFF+1*8+1, YOFF, "White wins", 3);
  331.          }
  332.          else {
  333.             put_text(XOFF+1*8+1, YOFF, "Brown wins", 4);
  334.          }
  335.       }
  336.    }
  337.    else {
  338.       if (bead_count == MAXX*MAXY) {
  339.          tempret = 1;
  340.          put_text(XOFF-7, YOFF, "It's a tie !!!", 14);
  341.       }
  342.    }
  343.  
  344.    if (tempret) {
  345.       put_text(XOFF-2*8-6, YOFF+(MAXY+3)*ROWS+3, "                   ", 0);
  346.    }
  347.  
  348.    return(tempret);
  349. }
  350.  
  351.  
  352. void illegal_move()
  353. {
  354.    put_text(XOFF-2*8-2, YOFF+(MAXY+4)*ROWS+3, "That column's full", 15);
  355.    DisplayBeep(screen1);
  356.    illegal = 1;
  357.  
  358.    return;
  359. }
  360.  
  361.  
  362. void get_possibles(who, pole, onpole)
  363. int who, pole, onpole;
  364. {
  365.    int dir;
  366.  
  367.    inrow[0] = in_row(who, 1, 1, &empty[0], &maybe[0], pole, onpole);
  368.    inrow[1] = in_row(who, -1, 1, &empty[1], &maybe[1], pole, onpole);
  369.    inrow[2] = in_row(who, 0, 1, &empty[2], &maybe[2], pole, onpole);
  370.    inrow[3] = in_row(who, 1, 0, &empty[3], &maybe[3], pole, onpole);
  371.    for (dir = 0; dir < 4; dir++) {
  372.       possibles[dir] = 0;
  373.    }
  374.    for (dir = 0; dir < 4; dir++) {
  375.       if (inrow[dir] >3) {
  376.          possibles[3] = 5;
  377.       }
  378.       else {
  379.          if (empty[dir] + inrow[dir] >= 4) {
  380.             possibles[inrow[dir]-1]++;
  381.          }
  382.       }
  383.    }
  384.    return;
  385. }
  386.  
  387.  
  388. int best_move(who, pole, otherhigh, bad)
  389. int who, pole, otherhigh, *bad;
  390. {
  391.    int inrow, temp_high, mult;
  392.  
  393.    get_possibles(who, pole, 0);
  394.    inrow = 3;
  395.    temp_high = possibles[inrow];
  396.    while (temp_high < 1 && inrow > 0) {
  397.       inrow--;
  398.       temp_high = possibles[inrow];
  399.    }
  400.    if (inrow == 0) mult = 1;
  401.    else if (inrow == 1) mult = 4;
  402.    else if (inrow == 2) mult = 13;
  403.    else mult = 40;
  404.    temp_high *= mult;
  405.  
  406. /* try not to set up the player for a win */
  407.  
  408.    if (who == YOU && temp_high < 100
  409.        && otherhigh < 100 && on_pole[pole] < MAXY-1) {
  410.       get_possibles(YOU, pole, -1);
  411.       if (possibles[3] > 4) {
  412.          *bad = 1;
  413.          temp_high = 0;
  414.       }
  415.    }
  416.  
  417.    return(temp_high);
  418. }
  419.  
  420.  
  421. int random_move()
  422. {
  423.    int pole;
  424.  
  425.    while (on_pole[(pole = rand()&7)] >= MAXY)  ;
  426.    return(pole);
  427. }
  428.  
  429.  
  430. void my_move()
  431. {
  432.    int high_move, polenum, move, block, badmoves, bad, winmove;
  433.  
  434.    high_move = 0;
  435.    badmoves = 1;
  436.    winmove = 0;
  437.    for (polenum = 0; polenum < MAXX; polenum++) {
  438.       if (on_pole[polenum] < MAXY) {
  439.          bad = 0;
  440.          if ((move = best_move(ME, polenum, 0, &bad)) >100) {
  441.             if (!winmove || (winmove && rand() < rand() )) {
  442.                winmove = 1;
  443.                high_move = move;
  444.                badmoves = 0;
  445.                polepick = polenum;
  446.             }
  447.          }
  448.          else if (!winmove) {
  449.             block = best_move(YOU, polenum, move, &bad);
  450.             if (block > move || bad)
  451.                move = block;
  452.             if (move > high_move || ( move == high_move && move > 0 &&
  453.                 rand() < rand() )) {
  454.                high_move = move;
  455.                badmoves = 0;
  456.                polepick = polenum;
  457.             }
  458.          }
  459.       }
  460.    }
  461.    if (badmoves) {
  462.       polepick = random_move();
  463.    }
  464.    set_ball(ME);
  465.    if (check_win()) finished = 1;
  466.    else  turn = YOU;
  467.  
  468.    return;
  469. }
  470.  
  471.  
  472. void set_ball(who)
  473. int who;
  474. {
  475.    struct Image *image_ptr;
  476.    int i, j;
  477.  
  478.    j = polepick;
  479.    i = on_pole[j];
  480.  
  481.    grid[i][j] = who;
  482.    switch (who) {
  483.             case YOU     : if (i)   image_ptr = &ball_1;
  484.                            else     image_ptr = &base_ball_1;
  485.                            break;
  486.             case ME      : if (i)   image_ptr = &ball_2;
  487.                            else     image_ptr = &base_ball_2;
  488.          }
  489.    DrawImage(window1->RPort, image_ptr,
  490.              XOFF+j*COLS, YOFF+(MAXY-i-1)*(ROWS-1)+MAXY-1);
  491.    on_pole[polepick] += 1;
  492.    bead_count += 1;
  493.  
  494.    return;
  495. }
  496.  
  497.  
  498. void player_move()
  499. {
  500.    if (on_pole[polepick] >= MAXY)   illegal_move();
  501.    else {
  502.       if ( turn == YOU )
  503.          set_ball(YOU);
  504.       else
  505.          set_ball(ME);     /* ME is player2 in two player mode */
  506.       if (check_win() ) finished = 1;
  507.       else  if ( (turn += 1) > 1) turn = 0;
  508.    }
  509.    return;
  510. }
  511.  
  512.  
  513. void open_libraries()
  514. {
  515.    if ((IntuitionBase = (struct IntuitionBase *)
  516.       OpenLibrary("intuition.library",I_REV)) == NULL) done(2);
  517.    if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",G_REV))
  518.       == NULL) done(3);
  519.    oldview = GfxBase -> ActiView;
  520.    return;
  521. }
  522.  
  523.  
  524. void done(s)
  525. SHORT s;
  526. {
  527.    if (window1)   {
  528.       ClearMenuStrip(window1);
  529.       CloseWindow(window1);
  530.    }
  531.    if (screen1)   {
  532.       CloseScreen(screen1);
  533.       LoadView(oldview);
  534.    }
  535.    if (colormap != NULL) FreeColorMap(colormap);
  536.    if (GfxBase) CloseLibrary(GfxBase);
  537.    if (IntuitionBase) CloseLibrary(IntuitionBase);
  538.  
  539.    if (s) {
  540.       printf("Error #%d",s);
  541.    }
  542.  
  543.    exit(s);
  544. }
  545.  
  546.  
  547. void clear_grid()
  548. {
  549.    int i, j;
  550.    for (i=0; i<MAXX; i++) {
  551.       for (j=0; j<MAXY; j++) {
  552.          grid [i][j] = NOONE;
  553.       }
  554.    }
  555.    return;
  556. }
  557.  
  558.  
  559. void clear_square()
  560. {
  561.    DrawImage(window1->RPort, &clear_block, XOFF, YOFF);
  562.    return;
  563. }
  564.  
  565.  
  566. void draw_grid()
  567. {
  568.    int i, j;
  569.    struct Image *image_ptr;
  570.  
  571.    for (i=0 ; i<MAXY; i++) {
  572.       for (j=0; j<MAXX; j++) {
  573.          switch (grid [i][j]) {
  574.             case NOONE   : image_ptr = &pole;
  575.                            break;
  576.             case YOU     : if (i)   image_ptr = &ball_1;
  577.                            else     image_ptr = &base_ball_1;
  578.                            break;
  579.             case ME      : if (i)   image_ptr = &ball_2;
  580.                            else     image_ptr = &base_ball_2;
  581.          }
  582.          DrawImage(window1->RPort, image_ptr,
  583.                    XOFF+j*COLS, YOFF+(MAXY-i-1)*(ROWS-1)+MAXY-1);
  584.       }
  585.    }
  586.    return;
  587. }
  588.  
  589.  
  590. void draw_base()
  591. {
  592.    DrawImage(window1->RPort, &base_top, XOFF-5, YOFF+MAXY*ROWS-5);
  593.    DrawImage(window1->RPort, &base_bot, XOFF-15, YOFF+MAXY*ROWS+5);
  594.    DrawImage(window1->RPort, &top_left, XOFF-15, YOFF+MAXY*ROWS-5);
  595.    DrawImage(window1->RPort, &end_rect, XOFF-15, YOFF+MAXY*ROWS+5);
  596.    DrawImage(window1->RPort, &bot_left, XOFF-15, YOFF+MAXY*ROWS+15);
  597.    DrawImage(window1->RPort, &top_right,XOFF+MAXX*COLS+5, YOFF+MAXY*ROWS-5);
  598.  
  599.    DrawBorder(window1->RPort, &line1, 0*COLS, 0);
  600.    DrawBorder(window1->RPort, &line1, 1*COLS, 0);
  601.    DrawBorder(window1->RPort, &line1, 2*COLS, 0);
  602.    DrawBorder(window1->RPort, &line1, 3*COLS, 0);
  603.    DrawBorder(window1->RPort, &line1, 4*COLS, 0);
  604.    DrawBorder(window1->RPort, &line1, 5*COLS, 0);
  605.    DrawBorder(window1->RPort, &line1, 6*COLS, 0);
  606.    DrawBorder(window1->RPort, &line1, 7*COLS, 0);
  607.  
  608.    RefreshGadgets(&Gadget1, window1, NULL);
  609.  
  610.    return;
  611. }
  612.  
  613.  
  614. void initialize()
  615. {
  616.    open_libraries();
  617.  
  618.    font = &Font80;
  619.  
  620.    init_images();
  621.    init_menus();
  622.    init_gadgets();
  623.    init_display(80*W, 20*H, 160*W, 148*H, 4, "Four in a Row");
  624.  
  625.    player2 = 0;
  626.    first_turn = YOU;
  627.    newgame = 1;
  628.  
  629.    return;
  630. }
  631.  
  632.  
  633. void setup()
  634. {
  635.    int i;
  636.  
  637.    newgame = 0;
  638.    clear_grid();
  639.    clear_square();
  640.    draw_base();
  641.    draw_grid();
  642.    turn = first_turn;
  643.    bead_count = 0;
  644.    finished = 0;
  645.    for (i=0; i<MAXY; i++) {
  646.       on_pole[i] = 0;
  647.    }
  648.    illegal = 0;
  649.  
  650.    return;
  651. }
  652.