connect4

Connect 4 Board Game
Log | Files | Refs

Board.cs (4738B)


      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 
      5 public class Board {
      6     private int _n; // number of columns
      7     private int _m; // number of rows
      8     private Cell[,] _board;
      9     private int[] _height;
     10     private Cell _next;
     11     private Status _status;
     12 
     13     public enum Cell {
     14         Free = 0, // make sure free is the default value
     15         PlayerX,
     16         PlayerO,
     17         None,
     18     }
     19 
     20     public enum Status {
     21         InProgress,
     22         PlayerXWon,
     23         PlayerOWon,
     24         Draw,
     25     }
     26 
     27     /*
     28      * Constructs a new board with m rows and n columns.
     29      */
     30     public Board( int n, int m ) {
     31         _m = m;
     32         _n = n;
     33         _board = new Cell[ m, n ];
     34         _height = new int[ n ];
     35         _next = Cell.PlayerX; // player X starts
     36         _status = Status.InProgress;
     37     }
     38 
     39     /*
     40      * Constructs a new board with the given board
     41      */
     42     public Board( Board board ) {
     43         _m = board._m;
     44         _n = board._n;
     45         _board = new Cell[ _m, _n ];
     46         _height = new int[ _n ];
     47         // why does it have to be so difficult to deep copy a 2d array?
     48         for ( int j = 0; j < _m; j ++ ) {
     49             for ( int i = 0; i < _n; i ++ ) {
     50                 _board[ j, i ] = board._board[ j, i ];
     51             }
     52         }
     53         board._height.CopyTo( _height, 0 );
     54         _next = board._next;
     55         _status = board._status;
     56     }
     57 
     58     /*
     59      * Determines if it is legal to play a piece in the given column
     60      */
     61     public bool IsLegal( int column ) {
     62         return _height[ column ] < _m;
     63     }
     64 
     65     /*
     66      * assumes play is legal
     67      */
     68     public void Play( int column ) {
     69         _board[ _m - _height[ column ] - 1, column ] = _next;
     70         _height[ column ] ++;
     71         _next = ( _next == Cell.PlayerX ) ? Cell.PlayerO : Cell.PlayerX;
     72         ComputeStatus();
     73     }
     74 
     75     /*
     76      * returns whos turn it is
     77      */
     78     public Cell GetNext() {
     79         return _next;
     80     }
     81 
     82     /*
     83      * returns who just played
     84      */
     85     public Cell GetPrevious() {
     86         return _next == Cell.PlayerX ? Cell.PlayerO : Cell.PlayerX;
     87     }
     88 
     89     /*
     90      * Pretty prints the board
     91      */
     92     public void PrettyPrint() {
     93         char[] prettyChar = { '.', 'X', 'O' };
     94         Console.WriteLine( $"{ _status }:" );
     95         for ( int j = 0; j < _m; j++ ) {
     96             for ( int i = 0; i < _n; i++ ) {
     97                 Console.Write( $" { prettyChar[ (int) _board[ j, i ] ] } " );
     98             }
     99             Console.Write( "\n" );
    100         }
    101     }
    102 
    103     /*
    104      * Returns a list of all legal moves on this board 
    105      */
    106     public List< int > LegalMoves() {
    107         List< int > legalMoves = new List< int >();
    108         if ( _status == Status.InProgress ) {
    109             for ( int i = 0; i < _n; i ++ ) {
    110                 if ( IsLegal( i ) ) {
    111                     legalMoves.Add( i );
    112                 }
    113             }
    114         }
    115         return legalMoves;
    116     }
    117 
    118     public Status GetStatus() {
    119         return _status;
    120     }
    121 
    122     public int GetHeight() {
    123         return _m;
    124     }
    125 
    126     public int GetWidth() {
    127         return _n;
    128     }
    129 
    130     /*
    131      * Indexer to grant read-only access to the board
    132      */
    133      public Cell this[ int j, int i ] {
    134         get {
    135             if ( 0 <= j && j < _m && 0 <= i && i < _n ) {
    136                 return _board[ j, i ];
    137             } else {
    138                 return Cell.None;
    139             }
    140         }
    141      }
    142 
    143 
    144     /*
    145      * Computes the status of this board, ie. has someone won by obtaining four in a row.
    146      */
    147     public Status ComputeStatus() {
    148         int FourInARow = NumberQInRow( 4, GetPrevious() );
    149 
    150         if ( FourInARow > 0 ) {
    151             _status = _next == Cell.PlayerO ? Status.PlayerXWon : Status.PlayerOWon;
    152         }
    153         return _status;
    154     }
    155 
    156     /*
    157      * Returns the number of q in a row for player.
    158      * Note: this also counts instance of more than q in a row.
    159      */
    160     public int NumberQInRow( int q, Cell player ) {
    161         var rows = Enumerable.Range( 0, _m );
    162         var columns = Enumerable.Range( 0, _n );
    163 
    164         var indices = new Func< int, int, int, ( int, int ) >[] {
    165             ( j, i, k ) => ( j + k, i ),
    166             ( j, i, k ) => ( j, i + k ),
    167             ( j, i, k ) => ( j + k, i + k ),
    168             ( j, i, k ) => ( j - k, i + k ),
    169         };
    170 
    171         int count =
    172             (   from index in indices
    173                 from j in rows
    174                 from i in columns
    175                 select Enumerable.All(
    176                     Enumerable.Range( 0, q ),
    177                     k => {
    178                         var ( jj, ii ) = index( j, i, k );
    179                         return this[ jj, ii ] == player;
    180                     }
    181                 )
    182             ).Where( b => b )
    183             .Count();
    184         return count;
    185     }
    186 }