From 89c86772c2ea40b983b31fbf7ccab6f66c1e6c46 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 26 Sep 2021 20:28:37 +0300 Subject: [PATCH 1/2] Day 2-3 tasks --- courses/golang/ex01-downcase/downcase.go | 14 +++ courses/golang/ex01-downcase/go.mod | 3 + courses/golang/ex02-cipher/cipher.go | 118 ++++++++++++++++++ courses/golang/ex02-cipher/go.mod | 3 + courses/golang/ex03-stack/go.mod | 3 + courses/golang/ex03-stack/stack.go | 21 ++++ courses/golang/ex04-brackets/bracket_push.go | 27 ++++ courses/golang/ex04-brackets/go.mod | 3 + courses/golang/ex05-parallel/go.mod | 3 + .../parrallel_letter_frequency.go | 28 +++++ courses/golang/ex06-barbershop/barbershop.go | 78 ++++++++++++ courses/golang/ex07-container/container.go | 52 ++++++++ courses/golang/ex07-container/go.mod | 3 + 13 files changed, 356 insertions(+) create mode 100644 courses/golang/ex01-downcase/downcase.go create mode 100644 courses/golang/ex01-downcase/go.mod create mode 100644 courses/golang/ex02-cipher/go.mod create mode 100644 courses/golang/ex03-stack/go.mod create mode 100644 courses/golang/ex03-stack/stack.go create mode 100644 courses/golang/ex04-brackets/bracket_push.go create mode 100644 courses/golang/ex04-brackets/go.mod create mode 100644 courses/golang/ex05-parallel/go.mod create mode 100644 courses/golang/ex05-parallel/parrallel_letter_frequency.go create mode 100644 courses/golang/ex06-barbershop/barbershop.go create mode 100644 courses/golang/ex07-container/container.go create mode 100644 courses/golang/ex07-container/go.mod diff --git a/courses/golang/ex01-downcase/downcase.go b/courses/golang/ex01-downcase/downcase.go new file mode 100644 index 00000000..fd39fb66 --- /dev/null +++ b/courses/golang/ex01-downcase/downcase.go @@ -0,0 +1,14 @@ +package downcase + +func Downcase(str string) (lowerStr string, err error) { + + for _, char := range str { + if 65 <= char && char <= 90 { + lowerStr += string(char + 32) + } else { + lowerStr += string(char) + } + } + + return lowerStr, nil +} diff --git a/courses/golang/ex01-downcase/go.mod b/courses/golang/ex01-downcase/go.mod new file mode 100644 index 00000000..3d3d3ea5 --- /dev/null +++ b/courses/golang/ex01-downcase/go.mod @@ -0,0 +1,3 @@ +module downcase + +go 1.17 diff --git a/courses/golang/ex02-cipher/cipher.go b/courses/golang/ex02-cipher/cipher.go index 9b76c8d3..fdfb3353 100644 --- a/courses/golang/ex02-cipher/cipher.go +++ b/courses/golang/ex02-cipher/cipher.go @@ -1,6 +1,124 @@ package cipher +import ( + "regexp" + "strings" +) + type Cipher interface { Encode(string) string Decode(string) string } + +type caesar struct{} + +type shift struct { + offset int +} + +type vigenere struct { + s string +} + +func NewCaesar() Cipher { + return caesar{} +} + +func NewShift(offset int) Cipher { + if offset == 0 || offset > 25 || offset < -25 { + return nil + } + return shift{offset: offset} +} + +func NewVigenere(s string) Cipher { + r, _ := regexp.Compile("^[a-z]+$") + if !r.MatchString(s) { + return nil + } + for _, v := range s { + if v != 'a' { + return vigenere{s: s} + } + } + return nil +} + +func (c caesar) Encode(s string) string { + s = ToCleanAndLower(s) + return string(shiftLetters([]byte(s), 3)) +} + +func (c caesar) Decode(s string) string { + return string(shiftLetters([]byte(s), 26-3)) +} + +func (sh shift) Encode(s string) string { + var offset byte + s = ToCleanAndLower(s) + if sh.offset < 0 { + offset = byte(sh.offset + 26) + } else { + offset = byte(sh.offset) + } + return string(shiftLetters([]byte(s), offset)) +} + +func (sh shift) Decode(s string) string { + var offset byte + if sh.offset > 0 { + offset = byte(26 - sh.offset) + } else { + offset = byte(-sh.offset) + } + return string(shiftLetters([]byte(s), offset)) +} + +func (v vigenere) Encode(s string) string { + s = ToCleanAndLower(s) + return string(translateLetters([]byte(s), []byte(v.s))) +} + +func (v vigenere) Decode(s string) string { + keys := reverseKeys([]byte(v.s)) + return string(translateLetters([]byte(s), keys)) +} + +func ToCleanAndLower(s string) string { + r, _ := regexp.Compile("[^A-z]+") + letterChunks := r.Split(s, -1) + cleanS := strings.Join(letterChunks, "") + newS := strings.ToLower(cleanS) + return newS +} + +func shiftLetters(bytes []byte, offset byte) []byte { + for i := range bytes { + bytes[i] += offset + if bytes[i] > 'z' { + bytes[i] -= 26 + } + } + return bytes +} + +func translateLetters(bytes []byte, keys []byte) []byte { + key_num := len(keys) + for i := range bytes { + key := byte(keys[i%key_num] - 'a') + bytes[i] += key + if bytes[i] > 'z' { + bytes[i] -= 26 + } + } + return bytes +} + +func reverseKeys(bytes []byte) []byte { + for i := range bytes { + bytes[i] -= 'a' + bytes[i] = 26 - bytes[i] + bytes[i] += 'a' + } + return bytes +} diff --git a/courses/golang/ex02-cipher/go.mod b/courses/golang/ex02-cipher/go.mod new file mode 100644 index 00000000..cfffda48 --- /dev/null +++ b/courses/golang/ex02-cipher/go.mod @@ -0,0 +1,3 @@ +module cipher + +go 1.17 diff --git a/courses/golang/ex03-stack/go.mod b/courses/golang/ex03-stack/go.mod new file mode 100644 index 00000000..f9a06e57 --- /dev/null +++ b/courses/golang/ex03-stack/go.mod @@ -0,0 +1,3 @@ +module stack + +go 1.17 diff --git a/courses/golang/ex03-stack/stack.go b/courses/golang/ex03-stack/stack.go new file mode 100644 index 00000000..b224ba98 --- /dev/null +++ b/courses/golang/ex03-stack/stack.go @@ -0,0 +1,21 @@ +package stack + +type Stack struct { + items []int +} + +func New() *Stack { + myStack := Stack{} + return &myStack +} + +func (s *Stack) Push(i int) { + s.items = append(s.items, i) +} + +func (s *Stack) Pop() int { + l := len(s.items) - 1 + toRemove := s.items[l] + s.items = s.items[:l] + return toRemove +} diff --git a/courses/golang/ex04-brackets/bracket_push.go b/courses/golang/ex04-brackets/bracket_push.go new file mode 100644 index 00000000..c4203b27 --- /dev/null +++ b/courses/golang/ex04-brackets/bracket_push.go @@ -0,0 +1,27 @@ +package brackets + +func Bracket(s string) (bool, error) { + bracket := map[rune]rune{ + '}': '{', + ')': '(', + ']': '[', + } + stack := make([]rune, 0) + for _, b := range s { + v, ok := bracket[b] + if ok { + length := len(stack) + if length > 0 && stack[length-1] == v { + stack = stack[:len(stack)-1] + } else { + return false, nil + } + } else { + stack = append(stack, b) + } + } + if len(stack) > 0 { + return false, nil + } + return true, nil +} diff --git a/courses/golang/ex04-brackets/go.mod b/courses/golang/ex04-brackets/go.mod new file mode 100644 index 00000000..417ff321 --- /dev/null +++ b/courses/golang/ex04-brackets/go.mod @@ -0,0 +1,3 @@ +module brackets + +go 1.17 diff --git a/courses/golang/ex05-parallel/go.mod b/courses/golang/ex05-parallel/go.mod new file mode 100644 index 00000000..e378d1e5 --- /dev/null +++ b/courses/golang/ex05-parallel/go.mod @@ -0,0 +1,3 @@ +module letter + +go 1.17 diff --git a/courses/golang/ex05-parallel/parrallel_letter_frequency.go b/courses/golang/ex05-parallel/parrallel_letter_frequency.go new file mode 100644 index 00000000..6acdc30f --- /dev/null +++ b/courses/golang/ex05-parallel/parrallel_letter_frequency.go @@ -0,0 +1,28 @@ +package letter + +func Frequency(s string) map[rune]uint64 { + freq := make(map[rune]uint64) + for _, l := range s { + freq[l]++ + } + return freq +} + +func ConcurrentFrequency(ss []string) map[rune]uint64 { + allFreq := make(map[rune]uint64) + c := make(chan map[rune]uint64, len(ss)) + + for _, s := range ss { + go func(c chan map[rune]uint64, s string) { + c <- Frequency(s) + }(c, s) + } + + for i := 0; i < len(ss); i++ { + freq := <-c + for k, v := range freq { + allFreq[k] += v + } + } + return allFreq +} diff --git a/courses/golang/ex06-barbershop/barbershop.go b/courses/golang/ex06-barbershop/barbershop.go new file mode 100644 index 00000000..1b324117 --- /dev/null +++ b/courses/golang/ex06-barbershop/barbershop.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "time" +) + +func Barber(client_start chan byte, client_end chan bool) { + for { + select { + case num := <-client_start: + fmt.Printf("Start working with client %d.\n", num) + time.Sleep(700 * time.Millisecond) + client_end <- true + fmt.Printf("End working with client %d.\n", num) + default: + fmt.Println("Sleeping...") + fmt.Println() + time.Sleep(100 * time.Millisecond) + } + } +} + +func Barbershop(seats byte, passer_in chan byte, passer_out chan byte, done chan byte) { + client_start := make(chan byte, seats) + client_end := make(chan bool) + emptySeats := seats + go Barber(client_start, client_end) + + for { + select { + case num := <-passer_in: + fmt.Printf("\nNew client: %d.\n", num) + if emptySeats > 0 { + client_start <- num + fmt.Printf("Client %d took an empty seat.\n", num) + emptySeats-- + fmt.Printf("Empty seats: %d.\n", emptySeats) + } else { + go func() { + time.Sleep(600 * time.Millisecond) + passer_out <- num + }() + fmt.Printf("Client %d will come back later.\n", num) + } + case <-client_end: + emptySeats++ + fmt.Printf("Empty seats: %d.\n", emptySeats) + done <- emptySeats + } + } +} + +func main() { + passer_in := make(chan byte) + passer_out := make(chan byte) + done := make(chan byte, 15) + seats := byte(4) + go Barbershop(seats, passer_in, passer_out, done) + + for i := byte(1); i < 16; { + time.Sleep(300 * time.Millisecond) + select { + case num := <-passer_out: + passer_in <- num + default: + passer_in <- i + i++ + } + } + + for { + emptySeats := <-done + if emptySeats == seats { + break + } + } +} diff --git a/courses/golang/ex07-container/container.go b/courses/golang/ex07-container/container.go new file mode 100644 index 00000000..cff7a823 --- /dev/null +++ b/courses/golang/ex07-container/container.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "syscall" +) + +func main() { + switch os.Args[1] { + case "run": + parent() + case "child": + child() + default: + panic("wat should i do") + } +} + +func parent() { + cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID, + } + + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + must(cmd.Run()) +} + +func child() { + fmt.Printf("\nPID: %d\n\n", os.Getpid()) + + cmd := exec.Command(os.Args[2], os.Args[3:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + must(syscall.Chroot("rootfs")) + must(os.Chdir("/")) + must(syscall.Mount("proc", "proc", "proc", 0, "")) + must(cmd.Run()) + must(syscall.Unmount("proc", 0)) +} + +func must(err error) { + if err != nil { + panic(err) + } +} diff --git a/courses/golang/ex07-container/go.mod b/courses/golang/ex07-container/go.mod new file mode 100644 index 00000000..c0ecf8b6 --- /dev/null +++ b/courses/golang/ex07-container/go.mod @@ -0,0 +1,3 @@ +module main + +go 1.17 From fd838b76386312bb3bd81d1aedd77020bdaadd48 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 3 Oct 2021 19:34:20 +0300 Subject: [PATCH 2/2] 9-11 tasks --- courses/golang/ex09-tcp-fibonacci/client.go | 34 ++++++++ courses/golang/ex09-tcp-fibonacci/fib.go | 47 ++++++++++ courses/golang/ex09-tcp-fibonacci/server.go | 42 +++++++++ courses/golang/ex10-workerpool/goroutines.go | 45 ++++++++++ courses/golang/ex11-orderbook/orderbook.go | 92 +++++++++++++++++++- 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 courses/golang/ex09-tcp-fibonacci/client.go create mode 100644 courses/golang/ex09-tcp-fibonacci/fib.go create mode 100644 courses/golang/ex09-tcp-fibonacci/server.go diff --git a/courses/golang/ex09-tcp-fibonacci/client.go b/courses/golang/ex09-tcp-fibonacci/client.go new file mode 100644 index 00000000..ddc9d708 --- /dev/null +++ b/courses/golang/ex09-tcp-fibonacci/client.go @@ -0,0 +1,34 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "net" + "os" + "strconv" +) + +func main() { + conn, err := net.Dial("tcp", "127.0.0.1:8080") + handleError(err) + + defer conn.Close() + + // var resp Response + scan := bufio.NewScanner(os.Stdin) + for scan.Scan() { + input, err := strconv.ParseInt(scan.Text(), 10, 64) + handleError(err) + request := RequestFib{Number: int(input)} + + encoder := json.NewEncoder(conn) + handleError(encoder.Encode(request)) + + var resp ResponseFib + decoder := json.NewDecoder(conn) + handleError(decoder.Decode(&resp)) + + fmt.Printf("%s %d\n", resp.Time, resp.Fib) + } +} diff --git a/courses/golang/ex09-tcp-fibonacci/fib.go b/courses/golang/ex09-tcp-fibonacci/fib.go new file mode 100644 index 00000000..4dc61b03 --- /dev/null +++ b/courses/golang/ex09-tcp-fibonacci/fib.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "math/big" + "time" +) + +type RequestFib struct { + Number int +} + +type ResponseFib struct { + Number int + Fib *big.Int + Time time.Duration +} + +var fibCache map[int]*big.Int + +func fib(num int) *big.Int { + if num < 0 { + panic("num < 0") + } + + if val, ok := fibCache[num]; ok { + return val + } + + size := len(fibCache) + a := fibCache[size-2] + b := fibCache[size-1] + + for i := size; i <= num; i++ { + a.Add(a, b) + fibCache[i] = a + a, b = b, a + } + return b +} + +func handleError(err error) { + if err == nil { + return + } + fmt.Println("Error: ", err.Error()) +} diff --git a/courses/golang/ex09-tcp-fibonacci/server.go b/courses/golang/ex09-tcp-fibonacci/server.go new file mode 100644 index 00000000..54968374 --- /dev/null +++ b/courses/golang/ex09-tcp-fibonacci/server.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/json" + "fmt" + "math/big" + "net" + "time" +) + + + +func main() { + fibCache = make(map[int]*big.Int) + fibCache[0] = big.NewInt(0) + fibCache[1] = big.NewInt(1) + + fmt.Println("Booting up server...") + const port string = "8080" + + ln, err := net.Listen("tcp", ":"+port) + handleError(err) + fmt.Printf("Listening on localhost:%v\n", port) + conn, err := ln.Accept() + handleError(err) + + for { + var request RequestFib + decoder := json.NewDecoder(conn) + handleError(decoder.Decode(&request)) + + start := time.Now() + resp := ResponseFib{ + Number: request.Number, + Fib: fib(request.Number), + Time: time.Since(start), + } + + enc := json.NewEncoder(conn) + handleError(enc.Encode(resp)) + } +} diff --git a/courses/golang/ex10-workerpool/goroutines.go b/courses/golang/ex10-workerpool/goroutines.go index d5cba996..a00b481b 100644 --- a/courses/golang/ex10-workerpool/goroutines.go +++ b/courses/golang/ex10-workerpool/goroutines.go @@ -1,4 +1,49 @@ package goroutines +import ( + "bufio" + "fmt" + "os" + "strconv" + "sync" + "time" +) + func Run(poolSize int) { + jobs := make(chan float64, poolSize) + var wg sync.WaitGroup + scanner := bufio.NewScanner(os.Stdin) + + id := 1 + for scanner.Scan() { + input := string(scanner.Bytes()) + f, err := strconv.ParseFloat(input, 64) + handleError(err) + jobs <- f + + if id <= poolSize { + wg.Add(1) + go workerTask(id, jobs, &wg) + id++ + } + } + close(jobs) + wg.Wait() } + +func workerTask(id int, jobs <-chan float64, wg *sync.WaitGroup) { + fmt.Printf("worker:%d spawning\n", id) + for job := range jobs { + fmt.Printf("worker:%d sleep:%.1f\n", id, job) + time.Sleep(time.Duration(int(job*1000)) * time.Millisecond) + } + fmt.Printf("worker:%d stopping\n", id) + wg.Done() +} + +func handleError(err error) { + if err == nil { + return + } + fmt.Println("ERROR: ", err) +} \ No newline at end of file diff --git a/courses/golang/ex11-orderbook/orderbook.go b/courses/golang/ex11-orderbook/orderbook.go index ca4161e7..fa34c8b7 100644 --- a/courses/golang/ex11-orderbook/orderbook.go +++ b/courses/golang/ex11-orderbook/orderbook.go @@ -1,7 +1,13 @@ package orderbook +import ( + "fmt" + "sort" +) + type Orderbook struct { - // TODO + Ask []*Order + Bid []*Order } func New() *Orderbook { @@ -10,6 +16,86 @@ func New() *Orderbook { } func (orderbook *Orderbook) Match(order *Order) ([]*Trade, *Order) { - // TODO - return nil, nil + + return orderbook.Trade(order) +} + +func (orderbook *Orderbook) Trade(order *Order) ([]*Trade, *Order) { + var tradeArr []*Trade + var propArr *[]*Order + + switch order.Side { + case SideAsk: + propArr = &orderbook.Bid + case SideBid: + propArr = &orderbook.Ask + } + + for order.Volume != 0 { + if len(*propArr) == 0 { + orderbook.RejectOrder(order) + break + } + + theBestProp := (*propArr)[0] + + if propAccepted(order, theBestProp, 0) { + var tradeValue uint64 + if order.Volume < theBestProp.Volume { + tradeValue = order.Volume + } else { + tradeValue = theBestProp.Volume + } + + trade := Trade{theBestProp, order, tradeValue, theBestProp.Price} + order.Volume -= tradeValue + theBestProp.Volume -= tradeValue + tradeArr = append(tradeArr, &trade) + + if theBestProp.Volume == 0 { + *propArr = (*propArr)[1:] + } + } else { + orderbook.RejectOrder(order) + break + } + } + + if order.Volume > 0 && order.Kind == KindMarket { + return tradeArr, order + } + + return tradeArr, nil +} + +func propAccepted(order *Order, prop *Order, side int) bool { + switch order.Kind { + case KindMarket: + return true + case KindLimit: + switch order.Side { + case SideAsk: + return order.Price <= prop.Price + case SideBid: + return order.Price >= prop.Price + } + } + + fmt.Println("Inaccessible point was accessed") + return false +} + +func (orderbook *Orderbook) RejectOrder(order *Order) { + switch order.Side { + case SideAsk: + orderbook.Ask = append(orderbook.Ask, order) + sort.Slice(orderbook.Ask, func(i, j int) bool { + return orderbook.Ask[i].Price < orderbook.Ask[j].Price + }) + case SideBid: + orderbook.Bid = append(orderbook.Bid, order) + sort.Slice(orderbook.Bid, func(i, j int) bool { + return orderbook.Bid[i].Price > orderbook.Bid[j].Price + }) + } }