github.com/gorgonia/agogo@v0.1.1/game/c4/c4.go (about)

     1  package c4
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	// "log"
     7  
     8  	"github.com/gorgonia/agogo/game"
     9  	"gorgonia.org/tensor"
    10  	"gorgonia.org/tensor/native"
    11  )
    12  
    13  type Board struct {
    14  	data *tensor.Dense
    15  	it   [][]game.Colour
    16  	n    int // how many to be considered a win?
    17  }
    18  
    19  func newBoard(rows, cols, n int) *Board {
    20  	backing := make([]game.Colour, rows*cols)
    21  	data := tensor.New(tensor.WithShape(rows, cols), tensor.WithBacking(backing))
    22  	iter, err := native.Matrix(data)
    23  	if err != nil {
    24  		panic(err)
    25  	}
    26  	it := iter.([][]game.Colour)
    27  	return &Board{
    28  		data: data,
    29  		it:   it,
    30  		n:    n,
    31  	}
    32  }
    33  
    34  func (b *Board) Format(s fmt.State, c rune) {
    35  	switch c {
    36  	case 's', 'v':
    37  		for _, row := range b.it {
    38  			fmt.Fprint(s, "⎢ ")
    39  			for _, col := range row {
    40  				fmt.Fprintf(s, "%s ", col)
    41  			}
    42  			fmt.Fprint(s, "⎥\n")
    43  		}
    44  	}
    45  }
    46  
    47  func (b *Board) Apply(m game.PlayerMove) error {
    48  	if m.Single.IsPass() {
    49  		return nil
    50  	}
    51  	row, col, err := b.check(m)
    52  	if err != nil {
    53  		return err
    54  	}
    55  	b.it[row][col] = game.Colour(m.Player)
    56  	return nil
    57  }
    58  
    59  func (b *Board) check(m game.PlayerMove) (row, col int, err error) {
    60  	if m.Single.IsPass() {
    61  		return -1, -1, nil
    62  	}
    63  	col = int(m.Single)
    64  	for row = len(b.it) - 1; row >= 0; row-- {
    65  		if b.it[row][col] == game.None {
    66  			return row, col, nil
    67  		}
    68  	}
    69  	return -1, -1, errors.New("Selected column is full")
    70  }
    71  
    72  func (b *Board) clone() *Board {
    73  	sh := b.data.Shape()
    74  
    75  	b2 := newBoard(sh[0], sh[1], b.n)
    76  	raw2 := b2.data.Data().([]game.Colour)
    77  	raw := b.data.Data().([]game.Colour)
    78  	copy(raw2, raw)
    79  	return b2
    80  }
    81  
    82  func (b *Board) checkWin() game.Colour {
    83  	rows, cols := b.data.Shape()[0], b.data.Shape()[1]
    84  	if winner := b.checkVertical(rows, cols); winner != game.None {
    85  		return winner
    86  	}
    87  	if winner := b.checkHorizontal(rows, cols); winner != game.None {
    88  		return winner
    89  	}
    90  	if winner := b.checkTLBR(rows, cols); winner != game.None {
    91  		return winner
    92  	}
    93  	return b.checkTRBL(rows, cols)
    94  }
    95  
    96  // checkVertical checks downwards
    97  func (b *Board) checkVertical(rows, cols int) game.Colour {
    98  	for x := 0; x < cols; x++ {
    99  		for y := 0; y < rows; y++ {
   100  			c := b.it[y][x]
   101  			winning := true
   102  			if c != game.None {
   103  				for i := 0; i < b.n; i++ {
   104  					if y+i < rows {
   105  						if b.it[y+i][x] != c {
   106  							winning = false
   107  						}
   108  					} else {
   109  						winning = false
   110  					}
   111  				}
   112  				if winning {
   113  					return c
   114  				}
   115  			}
   116  		}
   117  	}
   118  	return game.None
   119  }
   120  
   121  // checkHorizontal checks rightwards
   122  func (b *Board) checkHorizontal(rows, cols int) game.Colour {
   123  	for x := 0; x < cols; x++ {
   124  		for y := 0; y < rows; y++ {
   125  			c := b.it[y][x]
   126  			winning := true
   127  			if c != game.None {
   128  				for i := 0; i < b.n; i++ {
   129  					if x+i < cols {
   130  						if b.it[y][x+i] != c {
   131  							winning = false
   132  						}
   133  					} else {
   134  						winning = false
   135  					}
   136  				}
   137  				if winning {
   138  					return c
   139  				}
   140  			}
   141  		}
   142  	}
   143  	return game.None
   144  }
   145  
   146  func (b *Board) checkTLBR(rows, cols int) game.Colour {
   147  	for x := 0; x < cols; x++ {
   148  		for y := 0; y < rows; y++ {
   149  			c := b.it[y][x]
   150  			winning := true
   151  			if c != game.None {
   152  				for i := 0; i < b.n; i++ {
   153  					if x-i >= 0 && y+i < rows {
   154  						if b.it[y+i][x-i] != c {
   155  							winning = false
   156  						}
   157  					} else {
   158  						winning = false
   159  					}
   160  				}
   161  				if winning {
   162  					return c
   163  				}
   164  			}
   165  		}
   166  	}
   167  	return game.None
   168  }
   169  
   170  func (b *Board) checkTRBL(rows, cols int) game.Colour {
   171  	for x := 0; x < cols; x++ {
   172  		for y := 0; y < rows; y++ {
   173  			c := b.it[y][x]
   174  			winning := true
   175  			if c != game.None {
   176  				for i := 0; i < b.n; i++ {
   177  					if x+i < cols && y+i < rows {
   178  						if b.it[y+i][x+i] != c {
   179  							winning = false
   180  						}
   181  					} else {
   182  						winning = false
   183  					}
   184  				}
   185  				if winning {
   186  					return c
   187  				}
   188  			}
   189  		}
   190  	}
   191  	return game.None
   192  }