package day09

type Marble struct {
	Number int
	CW     *Marble
	CCW    *Marble
}

// Returns the new current marble and the score to add.
func (m *Marble) PlaceNewMarble(number int) (*Marble, int) {
	// if the marble that is about to be placed has a number which is a multiple
	// of 23, the current player keeps the marble they would have placed, adding
	// it to their score. In addition, the marble 7 marbles counter-clockwise
	// from the current marble is removed from the circle and also added to the
	// current player's score. The marble located immediately clockwise of the
	// marble that was removed becomes the new current marble.
	if number%23 == 0 {
		score := number
		cursor := m
		for i := 0; i < 7; i++ {
			cursor = cursor.CCW
		}
		score += cursor.Number
		cursor = cursor.Remove()
		return cursor, score
	}

	// [Insert the marble] between the marbles that are 1 and 2
	// marbles clockwise of the current marble.
	// The marble that was just placed then becomes the current marble.

	// first create the marble and populate its fields correctly
	newMarble := &Marble{Number: number}
	cursor := m.CW
	newMarble.CCW = cursor
	newMarble.CW = cursor.CW

	// now sync up the pointers in the adjacent marbles
	newMarble.CCW.CW = newMarble
	newMarble.CW.CCW = newMarble
	return newMarble, 0
}

func (m *Marble) Remove() *Marble {
	// removes the marble from the list, repairing links. Returns the
	// marble immediately CW of this one.

	// link the two newly-adjacent marbles.
	ccw := m.CCW
	cw := m.CW
	ccw.CW = cw
	cw.CCW = ccw

	return cw
}