Golang gives different result everytime using map for AOC 2021 Day 6 problem - go

I've been trying to solve Advent of Code 2021 and in day 6, I am trying this solution but the result is different everytime. What seems to be the problem? Is there any memory leakage with map?
The input file can be found here
The details of the problem can be read here
For part one it was straight-forward looping over arrays but as the number of days increases, the population grows exponentially and the time complexity grows in similar manner.
with go version go1.19.3
I have tried this:
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func getInput() []int {
var parsedData []int
rawData, _ := os.ReadFile("input.txt")
data := strings.Split(string(rawData), ",")
for _, strNum := range data {
num, _ := strconv.Atoi(strNum)
parsedData = append(parsedData, num)
}
return parsedData
}
func main() {
data := getInput()
var total int64
// create a map t0 hold the number of fish with the same timer
fishWithSameTimer := make(map[int]int64)
for _, timer := range data {
if _, ok := fishWithSameTimer[timer]; ok {
fishWithSameTimer[timer] += 1
} else {
fishWithSameTimer[timer] = 1
}
}
const days int = 18
currDay := 1
for currDay <= days {
tempFishTimerData := make(map[int]int64)
for timer, numOfFishes := range fishWithSameTimer {
if timer == 0 {
tempFishTimerData[8] = numOfFishes
tempFishTimerData[6] = numOfFishes
}else{
tempFishTimerData[timer - 1] += numOfFishes
}
}
fishWithSameTimer = tempFishTimerData
fmt.Println("Day:", currDay, fishWithSameTimer)
currDay++
}
fmt.Println(fishWithSameTimer)
for _, num := range fishWithSameTimer {
total += num
}
fmt.Println(total)
}
Can anyone help?

I hope this piece of code does the work, please add the input file reading part and print the output slice as comma separated string. You can also validate if the input has all numbers between 0 and 8.
package main
import "fmt"
func refreshTimer(x int) (int, bool) {
if x == 0 {
return 6, true
} else {
return x - 1, false
}
}
func spawnFish(i []int) []int {
var parentIntTimer []int
var childIntTimer []int
for _, d := range i {
y, c := refreshTimer(d)
parentIntTimer = append(parentIntTimer, y)
if c {
childIntTimer = append(childIntTimer, 8)
}
}
return append(parentIntTimer, childIntTimer...)
}
func main() {
initialFishes := []int{3, 4, 3, 1, 2}
var spFishes []int
noOfDays := 18
for i := 1; i <= noOfDays; i++ {
spFishes = spawnFish(initialFishes)
initialFishes = spFishes
}
fmt.Println(spFishes)
}
Output: [6 0 6 4 5 6 0 1 1 2 6 0 1 1 1 2 2 3 3 4 6 7 8 8 8 8]

Related

How to split output from looping into four columns

I want the results of my program code output to be divided into 4 columns as shown below.
this my code :
package main
import "fmt"
func main() {
var data int
fmt.Scan(&data)
for i := 1; i <= data; i++ {
fmt.Println("VA", i)
}
}
what should i add in my code?
package main
import "fmt"
func main() {
const L = 4
data := make([]int, L)
for {
for i := 0; i < L; i++ {
_, err := fmt.Scan(&data[i])
if err != nil {
fmt.Println(err)
return
}
}
for _, i := range data {
fmt.Printf("VA%d ", i)
}
fmt.Println()
}
}
You can use the example below as a reference (source):
package main
import (
"fmt"
"os"
"text/tabwriter"
)
func main() {
// initialize tabwriter
w := new(tabwriter.Writer)
// minwidth, tabwidth, padding, padchar, flags
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
defer w.Flush()
fmt.Fprintf(w, "\n %s\t%s\t%s\t", "Col1", "Col2", "Col3")
fmt.Fprintf(w, "\n %s\t%s\t%s\t", "----", "----", "----")
for i := 0; i < 5; i++ {
fmt.Fprintf(w, "\n %d\t%d\t%d\t", i, i+1, i+2)
}
// Col1 Col2 Col3
// ---- ---- ----
// 0 1 2
// 1 2 3
// 2 3 4
// 3 4 5
// 4 5 6
}
Your question does not show much research though. I just googled it quickly and found the example above.

why does bufio.NewReader does not work proprely when input come from redirection?

I am currently trying to solve this challenge on the website CodeChef when entering input manually I get the expected answer for the problem like stated in the problem.
But when I tried to use cat in.txt | go run my_program.go the output from my program is different.
As you can see I tried to debug using fmt.Printf and it look like bufio.NewReader randomly miss the input from the pipe.
I would like to know what I am doing wrong and if there are alternative approach to read a whole line containing multiple integrers in Golang.
Thanks you for helping me !
content of in.txt :
4
3
1 2 3
3
3 2 1
3
0 0 0
3
1 3 2
normal output when entering input manually :
1 1
3 3
1 1
1 2
output with debug message when entering text using cat in.txt | go run my_program.go
debug <1 2 3
>
1 1
debug <>
1 1
debug <>
1 1
debug <>
1 1
my program :
package main
import (
"fmt"
"os"
"strings"
"bufio"
"strconv"
)
func main() {
t, n := 0, 0
fmt.Scanf("%d", &t)
for i := 0; i < t; i++ {
fmt.Scanf("%d\n", &n)
v := make([]int, n)
rd := bufio.NewReader(os.Stdin)
text, _ := rd.ReadString('\n')
fmt.Printf("debug <%s>\n", text)
arr := strings.Split(strings.TrimSuffix(text, "\n"), " ")
for k := 0; k < len(arr); k++ {
v[k], _ = strconv.Atoi(arr[k])
}
fmt.Println(calc_intersect(v))
}
}
func calc_intersect(v []int) (int, int) {
smt, lgt := 100, 0
scenario := make([]int, len(v))
for sc := 0; sc < len(v); sc++ {
infect := make([]bool, len(v))
infect[sc] = true
scenario[sc] = simulate(v, infect)
}
for i := 0; i < len(scenario); i++ {
if scenario[i] <= smt {
smt = scenario[i]
}
if scenario[i] > lgt {
lgt = scenario[i]
}
}
return smt, lgt
}
func simulate(v []int, infect []bool) int {
var nb_inf int = 1
pos := make([]int, len(v))
for time := 0; time < 25; time++ {
for p := 0; p < len(v); p++ {
pos[p] = (v[p] * time) + p
}
for a := 0; a < len(v); a++ {
check_intersect(pos, infect, &nb_inf, a)
}
}
return nb_inf
}
func check_intersect(pos []int, infect []bool, nb_inf *int, a int) {
for b := 0; b < len(pos); b++ {
if a == b {
continue
}
if pos[a] == pos[b] && (infect[a] || infect[b]) && !(infect[a] && infect[b]) {
*nb_inf += 1
infect[a], infect[b] = true, true
}
}
}
Your use of bufio.NewReader is wrong. You create a new buffered reader each time through the i loop. The reader may read ahead if input is available, and when you don't re-use the reader that buffered input is unused.
Simply move rd := bufio.NewReader(os.Stdin) outside of the loop to fix the problem.
Your code works when you read from the console via stdin because you can't type fast enough for the reader to try to buffer input.

Golang Simple User Input Product Math Question like 3*2*1 = 6

I'm trying to create a small program that allows a user to input an integer which will output the product such as follows:
For example:
a = 5, 5*4*3*2 = 120
a = 4, 4*3*2*1 = 24
a = 3, 3*2*1 = 6
Can someone provide guidance as I'm stuck on how to frame this more efficiently. If using Python, I would probably write the logic something like:
def a(num):
x = 1
for i in range (num):
x=x*(i + 1)
return x
print a(5)
You need to learn about the go language itself first, after that you'll be able to convert your python code into go, easily.
Few go learning resources:
https://tour.golang.org
https://gobyexample.com
https://golang.org/doc
But anyway, here is the go version of your python code:
func a(num int) int {
x := 1
for i := 0; i < num; i++ {
x = x * (i + 1)
}
return x
}
func main() {
fmt.Println(a(5)) // 120
fmt.Println(a(4)) // 24
fmt.Println(a(3)) // 6
}
Working playground: https://play.golang.org/p/glHwuMhTDYj
the main function taken from previous answer - only the scanf added here as you requested
package main
import (
"fmt"
)
func a(num int) int {
x := 1
for i := 0; i < num; i++ {
x = x * (i + 1)
}
return x
}
func main() {
var i int
_, err := fmt.Scanf("%d", &i)
if nil == err {
fmt.Println(a(i))
} else {
panic(err)
}
}

Golang Calculator -- Can't divide by 0 error

I'm actually in a bit of a trouble...
I have a calculator, but when I want to divide nubers with them, I have a panic err saying that you can't divide by 0.
Well, I know that in maths we can't divide by 0, but I don't put 0 in my ints.
Any idea of the problem ?
Here is the code :
package main
import (
"fmt"
"os"
"strconv"
)
func mult(nums ...int) {
result := 0
total := 1
for _, num := range nums {
result = total * num
total = result
}
fmt.Println(result)
}
func add(nums ...int){
result := 0
total := 0
for _, num := range nums {
result = total + num
total = result
}
fmt.Println(result)
}
func sub(nums ...int){
result := 0
total := 0
for _, num := range nums {
result = num - total
total = result
}
fmt.Println(result)
}
func div(nums ...int){
result := 1
total := 1
for _, num := range nums {
result = num / total
total = result
}
fmt.Println(result)
}
func main() {
var d [] int
var args= os.Args[1:]
nums := make([]int, len(args))
for i := 0; i < len(args); i++ {
nums[i], _ = strconv.Atoi(args[i]);
strconv.Atoi(args[i])
d = append(d, nums[i])
}
num := d
if os.Args[1] == "*"{
mult(num...)
} else if os.Args[1] == "+"{
add(num...)
} else if os.Args[1] == "-"{
sub(num...)
} else if os.Args[1] == "/"{
div(num...)
} else {
fmt.Println("Well well well, you didn't entered a right operand ! Try with +, -, /, or * between double quotes")
}
}
The command I want to run this go code is :
go run calc.exe / 3 2 [Infinite args,...]
If your first parameter will always be a operator select, you can do something like that in your main func, you have a two problems in your main, you are ignoring the convertion error of a string to int and then this index of your array are setted with 0, and you are defining the array larger than you need because your first parameter it's not a number to your div func
nums := make([]int, len(args)-1)
for i := 0; i < len(args); i++ {
ret, errAtoi := strconv.Atoi(args[i])
if errAtoi != nil {
fmt.Println(errAtoi.Error())
} else {
nums[i-1] = ret
d = append(d, nums[i-1])
}
}

Extract digits at a certain position in a number

number := 111555
How do I get, for instance the first 3 digits (111) and the last 2 digits (55)?
Try this:
number := 111555
fmt.Println(number % 100) // last 2 digits (55)
// first 3 digits (111)
for ; number > 999; number /= 10 {
}
fmt.Println(number) // 111
Try this:
number := 111555
slice := strconv.Itoa(number)
fmt.Println(slice[:3]) // first 3 digits (111)
fmt.Println(slice[len(slice)-2:]) // and the last 2 digits (55)
The first 3 digits (111):
strconv.Itoa(number)[:3]
and the last 2 digits (55):
number % 100
or:
slice := strconv.Itoa(number)
slice[len(slice)-2:]
try this:
number := 111555
// and the last 2 digits (55)
l2d := number % 100
fmt.Println(l2d)
// first 3 digits (111)
f3d := strconv.Itoa(number)[:3]
// i, e := strconv.Atoi(f3d)
fmt.Println(f3d)
Another way, try this:
package main
import (
"fmt"
"math"
)
func main() {
number := 111555
// last 2 digits (55)
l2d := number % 100
fmt.Println(l2d)
// first 3 digits (111)
remainingDigits := numberOfDigits(number) - 3
f3d := number / int(math.Pow10(remainingDigits))
fmt.Println(f3d)
}
func numberOfDigits(n int) (digits int) {
for ; n != 0; n /= 10 {
digits++
}
return
}
another way:
package main
import (
"fmt"
)
func main() {
number := 111555
// and the last 2 digits (55)
l2d := number % 100
fmt.Println(l2d)
// first 3 digits (111)
fmt.Println(leftDigits(number, 3))
}
func leftDigits(number, n int) int {
digits := make([]byte, 20)
i := -1
for number != 0 {
i++
digits[i] = byte(number % 10)
number /= 10
}
r := 0
for ; n != 0; n-- {
r = r * 10
r += int(digits[i])
i--
}
return r
}
output:
55
111
By using simple arithmetic:
func d(num int) (firstThree int, lastTwo int) {
firstThree = num / 1000
lastTwo = num % 100
return
}
This function gives the digit at a specific place:
func digit(num, place int) int {
r := num % int(math.Pow(10, float64(place)))
return r / int(math.Pow(10, float64(place-1)))
}
For example digit(1234567890, 2) (second number from the right side) gives 9 and digit(1234567890, 6) gives 5 (sixth number from the right side).
you cant turn int into slice of digits in golang
the trick is u have to turn it into string, do the composition, then fallback to int seperatly
https://play.golang.org/p/eZn1onG7T6
If the number is not too large, there is a simple way.
package main
import (
"fmt"
"log"
"strconv"
)
func main() {
num := 111555
s := strconv.Itoa(num)
pos := 3 // first 3 digits, others
part1 := s[:pos]
part2 := s[pos:]
num1, err := strconv.Atoi(part1)
if err != nil {
log.Fatal(err)
}
num2, err := strconv.Atoi(part2)
if err != nil {
log.Fatal(err)
}
fmt.Println(num1, num2)
}
str := strconv.Itoa(111555)
fmt.Println(str[len(str)-2:]) //trailing 2 digits
fmt.Println(str[:3]) //first 3 digits
For example,
package main
import (
"fmt"
"strconv"
)
func strDigits(n, digits int) (string, int) {
s := strconv.Itoa(n)
if s[0] == '-' {
s = s[1:]
}
if digits > len(s) {
digits = len(s)
}
if digits < 0 {
digits = 0
}
return s, digits
}
func firstDigits(n, digits int) string {
s, d := strDigits(n, digits)
return s[:d]
}
func lastDigits(n, digits int) string {
s, d := strDigits(n, digits)
return s[len(s)-d:]
}
func main() {
number := 111555
fmt.Println(firstDigits(number, 3))
fmt.Println(lastDigits(number, 2))
}
Playground: https://play.golang.org/p/oYwZ5HFndt
Output:
111
55

Resources