Skip to content

Instantly share code, notes, and snippets.

@ervitis
Created January 7, 2021 12:08
Show Gist options
  • Save ervitis/4dc439ef34d54ba41834692d862ae382 to your computer and use it in GitHub Desktop.
Save ervitis/4dc439ef34d54ba41834692d862ae382 to your computer and use it in GitHub Desktop.
hennge test
package main
import (
"bufio"
"bytes"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"sync"
)
/*
Notes: as the assessment says all the input data has a min and max value so I decided to use a slice data struct to
store each line of integer numbers. If we wouldn't know the limit (or it is very big) I would consider using channels with
go routines and read them one by one using a fanIn-fanOut pattern.
For example:
items := make(chan int, 1)
complete := make(chan bool)
go func() {
// inside a loop to read each item
items <- readItemFromLine()
// after the loop
close(items)
}
...
// inside another loop of the queue to get each item and then send the complete signal
item := <-items
sumSquare += item*item
...
complete <- true
// in another part of the code I would control the complete channel to finish each go routine
*/
type (
inputData struct {
numberItems int
items []int
sumSquares int
}
)
const (
TESTINGENABLE = "TEST"
TESTINGFILENAME = "TESTFILENAME"
TESTINGOUTPUTFILENAME = "TESTFILENAMEOUTPUT"
)
var (
testCase []*inputData
mtx sync.Mutex
)
func readInput(reader *bufio.Reader) (string, error) {
mtx.Lock()
defer mtx.Unlock()
line, _, err := reader.ReadLine()
if err != nil {
return "", err
}
return string(line), nil
}
func convertStringItemsToIntItems(items []string) ([]int, error) {
n := len(items)
data := make([]int, 0)
LOOP:
if n > 0 {
input, err := strconv.Atoi(items[len(items)-n])
if err != nil {
return nil, err
}
data = append(data, input)
n--
goto LOOP
}
return data, nil
}
func getBufferReaderFromEnviron() *bufio.Reader {
envTest := os.Getenv(TESTINGENABLE)
if envTest == "" {
return bufio.NewReader(os.Stdin)
}
fileName := os.Getenv(TESTINGFILENAME)
if fileName == "" {
fileName = "tests_cases.txt"
}
buff, _ := ioutil.ReadFile(fileName)
return bufio.NewReader(bytes.NewBuffer(buff))
}
func getInputData() ([]*inputData, error) {
reader := getBufferReaderFromEnviron()
INITINPUTDATA:
input, err := readInput(reader)
if err != nil {
return nil, err
}
input = strings.TrimSpace(input)
if input == "" {
goto INITINPUTDATA
}
numberTestCases, err := strconv.Atoi(input)
if err != nil {
return nil, err
}
INPUTLOOP:
if numberTestCases > 0 {
input, err = readInput(reader)
if err != nil {
return nil, err
}
input = strings.TrimSpace(input)
numberItems, err := strconv.Atoi(input)
if err != nil {
return nil, err
}
if numberItems == 0 {
_, _ = readInput(reader)
numberTestCases--
goto INPUTLOOP
}
input, err = readInput(reader)
if err != nil {
return nil, err
}
input = strings.TrimSpace(input)
items, err := convertStringItemsToIntItems(strings.Split(input, " "))
if err != nil {
return nil, err
}
mtx.Lock()
data := &inputData{
numberItems: numberItems,
items: items,
}
testCase = append(testCase, data)
mtx.Unlock()
numberTestCases--
goto INPUTLOOP
}
return testCase, nil
}
func calculateSumSquares(data []*inputData) {
mtx.Lock()
defer mtx.Unlock()
n := len(data)
LOOPTESTCASES:
if n > 0 {
i := len(data) - n
m := len(data[i].items)
LOOPITEMS:
if m > 0 {
j := len(data[i].items) - m
if data[i].items[j] > 0 {
data[i].sumSquares += data[i].items[j] * data[i].items[j]
}
m--
goto LOOPITEMS
}
n--
goto LOOPTESTCASES
}
}
func printResult(data []*inputData, printer io.ReadWriter) {
mtx.Lock()
n := len(data)
LOOPTESTCASES:
if n > 0 {
_, _ = printer.Write([]byte(strconv.Itoa(data[len(data)-n].sumSquares) + "\n"))
n--
goto LOOPTESTCASES
}
mtx.Unlock()
}
func setOutputStream() (*os.File, error) {
testEnable := os.Getenv(TESTINGENABLE)
if testEnable == "" {
return os.Stdout, nil
}
testOutputFileName := os.Getenv(TESTINGOUTPUTFILENAME)
if testOutputFileName == "" {
return os.Stdout, nil
}
f, err := os.OpenFile(testOutputFileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755)
if err != nil {
return nil, err
}
return f, err
}
func main() {
testCase = make([]*inputData, 0)
input, err := getInputData()
if err != nil {
log.Fatalf("An error happened! %s", err.Error())
}
calculateSumSquares(input)
outputStream, err := setOutputStream()
if err != nil {
log.Fatalf("An error happened trying open an output stream %s", err.Error())
}
defer outputStream.Close()
printResult(input, outputStream)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment