Skip to content

Commit

Permalink
added esusu and alpaca
Browse files Browse the repository at this point in the history
  • Loading branch information
nebuxadnezzar committed Jun 27, 2024
1 parent 6c7693d commit 469a5ea
Show file tree
Hide file tree
Showing 36 changed files with 59,658 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Interview take home coding assignments

- [alpaca](./alpaca/README.md)
- [esusu](./esusu/README.md)
21 changes: 21 additions & 0 deletions alpaca/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
BINARY_NAME=lottery-winners
MAIN_NAME=cmd/cli.go
DIST=./dist

run:
go run ${MAIN_NAME} $(arg1)

build:
GOARCH=amd64 GOOS=darwin go build -o ${DIST}-darwin/${BINARY_NAME} ${MAIN_NAME}
GOARCH=amd64 GOOS=linux go build -o ${DIST}-linux/${BINARY_NAME} ${MAIN_NAME}
GOARCH=amd64 GOOS=windows go build -o ${DIST}-windows/${BINARY_NAME} ${MAIN_NAME}

deps:
@[ -d $(DIST)-linux ] || mkdir -p $(DIST)-linux
@[ -d $(DIST)-darwin ] || mkdir -p $(DIST)-darwin
@[ -d $(DIST)-windows ] || mkdir -p $(DIST)-windows

clean:
@rm -rf ${DIST}*

all: deps build
78 changes: 78 additions & 0 deletions alpaca/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

## Story
__Alpaca Inc(?)__ presented me with this take home assignment described [here](pdf/Software_Engineering_Test.pdf).

## Data
Sample file [here](data/lottery-300.txt)
```
4 79 13 80 56
71 84 48 85 38
41 65 39 82 36
36 42 79 21 58
...
```
__or__ to generate 10 million records lottery numbers file yourself
```ruby
ruby -e '50000000.times.map{rand(1..90)}.each_with_index{|a,i| printf("\n") if i > 0 && i % 5 == 0; printf("%s ", a)}'

or to generate without trailing space

ruby -e '50000000.times.map{rand(1..90)}.each_with_index{|a,i| if i > 0 then i % 5 == 0 ? printf("\n") : print(" ") end; printf("%d",a)}'
```
### Building binary
```
make all
```
### Running code
```
make run arg1=~/path/to/10m-v2.txt
```

### Run results

```
go run cmd/cli.go ~/test-data/10m-v2.txt
error loading record 85 21 67 93 2
: value 93 out of range
error loading record 10 85 69 -7 50
: value -7 out of range
LOADED 10000000 records
READY: enter your numbers below or press Ctrl+C to exit
--> 77 88 21 33 1
numbers matching | winners
5 | 0
4 | 12
3 | 917
2 | 25008
winners for numbers [77 88 21 33 1]
report numbers , execution time 63.910126ms
```

### Alpaca feedback
*I will leave it mostly uncommented ...*

>Unfortunately you were not selected to advance to the next stage of screening.
>
>For the homework I would like to share the following feedback:
>
>Pros:
>- Divided into multiple packages
>- Faster than linear search
>- Fun CLI with history
>
>Cons:
>
>- It doesn't implement the assignment (e.g. it should return the number of winners with 5, 4, 3 and 2 matches) <span style="color:blue">*Why?*</span>
>- No unit tests <span style="color:blue">*None were required in the assignment.*</span>
>- No validation of the lotto numbers (e.g they should be in the range of [1 ... 90], each line should contain 5 entries)
>- O(N) solution with a constant less than one <span style="color:blue">*Is sub-linear solution that searches 10 million records in ~60ms bad?*</span>
>- The prompt handling requires external utilities (stty) instead of relying on libraries
>- CTRL-C handling should be done using signals instead of terminal manipulation
>- Anding the bitsets could be done inplace preventing unnecessary memory allocation in cmd.op
>
I can think of some kind of solution using sort whereby you first sort every line, then sort whole file thus having the same items together and then use binary search to locate one of the same items in the sequence and then you would need to count them. But at this point I can't think of anything else, so if someone can please share.
I think the code performed pretty good finding and counting winners in 10 million set under 70ms (I tried several runs).
150 changes: 150 additions & 0 deletions alpaca/bitset/bitset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package bitset

import (
"alpaca/util"
"fmt"
"math"
)

const MAXBITSETSZ = 20_000_000

type Bitset []uint8

func NewBitset(n int) Bitset {
sz := 0
if n > 0 {
if n > MAXBITSETSZ {
n = MAXBITSETSZ
}
sz = int(math.Ceil(float64(n+7) / 8))
}
return make(Bitset, sz)
}

func (bs Bitset) Len() int {
return 8 * len(bs)
}

func (bs Bitset) Get(idx int) (bool, error) {
if pos, offset, err := getPosAndOffset(idx, bs.Len()); err == nil {
return (bs[pos] & (uint8(1) << offset)) != 0, nil
} else {
return false, err
}
}

func (bs Bitset) Set(idx int, val bool) error {
if pos, offset, err := getPosAndOffset(idx, bs.Len()); err == nil {
if val {
bs[pos] |= (uint8(1) << offset)
} else {
bs[pos] &= ^(uint8(1) << offset)
}
} else {
return err
}
return nil
}

func (bs Bitset) SetAll(idx []int, val bool) error {
for _, v := range idx {
if err := bs.Set(v, val); err != nil {
return err
}
}
return nil
}

func getPosAndOffset(idx int, ln int) (int, uint, error) {
if idx < 0 {
idx = ln + idx
}
if !(idx >= 0 && idx < ln) {
return -1, 0, fmt.Errorf("index %d out of range", idx)
}
pos := idx / 8
offset := uint(idx % 8)
return pos, offset, nil
}

func (bs Bitset) Intersection(bp *Bitset) Bitset {
f := func(b1, b2 uint8) uint8 { return (b1 & b2) }
return op(bs, *bp, f)
}

func (bs Bitset) Union(bp *Bitset) Bitset {
f := func(b1, b2 uint8) uint8 { return (b1 | b2) }
return op(bs, *bp, f)
}

func (bs Bitset) Difference(bp *Bitset) Bitset {
f := func(b1, b2 uint8) uint8 { return (b1 & b2) }
a := op(bs, *bp, f).Slice()
c := bs.Clone()
for _, v := range a {
c.Set(v, false)
}
return c
}

func op(bs1, bs2 Bitset, opfunc func(uint8, uint8) uint8) Bitset {
l1 := bs1.Len()
l2 := bs2.Len()
if l1 == 0 || l2 == 0 {
return NewBitset(0)
}
sz := util.Min(l1, l2) / 8
bi := NewBitset(util.Max(l1, l2))
for i, k := 0, sz; i < k; i++ {
b := opfunc(bs1[i], bs2[i])
if b > 0 {
bi[i] |= b
}
}
return bi
}

func (bs Bitset) Invert() {
for k, v := range bs {
bs[k] = ^v
}
}

func (bs Bitset) ClearAll() {
for k, v := range bs {
bs[k] = v ^ v
}
}

func (bs Bitset) Clone() Bitset {
bn := make(Bitset, len(bs))
copy(bn, bs)
return bn
}

func (bs Bitset) Slice() []int {
l := len(bs) * 8 / 3
if l < 1 {
l = 1
}
a := make([]int, 0, l)
mask := uint8(1)
for k, v := range bs {
if v < 1 {
continue
}
for i := uint(0); i < 8; i++ {
b := mask & (v >> i)
if b > 0 {
a = append(a, k*8+int(i))
}
}
}
return a
}

func (bs Bitset) dump() {
for k, v := range bs {
fmt.Printf("%02d %08b\n", k, v)
}
}
Loading

0 comments on commit 469a5ea

Please sign in to comment.