2024-04-24 17:49:03 +00:00
|
|
|
package collatz
|
|
|
|
|
|
|
|
import (
|
2024-04-24 20:04:34 +00:00
|
|
|
"collatz/parsing"
|
2024-04-24 17:49:03 +00:00
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Calculator struct {
|
2024-04-25 02:41:39 +00:00
|
|
|
parser parsing.Parser
|
|
|
|
three *big.Int
|
|
|
|
two *big.Int
|
|
|
|
one *big.Int
|
|
|
|
sequence Sequence
|
|
|
|
}
|
|
|
|
type Sequence struct {
|
|
|
|
Iterations int
|
|
|
|
Sequence []*big.Int
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
|
|
|
|
2024-04-24 20:04:34 +00:00
|
|
|
func NewCalculator(parser parsing.Parser) *Calculator {
|
|
|
|
r := &Calculator{
|
2024-04-25 02:41:39 +00:00
|
|
|
parser: parser,
|
|
|
|
three: big.NewInt(3),
|
|
|
|
two: big.NewInt(2),
|
|
|
|
one: big.NewInt(1),
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2024-04-25 02:41:39 +00:00
|
|
|
func (calc *Calculator) CalculateCollatz() (Sequence, error) {
|
|
|
|
number, err := calc.parser.Parse()
|
2024-04-24 17:49:03 +00:00
|
|
|
if err != nil {
|
2024-04-25 02:41:39 +00:00
|
|
|
return Sequence{}, fmt.Errorf("couldn't parse input: %w", err)
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
2024-04-25 02:41:39 +00:00
|
|
|
calc.sequence = Sequence{Iterations: 0}
|
|
|
|
calc.sequence.Sequence = append(calc.sequence.Sequence, new(big.Int).Set(number))
|
|
|
|
err = calc.calculateNextCollatzNumber(*number)
|
2024-04-24 20:04:34 +00:00
|
|
|
if err != nil {
|
2024-04-25 02:41:39 +00:00
|
|
|
return Sequence{}, err
|
2024-04-24 20:04:34 +00:00
|
|
|
}
|
2024-04-25 02:41:39 +00:00
|
|
|
return calc.sequence, nil
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
|
|
|
|
2024-04-25 02:41:39 +00:00
|
|
|
func (calc *Calculator) calculateNextCollatzNumber(in big.Int) error {
|
|
|
|
if in.Cmp(calc.one) < 0 {
|
2024-04-24 20:04:34 +00:00
|
|
|
return fmt.Errorf("must be greater than 0")
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
2024-04-25 02:41:39 +00:00
|
|
|
if in.Cmp(calc.one) == 0 {
|
2024-04-24 20:04:34 +00:00
|
|
|
return nil
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
|
|
|
var newNumber *big.Int
|
2024-04-25 02:41:39 +00:00
|
|
|
if new(big.Int).And(&in, calc.one).Cmp(calc.one) == 0 {
|
|
|
|
newNumber = new(big.Int).Add(new(big.Int).Mul(&in, calc.three), calc.one)
|
2024-04-24 17:49:03 +00:00
|
|
|
} else {
|
2024-04-25 02:41:39 +00:00
|
|
|
newNumber = new(big.Int).Div(&in, calc.two)
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|
2024-04-25 02:41:39 +00:00
|
|
|
calc.sequence.Iterations++
|
|
|
|
calc.sequence.Sequence = append(calc.sequence.Sequence, newNumber)
|
|
|
|
return calc.calculateNextCollatzNumber(*newNumber)
|
2024-04-24 17:49:03 +00:00
|
|
|
}
|