Logo Search packages:      
Sourcecode: vgagamespack version File versions

c4linux.c

/*
 * ConnectN
 *
 * Copyright (C) Evan Harris, 1994-1998.
 *
 * Permission is granted to freely redistribute and modify this code,
 * providing the author(s) get credit for having written it.
 */

#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <time.h>
#include <unistd.h>
#include <vga.h>
#ifndef NOMOUSE
#include <vgamouse.h>
#endif

#include "c4.h"
#include "c4chip.h"
#include "vga16.h"
#include "mouse.h"
#include "key.h"


#if !defined(CLOCKS_PER_SECOND) && defined(CLOCKS_PER_SEC)
#define CLOCKS_PER_SECOND CLOCKS_PER_SEC
#endif

#define SCREENMODE G640x480x16
#define SCREENWIDTH 640
#define SCREENHEIGHT 480

#define BOARDWIDTH 552
#define BOARDHEIGHT SCREENHEIGHT

#define VERSION "Connect%d\n  v1.4"
#define VERSIONLEFT (SCREENWIDTH - 72)
#define VERSIONBOTTOM 200

#define QUITLEFT (SCREENWIDTH - 80)
#define QUITBOTTOM 76
#define QUITTOP (QUITBOTTOM - 15)
#define QUITRIGHT (QUITLEFT + 79)

#define NEWGAMELEFT QUITLEFT
#define NEWGAMEBOTTOM 48
#define NEWGAMETOP (NEWGAMEBOTTOM - 15)
#define NEWGAMERIGHT (NEWGAMELEFT + 79)

#define WINLEFT (SCREENWIDTH - 72)
#define WINBOTTOM 280

#define MOUSEKEYMOVE 8

#define PALETTESIZE 7

int palette[PALETTESIZE * 3] = {
    0x00, 0x00, 0x00,         /* black */
    0x00, 0x00, 0x30,         /* blue */
    0x30, 0x00, 0x00,         /* red */
    0x3f, 0x3f, 0x00,         /* yellow */
    0x3f, 0x3f, 0x3f,         /* white */
    0x20, 0x20, 0x20,         /* grey */
    0x00, 0x30, 0x00,         /* green */
};

#define TEXTFG 4
#define TEXTBG 0
#define BUTTONFG 0
#define BUTTONBG 5
#define BOARDFG 1
#define BOARDBG 0
#define THINKFG 5
#define THINKBG 0
#define BASEFG 6
#define MOUSEFG 6
#define MOUSEDARKFG 5

int turnfg[2] = {
    2, 3,
};

#define MINWIDTH 5
#define MAXWIDTH 21

#define NEWGAME -1
#define QUIT -2
#define UNKNOWN -8
#define ILLEGAL -9
#define DROP_CHIP(move) ((move) >= 0)

#ifndef MOUSESAMPLERATE
#define MOUSESAMPLERATE MOUSE_DEFAULTSAMPLERATE
#endif

#define USLEEP_TIME 30000


static int columnthickness, columnleftedge, columntopedge;
static int columnheight, columns;
static int incolumn[MAXWIDTH];


void
NewGame(int width, int height)
{
    int w, h, l, x, y;
    
    if (columnthickness < 16) {
      for (w = 0; w < width; w++) {
          for (h = 0; h < height; h++) {
            x = columnleftedge + (3 * w + 1) * columnthickness;
            y = columntopedge + (3 * h + 1) * columnthickness;
            for (l = 0; l < 2 * columnthickness; l++) {
                vga16_drawscansegment(smallchiplines[smallchip[2][l]],
                                x, y++, 2 * columnthickness);
            }
          }
          incolumn[w] = 0;
      }
    } else {
      for (w = 0; w < width; w++) {
          for (h = 0; h < height; h++) {
            x = columnleftedge + (3 * w + 1) * columnthickness;
            y = columntopedge + (3 * h + 1) * columnthickness;
            for (l = 0; l < 2 * columnthickness; l++) {
                vga16_drawscansegment(bigchiplines[bigchip[2][l]], x, y++,
                                2 * columnthickness);
            }
          }
          incolumn[w] = 0;
      }
    }
    vga16_text(WINLEFT, WINBOTTOM, "        ", TEXTFG, TEXTBG);
}


void
InitDisplay(int width, int height, int connectnum, int reverse)
{
    int thick, i, l, t;
    char versionstr[20];

    vga_disabledriverreport();
    vga_init();
#if !defined(USEMOUSEFUNCS) && !defined(NOMOUSE)
    vga_setmousesupport(1);
#endif

    if (vga_setmode(SCREENMODE) != 0) {
      fprintf(stderr, "Mode %s not available!\n",
            vga_getmodename(SCREENMODE));
      exit(1);
    }

#if defined(USEMOUSEFUNCS) && !defined(NOMOUSE)
    mouse_init("/dev/mouse", vga_getmousetype(), MOUSESAMPLERATE);
    mouse_setxrange(0, SCREENWIDTH - 1);
    mouse_setyrange(0, SCREENHEIGHT - 1);
    mouse_setwrap(MOUSE_NOWRAP);
#endif

    vga16_init();

    vga_setpalvec(0, PALETTESIZE, &palette[0]);

    vga16_text(NEWGAMELEFT, NEWGAMEBOTTOM, " NEW GAME ", BUTTONFG, BUTTONBG);
    vga16_text(QUITLEFT, QUITBOTTOM, "   QUIT   ", BUTTONFG, BUTTONBG);
    sprintf(versionstr, VERSION, connectnum);
    vga16_text(VERSIONLEFT, VERSIONBOTTOM, versionstr, TEXTFG, TEXTBG);

    thick = 16;
    if (((width + 1) * thick + width * 2 * thick > BOARDWIDTH)
      || ((height + 1) * thick + height * 2 * thick > BOARDHEIGHT)) {
      thick = 8;
    }

    columnthickness = thick;
    columnleftedge = (((BOARDWIDTH - ((width + 1) * thick + width * 2 * thick))
                   / 2) / 8) * 8;
    columntopedge =
      (BOARDHEIGHT - ((height + 1) * thick + height * 2 * thick)) / 2;
    columnheight = height;
    columns = width;

    vga16_filledblock(columnleftedge, columntopedge,
                  columnleftedge + (3 * width + 1) * thick - 1,
                  columntopedge + (3 * height + 1) * thick - 1,
                  BOARDFG);
    if (columnleftedge - thick >= 0
      && columnleftedge + (3 * width + 2) * thick <= BOARDWIDTH
      && columntopedge + (3 * height + 3) * thick <= BOARDHEIGHT) {
      vga16_filledblock(columnleftedge - thick,
                    columntopedge + (3 * height + 2) * thick,
                    columnleftedge - 1,
                    columntopedge + (3 * height + 3) * thick - 1,
                    BOARDFG);
      vga16_filledblock(columnleftedge + (3 * width + 1) * thick,
                    columntopedge + (3 * height + 2) * thick,
                    columnleftedge + (3 * width + 2) * thick - 1,
                    columntopedge + (3 * height + 3) * thick - 1,
                    BOARDFG);
    }
    if (columntopedge + (3 * height + 3) * thick <= BOARDHEIGHT) {
      vga16_filledblock(columnleftedge,
                    columntopedge + (3 * height + 1) * thick,
                    columnleftedge + thick - 1,
                    columntopedge + (3 * height + 3) * thick - 1,
                    BOARDFG);
      vga16_filledblock(columnleftedge + 3 * width * thick,
                    columntopedge + (3 * height + 1) * thick,
                    columnleftedge + (3 * width + 1) * thick - 1,
                    columntopedge + (3 * height + 3) * thick - 1,
                    BOARDFG);
      vga16_filledblock(0, columntopedge + (3 * height + 3) * thick,
                    BOARDWIDTH - 1, BOARDHEIGHT - 1, BASEFG);
    }

    NewGame(width, height);

    for (i = 0; i < width; i++) {
      incolumn[i] = 0;
    }

    if (reverse) {
      if (thick < 16) {
          for (i = 0; i < 15; i++) {
            for (l = 0; l < 2 * thick; l++) {
                if (smallchiplines[i][l] == turnfg[0]) {
                  smallchiplines[i][l] = turnfg[1];
                } else if (smallchiplines[i][l] == turnfg[1]) {
                  smallchiplines[i][l] = turnfg[0];
                }
            }
          }
      } else {
          for (i = 0; i < 30; i++) {
            for (l = 0; l < 2 * thick; l++) {
                if (bigchiplines[i][l] == turnfg[0]) {
                  bigchiplines[i][l] = turnfg[1];
                } else if (bigchiplines[i][l] == turnfg[1]) {
                  bigchiplines[i][l] = turnfg[0];
                }
            }
          }
      }
      t = turnfg[0];
      turnfg[0] = turnfg[1];
      turnfg[1] = t;
    }
}


void
EndDisplay()
{
    vga_setmode(TEXT);
#if defined(USEMOUSEFUNCS) && !defined(NOMOUSE)
    mouse_close();
#endif    
}


static int oldx = -1, oldy, oldcolour[40];

void
MakeMove(int turn, int move)
{
    int x, y, l;

    if (incolumn[move] < columnheight) {
      if (oldx != -1) {
          RestoreUnderMousePointer(oldx, oldy, SCREENWIDTH, SCREENHEIGHT,
                             oldcolour);
      }

      incolumn[move]++;
      x = columnleftedge + (3 * move + 1) * columnthickness;
      y = columntopedge
          + (3 * (columnheight - incolumn[move]) + 1) * columnthickness;
      if (columnthickness < 16) {
          for (l = 0; l < 2 * columnthickness; l++) {
            vga16_drawscansegment(smallchiplines[smallchip[turn][l]],
                              x, y++, 2 * columnthickness);
          }
      } else {
          for (l = 0; l < 2 * columnthickness; l++) {
            vga16_drawscansegment(bigchiplines[bigchip[turn][l]], x, y++,
                              2 * columnthickness);
          }
      }

      if (oldx != -1) {
          SaveUnderMousePointer(oldx, oldy, SCREENWIDTH, SCREENHEIGHT,
                          oldcolour);
          RenderMousePointer(oldx, oldy, MOUSEFG, MOUSEDARKFG,
                         SCREENWIDTH, SCREENHEIGHT);
      }
    }
}


void
ShowWin(int turn)
{
    if (turn) {
      vga16_text(WINLEFT, WINBOTTOM, " I WIN!", turnfg[turn], TEXTBG);
    } else {
      vga16_text(WINLEFT, WINBOTTOM, "YOU WIN!", turnfg[turn], TEXTBG);
    }
}


void
ShowTie()
{
    vga16_text(WINLEFT, WINBOTTOM, " A TIE!", TEXTFG, TEXTBG);
}


static long thinktime;

void
ThinkingOn()
{
    thinktime = clock();
    
    vga16_text(WINLEFT, WINBOTTOM, "THINKING", THINKFG, THINKBG);
    vga_runinbackground(1);
}


void
ThinkingOff()
{
    char buf[10];
    int timetaken = clock() - thinktime;

    while (!vga_oktowrite()) {
      usleep(100000);         /* 1/10 sec */
    }
    vga_runinbackground(0);
    vga16_text(WINLEFT, WINBOTTOM, "        ", THINKFG, THINKBG);
    sprintf(buf, "%.2fs", (double)timetaken / CLOCKS_PER_SECOND);
    vga16_text(WINLEFT + 4 * (8 - strlen(buf)), WINBOTTOM, buf,
             THINKFG, THINKBG);
}


void
MoveMousePointer(int x, int y)
{
    if (x != oldx || y != oldy) {
      if (oldx != -1) {
          RestoreUnderMousePointer(oldx, oldy, SCREENWIDTH, SCREENHEIGHT,
                             oldcolour);
      }
      SaveUnderMousePointer(x, y, SCREENWIDTH, SCREENHEIGHT, oldcolour);
      RenderMousePointer(x, y, MOUSEFG, MOUSEDARKFG, SCREENWIDTH,
                     SCREENHEIGHT);
      oldx = x;
      oldy = y;
    }
}


int
ParseMousePosition(int x, int y)
{
    int move;
    
    if (x >= NEWGAMELEFT && x <= NEWGAMERIGHT
      && y >= NEWGAMETOP && y <= NEWGAMEBOTTOM) {
      return NEWGAME;
    } else if (x >= QUITLEFT && x <= QUITRIGHT
             && y >= QUITTOP && y <= QUITBOTTOM) {
      return QUIT;
    } else if ((x - columnleftedge) % (columnthickness * 3)
             >= columnthickness) {
      move = ((x - columnleftedge - columnthickness)
            / (3 * columnthickness));
      if (move >= columns) {
          return UNKNOWN;
      }
      return move;
    }

    return UNKNOWN;
}


int
GetMove(int width, int height)
{
    int move = UNKNOWN, key;

#if !defined(NOMOUSE)
    int x, y, button;
    
    if (oldx == -1) {
      x = mouse_getx();
      y = mouse_gety();
      MoveMousePointer(x, y);
    }
#else
    MoveMousePointer(0, 0);
#endif
    
    while (move == UNKNOWN) {
      usleep(USLEEP_TIME);    /* don't chew up as much CPU */
      
#if !defined(NOMOUSE)
      if (mouse_update()) {
          x = mouse_getx();
          y = mouse_gety();
          button = mouse_getbutton();

          MoveMousePointer(x, y);

          if (button & MOUSE_LEFTBUTTON) {
            move = ParseMousePosition(x, y);
          }
      }
#endif

      if ((key = key_getkey()) != -1 ) {
          switch (key) {
            case 'n':
            case 'N':
            move = NEWGAME;
            break;
            case 'q':
            case 'Q':
            move = QUIT;
            break;
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            move = key - '1';
            if (move >= width || incolumn[move] == height) {
                move = ILLEGAL;
            }
            break;
            case KEY_CURSORUP:
            if (oldy >= MOUSEKEYMOVE) {
                MoveMousePointer(oldx, oldy - MOUSEKEYMOVE);
            }
            break;
            case KEY_CURSORDOWN:
            if (oldy < SCREENHEIGHT - MOUSEKEYMOVE) {
                MoveMousePointer(oldx, oldy + MOUSEKEYMOVE);
            }
            break;
            case KEY_CURSORLEFT:
            if (oldx >= MOUSEKEYMOVE) {
                MoveMousePointer(oldx - MOUSEKEYMOVE, oldy);
            }
            break;
            case KEY_CURSORRIGHT:
            if (oldx < SCREENWIDTH - MOUSEKEYMOVE) {
                MoveMousePointer(oldx + MOUSEKEYMOVE, oldy);
            }
            break;
            case '\n':
            move = ParseMousePosition(oldx, oldy);
            break;
            case '\014':
            case 'r':
            case 'R':
            vga16_redrawscreen();
            break;
            default:
            break;
          }
      }

      if (DROP_CHIP(move) && incolumn[move] == height) {
          move = ILLEGAL;
      }
    }

    return move;
}


void
Poll()
{
    int key, move;
#if !defined(NOMOUSE)
    int x, y, button;
#endif
    
    if (!vga_oktowrite()) {
      return;
    }
    
#if !defined(NOMOUSE)    
    if (mouse_update()) {
      x = mouse_getx();
      y = mouse_gety();
      button = mouse_getbutton();

      MoveMousePointer(x, y);

      if (button & MOUSE_LEFTBUTTON) {
          move = ParseMousePosition(x, y);
          if (move == QUIT) {
            EndDisplay();
            exit(0);
          }
      }
    }
#endif

    if ((key = key_getkey()) != -1 ) {
      switch (key) {
        case 'q':
        case 'Q':
          EndDisplay();
          exit(0);
        case KEY_CURSORUP:
          if (oldy >= MOUSEKEYMOVE) {
            MoveMousePointer(oldx, oldy - MOUSEKEYMOVE);
          }
          break;
        case KEY_CURSORDOWN:
          if (oldy < SCREENHEIGHT - MOUSEKEYMOVE) {
            MoveMousePointer(oldx, oldy + MOUSEKEYMOVE);
          }
          break;
        case KEY_CURSORLEFT:
          if (oldx >= MOUSEKEYMOVE) {
            MoveMousePointer(oldx - MOUSEKEYMOVE, oldy);
          }
          break;
        case KEY_CURSORRIGHT:
          if (oldx < SCREENWIDTH - MOUSEKEYMOVE) {
            MoveMousePointer(oldx + MOUSEKEYMOVE, oldy);
          }
          break;
        case '\n':
          move = ParseMousePosition(oldx, oldy);
          if (move == QUIT) {
            EndDisplay();
            exit(0);
          }
          break;
        case '\014':
        case 'r':
        case 'R':
          vga16_redrawscreen();
          break;
        default:
          break;
      }
    }
}


static struct option long_options[] = {
    { "computer-first", 0, NULL, 'c' },
    { "height", 1, NULL, 'h' },
    { "intelligence", 1, NULL, 'i' },
    { "connect-number", 1, NULL, 'n' },
    { "reverse-colors", 0, NULL, 'r' },
    { "reverse-colours", 0, NULL, 'r' },
    { "width", 1, NULL, 'w' },
    { "help", 0, NULL, 'H' }
};


int
main(int argc, char **argv)
{
    int computerfirst = 0, height = 6, width = 7, connectnum = 4;
    int intelligence = 5, reverse = 0;
    int turn, move, gameover, end = 0;
    int c, err = 0;
    int option_index;
    
    while ((c = getopt_long(argc, argv, "ch:i:n:rw:H",
                      long_options, &option_index)) != -1) {
      switch (c) {
        case 'c':
          computerfirst = 1;
          break;
        case 'h':
          height = atoi(optarg);
          if (height < 4 || height > 19) {
            err++;
          }
          break;
        case 'i':
          intelligence = atoi(optarg);
          if (intelligence < 1 || intelligence > 10) {
            err++;
          }
          break;
        case 'n':
          connectnum = atoi(optarg);
          if (connectnum < 3 || connectnum > 10) {
            err++;
          }
          break;
        case 'r':
          reverse = TRUE;
          break;
        case 'w':
          width = atoi(optarg);
          if (width < MINWIDTH || height > MAXWIDTH) {
            err++;
          }
          break;
        case 'H':
        case '?':
          err++;
          break;
      }
    }
    if (err) {
      fprintf(stderr, "Usage: %s [-c] [-h N] [-i N] [-n N] [-r] [-w N] [-H]\n",
            argv[0]);
      fprintf(stderr, "  -c     --computer-first     computer plays first\n");
      fprintf(stderr, "  -h N   --height             set board height to N (4-19), default: 6\n");
      fprintf(stderr, "  -i N   --intelligence=N     computer intelligence level (1-10), default: 5\n");
      fprintf(stderr, "  -n N   --connect-number=N   set number to connect to N (3-10), default: 4\n");
      fprintf(stderr, "  -r     --reverse-colours    reverse chip colours\n");
      fprintf(stderr, "  -w N   --width=N            set board width to N (%d-%d), default: 7\n",
            MINWIDTH, MAXWIDTH);
      fprintf(stderr, "  -H     --help               print this help message\n");
      exit(EXIT_FAILURE);
    }

    InitDisplay(width, height, connectnum, reverse);

    poll(Poll, 0);
    
    new_game(width, height, connectnum);
    turn = computerfirst;
    gameover = 0;

    while (!end) {
      if (turn) {
          ThinkingOn();
          move = automatic_move(turn, intelligence);
          ThinkingOff();
          MakeMove(turn, move);
      } else {
          move = GetMove(width, height);
          switch (move) {
            case NEWGAME:
            end_game();
            new_game(width, height, connectnum);
            NewGame(width, height);
            turn = !computerfirst; /* changed below */
            gameover = 0;
            break;
            case QUIT:
            end = 1;
            break;
            case ILLEGAL:
            break;
            default:
            if (!gameover) {
                make_move(turn, move);
                MakeMove(turn, move);
            }
            break;
          }
      }
      if (move != ILLEGAL && !gameover) {
          if (is_winner(turn) || is_tie()) {
            if (is_winner(turn)) {
                ShowWin(turn);
            } else {
                ShowTie();
            }
            turn = 0;
            gameover = 1;
          } else {
            turn = !turn;
          }
      }
    }

    EndDisplay();

    return 0;
}

Generated by  Doxygen 1.6.0   Back to index