SAI || Sommersemester 1997 || Systemnahe Software II || Übungen

<- Alle Module

Lösung zu Blatt 5 (Aufgabe 6): gbsess.h + gbsess.c

Steuerung einer Gobang-Sitzung.

gbsess.h

/*
 *      gbsess.h        - headerfile for Gobang session driver
 *
 *      Martin Hasch, University of Ulm, June 1997
 */

typedef enum { CLIENT_BLACK, CLIENT_WHITE, CLIENT_KIBITZ } SessionMode;

/*
 *      Gobang session.  (server_id) identifies server process.
 */
void session(SessionMode mode, int server_id);

gbsess.c

/*
 *      gbsess.c        - Gobang session driver
 *
 *      Martin Hasch, University of Ulm, June 1997
 */

#include        <stdio.h>
#include        <stdlib.h>
#include        "gbmesg.h"
#include        "gbuser.h"
#include        "gbdisp.h"
#include        "gbsess.h"

static unsigned boardsize = 0;
static unsigned lastx = 0;
static unsigned lasty = 0;

/*
 *      First stage of a session:  Establish connection and get board size.
 */
static void prepare(SessionMode mode, int server_id)
{
        unsigned request;
        Message message;

        switch ( mode ) {
        case CLIENT_BLACK:
                request = RQ_SIGNON_BLACK;
                printf("playing black stones\n");
                break;
        case CLIENT_WHITE:
                request = RQ_SIGNON_WHITE;
                printf("playing white stones\n");
                break;
        case CLIENT_KIBITZ:
                request = RQ_SIGNON_KIBITZ;
                printf("watching without playing\n");
                break;
        default:
                abort();                /* should not happen */
        }
        printf("trying to contact server (id %d)\n", server_id);
        if ( !mesg_init(server_id) || !mesg_sendrequest(request, 0, 0) ||
                        !mesg_receive(&message) ) {
                printf("connection failed\n");
                exit(1);
        }
        if ( message.m_code != MSG_SIZE ) {
                printf("connection refused\n");
                exit(1);
        }
        boardsize = message.m_y;
        printf("connection established, board size %u\n", boardsize);
}

/*
 *      Transmission of a request.  Returns only on success.
 */
static void send(code, x, y)
{
        if ( !mesg_sendrequest(code, x, y) ) {
                gb_status("connection broken");
                exit(1);
        }
}

/*
 *      Elicit a move from the user.
 */
static void getmove(void)
{
        (void) gb_goto(lastx, lasty);                   /* switch cursor on */
        for (;;) {
                switch ( gb_getcommand() ) {
                case GBU_QUIT:
                        send(RQ_RESIGN, 0, 0);
                        return;
                case GBU_LEFT:
                        if ( gb_goto(lastx-1, lasty) == GB_OK )
                                --lastx;
                        break;
                case GBU_DOWN:
                        if ( gb_goto(lastx, lasty-1) == GB_OK )
                                --lasty;
                        break;
                case GBU_UP:
                        if ( gb_goto(lastx, lasty+1) == GB_OK )
                                ++lasty;
                        break;
                case GBU_RIGHT:
                        if ( gb_goto(lastx+1, lasty) == GB_OK )
                                ++lastx;
                        break;
                case GBU_REDRAW:
                        gb_redraw();
                        break;
                case GBU_MOVE:
                        send(RQ_MOVE, lastx, lasty);
                        return;
                case GBU_PASS:
                        send(RQ_MOVE, 0, 0);
                        return;
                default:
                        /* ignore */
                        break;
                }
        }
}

/*
 *      Update screen and data structures when a move has been reported.
 */
static void do_move(unsigned x, unsigned y, int color)
{
        if ( x || y ) {                         /* not a pass? */
                lastx = x;
                lasty = y;
                gb_set(lastx, lasty, color);
        }
        if ( color == 1 || color == 2 )
                gb_turn(1+2 - color);
}

/*
 *      Main loop:  React (mostly) on server messages during the game.
 */
static void mainloop(void)
{
        Message message;
        int badmove;

        badmove = 0;
        for (;;) {
                (void) gb_goto(0,0);            /* hide cursor */
                gb_status("waiting for remote action");
                if ( !mesg_receive(&message) ) {
                        gb_status("connection broken");
                        exit(1);
                }
                switch ( message.m_code ) {
                case MSG_DRAW:
                        gb_status("game is a draw!");
                        return;
                case MSG_BLACK_WINS:
                        gb_status("winner is black!");
                        return;
                case MSG_WHITE_WINS:
                        gb_status("winner is white!");
                        return;
                case MSG_ABORT:
                        gb_status("game aborted!");
                        return;
                case MSG_TOGGLE_EMPTY:
                        do_move(message.m_x, message.m_y, 0);
                        badmove = 0;
                        continue;
                case MSG_TOGGLE_BLACK:
                        do_move(message.m_x, message.m_y, 1);
                        badmove = 0;
                        continue;
                case MSG_TOGGLE_WHITE:
                        do_move(message.m_x, message.m_y, 2);
                        badmove = 0;
                        continue;
                case MSG_YOUR_TURN:
                        if ( badmove )
                                gb_status("illegal move, try again");
                        else
                                gb_status("enter your move");
                        break;
                case MSG_ILLEGAL_MOVE:
                        badmove = 1;
                        continue;
                default:
                        /* ignore rubbish */
                        continue;
                }
                getmove();
        }
}

/*
 *      Gobang session.  (server_id) identifies server process.
 */
void session(SessionMode mode, int server_id)
{
        prepare(mode, server_id);
        /*
         *      We enter graphical mode only after a connection to the
         *      server has been established.
         */
        if ( gb_reset(boardsize) != GB_OK ) {
                printf("cannot handle board size %u, sorry\n", boardsize);
                (void) mesg_sendrequest(RQ_SIGNOFF, 0, 0);
                exit(1);
        }
        lastx = lasty = (gb_size()+1) >> 1;
        gb_turn(1);
        mainloop();
}
<- Alle Module
SAI || Sommersemester 1997 || Systemnahe Software II || Übungen

Martin Hasch, Juni 1997