github.com/joshprzybyszewski/masyu@v0.0.0-20230508015604-f31a025f6e7e/solve/crossings.go (about)

     1  package solve
     2  
     3  import (
     4  	"github.com/joshprzybyszewski/masyu/model"
     5  )
     6  
     7  type crossings struct {
     8  	// [col]numLines/AvoidsInThatCol
     9  	cols      [maxPinsPerLine]model.Dimension
    10  	colsAvoid [maxPinsPerLine]model.Dimension
    11  
    12  	// [row]numLines/AvoidsInThatRow
    13  	rows      [maxPinsPerLine]model.Dimension
    14  	rowsAvoid [maxPinsPerLine]model.Dimension
    15  
    16  	// This is the "target" for an _almost_ empty row/col
    17  	target model.Dimension
    18  }
    19  
    20  func newCrossings(
    21  	size model.Size,
    22  ) crossings {
    23  	return crossings{
    24  		target: model.Dimension(size) - 1,
    25  	}
    26  }
    27  
    28  func (c *crossings) lineHor(
    29  	col model.Dimension,
    30  	s *state,
    31  ) {
    32  	if col == 0 {
    33  		return
    34  	}
    35  	c.cols[col]++
    36  	if c.colsAvoid[col]+c.cols[col] == c.target {
    37  		c.completeCol(col, s)
    38  	}
    39  
    40  }
    41  
    42  func (c *crossings) avoidHor(
    43  	col model.Dimension,
    44  	s *state,
    45  ) {
    46  	if col == 0 {
    47  		return
    48  	}
    49  	c.colsAvoid[col]++
    50  	if c.colsAvoid[col]+c.cols[col] == c.target {
    51  		c.completeCol(col, s)
    52  	}
    53  }
    54  
    55  func (c *crossings) completeCol(
    56  	col model.Dimension,
    57  	s *state,
    58  ) {
    59  	row := getEmptyCrossingInColumn(s, col)
    60  	if c.cols[col]%2 == 0 {
    61  		s.avoidHor(row, col)
    62  	} else {
    63  		s.lineHor(row, col)
    64  	}
    65  }
    66  
    67  func (c *crossings) lineVer(
    68  	row model.Dimension,
    69  	s *state,
    70  ) {
    71  	if row == 0 {
    72  		return
    73  	}
    74  	c.rows[row]++
    75  	if c.rowsAvoid[row]+c.rows[row] == c.target {
    76  		c.completeRow(row, s)
    77  	}
    78  }
    79  
    80  func (c *crossings) avoidVer(
    81  	row model.Dimension,
    82  	s *state,
    83  ) {
    84  	if row == 0 {
    85  		return
    86  	}
    87  	c.rowsAvoid[row]++
    88  	if c.rowsAvoid[row]+c.rows[row] == c.target {
    89  		c.completeRow(row, s)
    90  	}
    91  }
    92  
    93  func (c *crossings) completeRow(
    94  	row model.Dimension,
    95  	s *state,
    96  ) {
    97  	col := getEmptyCrossingInRow(s, row)
    98  	if c.rows[row]%2 == 0 {
    99  		s.avoidVer(row, col)
   100  	} else {
   101  		s.lineVer(row, col)
   102  	}
   103  }
   104  
   105  func getEmptyCrossingInColumn(
   106  	s *state,
   107  	col model.Dimension,
   108  ) model.Dimension {
   109  	for row := model.Dimension(1); row <= model.Dimension(s.size); row++ {
   110  		if !s.hasHorDefined(row, col) {
   111  			return row
   112  		}
   113  	}
   114  	return 0
   115  }
   116  
   117  func getEmptyCrossingInRow(
   118  	s *state,
   119  	row model.Dimension,
   120  ) model.Dimension {
   121  	for col := model.Dimension(1); col <= model.Dimension(s.size); col++ {
   122  		if !s.hasVerDefined(row, col) {
   123  			return col
   124  		}
   125  	}
   126  	return 0
   127  }