Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

C-Kurs/TicTacToe/Musterlösung

#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>

#define ROWS    3
#define COLS    3

#define EMPTY      -1
#define PLAYER_A    0
#define PLAYER_B    1

// Spielfeld definieren
int board[ROWS][COLS];

// Konvertiert Mauskoordinaten in Spielfeldkoordinaten
void convert_coords(int x, int y, int *row, int *column) {
    *row = (y-25) / 100;
    if (*row < 0) *row = 0;
    if (*row >= ROWS) *row = ROWS-1;
    *column = (x-25) / 100;
    if (*column < 0) *column = 0;
    if (*column >= COLS) *column = COLS-1;
}

// Zeichnet das Spielfeld
void draw_board(SDL_Surface *back, SDL_Surface *circle, SDL_Surface *cross) {
    SDL_BlitSurface(back, NULL, SDL_GetVideoSurface(), NULL);

    SDL_Rect offset;
    int row, col;
    for (row=0; row<ROWS; row++) {
        for (col=0; col<COLS; col++) {
            offset.x = 25+100*col;
            offset.y = 25+100*row;
            if (board[row][col] == PLAYER_A) {
                SDL_BlitSurface(circle, NULL, SDL_GetVideoSurface(), &offset);
            } else if (board[row][col] == PLAYER_B) {
                SDL_BlitSurface(cross, NULL, SDL_GetVideoSurface(), &offset);
            }
        }
    }

    SDL_Flip(SDL_GetVideoSurface());
}

// Gibt 1 zurück, falls der übergebene Spieler gewonnen hat, andernfalls 0
int check_win(int player) {
    int row, col;
    // horizontal
    for (row=0; row<ROWS; row++) {
        if ((board[row][0] == player) && (board[row][1] == player) && (board[row][2] == player))
            return 1;
    }
    
    // vertikal
    for (col=0; col<COLS; col++) {
        if ((board[0][col] == player) && (board[1][col] == player) && (board[2][col] == player))
            return 1;
    }
    
    // diagonal 1
    if ((board[0][0] == player) && (board[1][1] == player) && (board[2][2] == player)) {
        return 1;
    }
    
    // diagonal 2
    if ((board[0][2] == player) && (board[1][1] == player) && (board[2][0] == player)) {
        return 1;
    }
    
    return 0;
}

void reset_board() {
    int row, col;
    for (row=0; row<ROWS; row++) {
        for (col=0; col < COLS; col++) {
            board[row][col] = EMPTY;
        }
    }
}

int wait_for_click() {
    SDL_Event event;
    while (1) {
        if (SDL_PollEvent(&event)) {
            if (event.type == SDL_MOUSEBUTTONDOWN)
                return 0;
            else if (event.type == SDL_QUIT)
                return 1;
        }
        SDL_Delay(10);
    }
}

int main(int argc, char *argv[]) {
    // Grafiksubsystem der SDL initialisieren
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL konnte nicht initialisiert werden: %s\n", SDL_GetError());
        return 1;
    }

    // SDL bei Programmende automatisch schließen lassen
    atexit(SDL_Quit);

    // Hintergrundgrafik laden
    SDL_Surface *background = SDL_LoadBMP("images/background.bmp");
    if (background == NULL) {
        printf("Fehler beim Laden von background.bmp: %s\n", SDL_GetError());
        return 1;
    }

    // Kreisgrafik laden
    SDL_Surface *circle = SDL_LoadBMP("images/circle.bmp");
    if (circle == NULL) {
        printf("Fehler beim Laden von circle.bmp: %s\n", SDL_GetError());
        return 1;
    }

    // Kreuzgrafik laden
    SDL_Surface *cross = SDL_LoadBMP("images/cross.bmp");
    if (cross == NULL) {
        printf("Fehler beim Laden von cross.bmp: %s\n", SDL_GetError());
        return 1;
    }

    // grünen Hintergrund transparent machen
    SDL_SetColorKey(circle, SDL_SRCCOLORKEY, SDL_MapRGB(circle->format, 0x00,0xFF,0x00));
    SDL_SetColorKey(cross, SDL_SRCCOLORKEY, SDL_MapRGB(cross->format, 0x00,0xFF,0x00));

    // Fenster für Grafikausgabe öffnen
    SDL_Surface *screen = SDL_SetVideoMode(350, 350, 32, SDL_SWSURFACE);
    if ( screen == NULL ) {
        printf("Fehler beim Öffnen des Ausgabefensters: %s\n", SDL_GetError());
        return 1;
    }

    SDL_WM_SetCaption("Freitagsrunde presents: TicTacToe", NULL);
    
    // Spielfeld initialisieren und zeichnen
    reset_board();
    draw_board(background, circle, cross);
    
    SDL_Event event;
    int row, col;
    int quit = 0, turn = 0, player = PLAYER_A;
    
    // Event-Loop
    while (!quit) {
        if (SDL_PollEvent(&event)) {
            switch (event.type) {

                case SDL_MOUSEBUTTONDOWN:
                    // Maus-Koordinaten in Spielfelfkoordinaten umrechnen
                    convert_coords(event.button.x, event.button.y, &row, &col);

                    // Ist die Zelle noch frei?
                    if (board[row][col] != EMPTY)
                        break;
                        
                    // Zelle besetzen und zeichnen
                    board[row][col] = player;
                    draw_board(background, circle, cross);

                    turn++;

                    if (check_win(player) || (turn == ROWS*COLS)) {
                        if (check_win(player)) {
                            // aktueller Spieler hat gewonnen
                            if (player == PLAYER_A) {
                                SDL_WM_SetCaption("Spieler A hat gewonnen!", NULL);
                            } else {
                                SDL_WM_SetCaption("Spieler B hat gewonnen!", NULL);
                            }
                        } else {
                            // Unentschieden
                            SDL_WM_SetCaption("Unentschieden", NULL);
                        }
                            
                        quit = wait_for_click();
                     
                        // nächste runde vorbereiten
                        SDL_WM_SetCaption("Freitagsrunde presents: TicTacToe", NULL);
                        reset_board();
                        draw_board(background, circle, cross);
                        turn = 0;
                    }

                    player = 1 - player;
                    break;

                case SDL_QUIT:
                    quit = 1;
                    break;
            }
        }
    }
    
    // Fenster schließen
    SDL_FreeSurface(screen);
    
    return 0;
}