Subato

Vier Gewinnt

Sie sollen in dieser Aufgabe das bekannte Strategiespiel »Vier Gewinnt« in C implementieren. Die entsprechende C Header Datei ist vorgegen. In dieser findet sich als struct insbesondere der Datentyp, der einen Spielzustand darstellt. Das Spielfeld ist dabei in 7 Spalten dmir je 6 Feldern in den Reihen aufgeteilt.

Zunächst geht es darum, die allgemeine Logik des Spiels zu implementieren. Welcher Spielzug in eine Spalte ist noch möglich, hat mit dem letzten Zug ein Spieler gewonnen, wie sieht der Spielzustand aus, wenn ein bestimmter Zug ausgeführt wird?

Wenn Sie auch die Funktion show implementiert haben, können Sie bereits mit dem Programm playHumanVsHuman.c eine Partie gegen einen zweiten Spieler in einem Linux Terminal spielen.

Wenn Sie die Funktion cfState adäquat implementieren, erhalten Sie eine Künstliche Intelligenz und Sie können mit dem Programm playHumanVsAI.c eine Partie gegen die Computer spielen. Der eigentliche Algorithmus zur Vorausberechnung der besten Züge ist in der Vorgabe für die Lösung bereits umgesetzt.

Zur C-Header-Datei finden sie hier eine HTML Dokumentation.

#ifndef CF__H
#define CF__H

#include<stdbool.h>
#include "MemoryTest.h"

/** Constant for the number of columns of the connect four board. **/
#define cfCOLUMNS 7

/** Constant for the number of rows of the connect four board.*/
#define cfROWS 6


/** There are two players. */
typedef enum {None, One, Two} Player;


/** The next player is the other player or None for the 
    special enum value None. */
Player cfNextPlayer(Player p);


/** The struct CF describes the status of the game. */
typedef struct {
  /** The board is stored as a two dimension array of player
      valued. The first index signifies the column, the second the row.
      The bottom of a column has row index 0.
  */
  Player** board;
  /** The current player is the player, which does the next move.*/
  Player currentPlayer;
  /** The next attribute stores how many disc have been put
      onto the board.*/
  unsigned int movesDone;
  /** The attribute lastRow stores in which row the last disc landed.
      In the beginning, when no disc is in the board it has value -1.*/
  int lastRow;
    /** The attribute lastRow stores in which column the last disc 
	has been dropped.
      In the beginning, when no disc is in the board it has value -1.*/
  int lastColumn;
} CF;


/** Creates a new empty game state. First cuurent player is player One.*/
CF cfNewCF();

/** Removes a CF value completely from the storage.*/
void cfDeleteCF(CF this);

/** Creates a string representation of the board like in the 
  following example:
| | | | | | | |
| | | | | | | |
|O| |X|X| | | |
|X| |O|O| | | |
|X| |O|O| |X| |
|X| |X|O|O|O|X|

The character 'O' is player One, the character 'X' player Two.*/
char* cfShowCF(CF this);

/** Like cfShowCF, but the memory for the resulting string 
    is provided as parameter.  It needs to have the correct
    size, in order to store the stríng representation of the
    game. */
void cfShowCFIn(CF this,char* result);

/** Returns true, if the parameter m is a legal column. Unlike in
    the array index, htecolumns are numbered left two right with
    1 to 7. A column is a legal column to dop a disc, if it is
    between 1 and 7 and not allredy full with discs.*/
bool cfIsMove(CF this,unsigned int m);

/** Creates a new game state for this game, with a new disc of
 the current player in the given columm. 
 Remember to set all attributes of the new game state correctly. */
CF cfMakeMove(CF this,unsigned int m) ;


/* A new generation of follow up game states is an array of
   length 7 representing the 7 columns. Array Elements are 
   pointers of CF. If a column is not a legal move in the game,
   it will be set to NULL in the follow up generation.
*/
typedef CF** Generation;

/** For a given game state create the array of follow up
    states. Columns which are allready full of discs will
    result in a null pointer in the generation. */
Generation cfMkNextGeneration(CF this);

/** As cfMkNextGeneration but the resulting array of size
    7 is provided as parameter.*/
void cfNextGeneration(CF this,Generation result);

/** Delete a generation comletely from the memory. This 
    not only includes the array itself but also all game states 
    CF, the array points to.*/
void cfDeleteGeneration(Generation bs);

/** Are 4 discs connected vertical, horizontal or digonal?
    It suffices to check only connections which include the
    last disc thrown.
 */
bool cfHasWinner(CF this);

/** Returns true, if all fields of the board have a disc.
    It means that the game ended with a draw.
*/ 
bool cfFinished(CF this);

/**
   This function gives a simple meassure, how good the current state is
   for player p. It counts the three in a row triples of player p, which 
   could be completed to four in a row, and multiplies these with 100.
   Then it counts the two in a row  tuples  of player p, which 
   could be completed to four in a row, and multiplies these with 10.
   Then the same values for the other player are substracted.
   
   The better this function evaluates the state for player p, the better
   the AI will work.
 **/
int cfState(CF this, Player p);


/** Uses cfState and additionally draws winning states into account.
    Allready implemented in the solution template.*/
int cfEvalState(CF this);

/** Gives the best follow up state according to the AI.
    Allready implemented in the solution template.
*/
CF cfBestMove(CF this,int depth);

/** The traditional alpha-beta algorithm for game treees. 
    Allready implemented in the solution template.
*/
int cfAlphaBeta(CF this,int tiefe, int alpha, int beta);

#endif

#include "CF.h" #include <stdlib.h> #include <stdio.h> Player cfNextPlayer(Player p){ } CF cfNewCF(){ } void cfDeleteCF(CF this){ } char* cfShowCF(CF this){ } void cfShowCFIn(CF this,char* result){ } bool cfIsMove(CF this,unsigned int m){ } CF cfMakeMove(CF this,unsigned int m) { } Generation cfMkNextGeneration(CF this ){ } void cfNextGeneration(CF this, Generation g){ } void cfDeleteGeneration(Generation g){ } bool cfHasWinner(CF this){ } bool cfFinished(CF this){ } int cfState(CF this, Player p){ } int cfEvalState(CF this){ if (cfHasWinner(this)){ return -1000000; } return cfState(this,cfNextPlayer(this.currentPlayer)) - cfState(this,this.currentPlayer); } int cfAlphaBeta(CF this,int tiefe, int alpha, int beta){ if (tiefe==0||cfFinished(this)||cfHasWinner(this)) return cfEvalState(this); Generation gs = cfMkNextGeneration(this); int m; for (m=0;m<cfCOLUMNS;m++){ if (gs[m]!=NULL){ int wert = -cfAlphaBeta(*(gs[m]),tiefe-1,-beta,-alpha); if (wert >= beta) {alpha= beta;break;} if (wert > alpha) alpha = wert; } } cfDeleteGeneration(gs); return alpha; } CF cfBestMove(CF this,int depth){ int val = -1000000; CF result; Generation gs = cfMkNextGeneration(this); int m; bool init = false; for (m=0;m<cfCOLUMNS;m++){ if (gs[m]!=NULL){ CF g = *(gs[m]); int eval = -cfAlphaBeta(g,depth,-1000000,-val); printf("(%d, %d) ",m+1,eval); fflush(stdout); if (eval>val){ result = g; val = eval; init = true; }else if (!init){ result = g; init = true; } } } for (m=0;m<cfCOLUMNS;m++){ if (gs[m]!=NULL){ if (m!=result.lastColumn){ cfDeleteCF(*gs[m]); } free(gs[m]); } } free(gs); printf("\n "); return result; }
c
You are not logged in and therefore you cannot submit a solution.