Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
61414ff5bf | ||
713f70041b | |||
a23e5f80f0 | |||
99eeeedc65 | |||
c73fa4e72b |
4
.github/workflows/build_release.yaml
vendored
4
.github/workflows/build_release.yaml
vendored
@ -17,9 +17,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: '>=1.22.1'
|
go-version: '>=1.22.1'
|
||||||
- name: release-build-windows
|
- name: release-build-windows
|
||||||
run: GOOS=windows GOARCH=amd64 go build -o bin/collatz-${{ github.ref_name }}-windows-amd64.exe
|
run: GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o bin/collatz-${{ github.ref_name }}-windows-amd64.exe
|
||||||
- name: release-build-linux
|
- name: release-build-linux
|
||||||
run: GOOS=linux GOARCH=amd64 go build -o bin/collatz-${{ github.ref_name }}-linux-amd64
|
run: GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o bin/collatz-${{ github.ref_name }}-linux-amd64
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
with:
|
with:
|
||||||
|
22
.github/workflows/run_tests.yaml
vendored
Normal file
22
.github/workflows/run_tests.yaml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: Run Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: '^1.22.1'
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test ./...
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.idea
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Run with `go run collatz.go 1234` or download the executable and pass a number `collatz 1234`.
|
30
collatz.go
30
collatz.go
@ -2,10 +2,34 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"collatz/collatz"
|
"collatz/collatz"
|
||||||
"collatz/io"
|
"collatz/parsing"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
calculator := collatz.NewCalculator(new(io.Cliargs))
|
sequence, err := runCollatz()
|
||||||
calculator.Collatz()
|
if err != nil {
|
||||||
|
log.Fatalf("Error calculating Collatz: %v", err)
|
||||||
|
}
|
||||||
|
printSequence(sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSequence(sequence collatz.Sequence) {
|
||||||
|
builder := new(strings.Builder)
|
||||||
|
log.Printf("Collatz sequence with %d iterations:", sequence.Iterations)
|
||||||
|
for i, num := range sequence.Sequence {
|
||||||
|
if i != 0 {
|
||||||
|
builder.WriteString("\n-> ")
|
||||||
|
}
|
||||||
|
builder.WriteString(num.String())
|
||||||
|
}
|
||||||
|
log.Println(builder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCollatz() (collatz.Sequence, error) {
|
||||||
|
parser := new(parsing.Cliargs)
|
||||||
|
calculator := collatz.NewCalculator(parser)
|
||||||
|
sequence, err := calculator.CalculateCollatz()
|
||||||
|
return sequence, err
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,61 @@
|
|||||||
package collatz
|
package collatz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"collatz/io"
|
"collatz/parsing"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Calculator struct {
|
type Calculator struct {
|
||||||
parser *io.Cliargs
|
parser parsing.Parser
|
||||||
three *big.Int
|
three *big.Int
|
||||||
two *big.Int
|
two *big.Int
|
||||||
one *big.Int
|
one *big.Int
|
||||||
|
sequence Sequence
|
||||||
|
}
|
||||||
|
type Sequence struct {
|
||||||
|
Iterations int
|
||||||
|
Sequence []*big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCalculator(parser *io.Cliargs) Calculator {
|
func NewCalculator(parser parsing.Parser) *Calculator {
|
||||||
r := Calculator{
|
r := &Calculator{
|
||||||
parser: parser,
|
parser: parser,
|
||||||
three: new(big.Int).SetInt64(3),
|
three: big.NewInt(3),
|
||||||
two: new(big.Int).SetInt64(2),
|
two: big.NewInt(2),
|
||||||
one: new(big.Int).SetInt64(1),
|
one: big.NewInt(1),
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Calculator) Collatz() {
|
func (calc *Calculator) CalculateCollatz() (Sequence, error) {
|
||||||
number, err := o.parser.Parse()
|
number, err := calc.parser.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Couldn't parse input: %s\n", err)
|
return Sequence{}, fmt.Errorf("couldn't parse input: %w", err)
|
||||||
}
|
}
|
||||||
fmt.Print(number.Text(10))
|
calc.sequence = Sequence{Iterations: 0}
|
||||||
o.nextNumber(number)
|
calc.sequence.Sequence = append(calc.sequence.Sequence, new(big.Int).Set(number))
|
||||||
fmt.Println()
|
err = calc.calculateNextCollatzNumber(*number)
|
||||||
|
if err != nil {
|
||||||
|
return Sequence{}, err
|
||||||
|
}
|
||||||
|
return calc.sequence, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Calculator) nextNumber(in *big.Int) {
|
func (calc *Calculator) calculateNextCollatzNumber(in big.Int) error {
|
||||||
if in.Cmp(o.one) < 0 {
|
if in.Cmp(calc.one) < 0 {
|
||||||
log.Panicln("Must be greater than 0")
|
return fmt.Errorf("must be greater than 0")
|
||||||
}
|
}
|
||||||
if in.Cmp(o.one) == 0 {
|
if in.Cmp(calc.one) == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
var newNumber *big.Int
|
var newNumber *big.Int
|
||||||
if new(big.Int).And(in, o.one).Cmp(o.one) == 0 {
|
if new(big.Int).And(&in, calc.one).Cmp(calc.one) == 0 {
|
||||||
newNumber = new(big.Int).Add(new(big.Int).Mul(in, o.three), o.one)
|
newNumber = new(big.Int).Add(new(big.Int).Mul(&in, calc.three), calc.one)
|
||||||
} else {
|
} else {
|
||||||
newNumber = new(big.Int).Div(in, o.two)
|
newNumber = new(big.Int).Div(&in, calc.two)
|
||||||
}
|
}
|
||||||
|
calc.sequence.Iterations++
|
||||||
fmt.Printf(" -> %s", newNumber.Text(10))
|
calc.sequence.Sequence = append(calc.sequence.Sequence, newNumber)
|
||||||
o.nextNumber(newNumber)
|
return calc.calculateNextCollatzNumber(*newNumber)
|
||||||
}
|
}
|
||||||
|
48
collatz/calculator_test.go
Normal file
48
collatz/calculator_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package collatz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockParser struct {
|
||||||
|
value *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockParser) Parse() (*big.Int, error) {
|
||||||
|
return m.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewCalculator(t *testing.T) {
|
||||||
|
parser := &MockParser{}
|
||||||
|
calculator := NewCalculator(parser)
|
||||||
|
|
||||||
|
if calculator.parser != parser {
|
||||||
|
t.Errorf("Expected parser to be %v, got %v", parser, calculator.parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
if calculator.one.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Errorf("Expected one to be 1, got %v", calculator.one)
|
||||||
|
}
|
||||||
|
|
||||||
|
if calculator.two.Cmp(big.NewInt(2)) != 0 {
|
||||||
|
t.Errorf("Expected two to be 2, got %v", calculator.two)
|
||||||
|
}
|
||||||
|
|
||||||
|
if calculator.three.Cmp(big.NewInt(3)) != 0 {
|
||||||
|
t.Errorf("Expected three to be 3, got %v", calculator.three)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateCollatz(t *testing.T) {
|
||||||
|
parser := &MockParser{value: big.NewInt(6)}
|
||||||
|
calculator := NewCalculator(parser)
|
||||||
|
|
||||||
|
sequence, err := calculator.CalculateCollatz()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if sequence.Iterations != 8 {
|
||||||
|
t.Errorf("Expected 8 iterations, got %v", sequence.Iterations)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io
|
package parsing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -7,7 +7,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Cliargs struct {
|
type Cliargs struct {
|
||||||
value *big.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (arg *Cliargs) Parse() (*big.Int, error) {
|
func (arg *Cliargs) Parse() (*big.Int, error) {
|
||||||
@ -19,10 +18,5 @@ func (arg *Cliargs) Parse() (*big.Int, error) {
|
|||||||
if !success {
|
if !success {
|
||||||
return nil, errors.New("argument is not an integer")
|
return nil, errors.New("argument is not an integer")
|
||||||
}
|
}
|
||||||
arg.value = num
|
|
||||||
return num, nil
|
return num, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (arg *Cliargs) GetNumber() *big.Int {
|
|
||||||
return arg.value
|
|
||||||
}
|
|
44
parsing/cliargs_test.go
Normal file
44
parsing/cliargs_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package parsing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCliargs_Parse(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
want *big.Int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test with valid integer",
|
||||||
|
args: []string{"", "10"}, // the first argument is the program name
|
||||||
|
want: big.NewInt(10),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test with non-integer",
|
||||||
|
args: []string{"", "abc"}, // the first argument is the program name
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
os.Args = tt.args
|
||||||
|
parser := &Cliargs{}
|
||||||
|
got, err := parser.Parse()
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !tt.wantErr && got.Cmp(tt.want) != 0 {
|
||||||
|
t.Errorf("Parse() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
7
parsing/interface.go
Normal file
7
parsing/interface.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package parsing
|
||||||
|
|
||||||
|
import "math/big"
|
||||||
|
|
||||||
|
type Parser interface {
|
||||||
|
Parse() (*big.Int, error)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user