add: more exercises to funcs

This commit is contained in:
Inanc Gumus
2019-06-21 12:18:33 +03:00
parent c5f69f98b0
commit 6ed4c0fc8b
13 changed files with 553 additions and 4 deletions

View File

@ -24,6 +24,4 @@ Let's exercise with the scanner and maps.
6. **[Create the Log Parser program from scratch](https://github.com/inancgumus/learngo/tree/master/23-input-scanning/exercises/06-log-parser)**
You've watched the lecture. Now, try to create the same log parser program on your own. Do not look at the lecture, and the existing source code.
Click the link for more details.
You've watched the lecture. Now, try to create the same log parser program on your own. Do not look at the lecture, and the existing source code. The link contains the code where you need to start working on.

View File

@ -6,4 +6,12 @@
2. **[Refactor the Game Store to Funcs - Step #2](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/refactor-to-funcs-2)**
Let's continue the refactoring from the previous exercise. This time, you're going to refactor the command handling logic.
Let's continue the refactoring from the previous exercise. This time, you're going to refactor the command handling logic.
3. **[Refactor the Game Store to Funcs - Step #3](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/refactor-to-funcs-3)**
Let's continue from the previous exercise. This time, you're going to add json encoding and decoding using funcs.
4. **[Rewrite the Log Parser program using funcs](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/rewrite-log-parser-using-funcs)**
You've watched the lecture. Now, try to rewrite the same log parser program using funcs on your own.

View File

@ -0,0 +1,70 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"strconv"
"strings"
)
func runCmd(input string, games []game, byID map[int]game) bool {
fmt.Println()
cmd := strings.Fields(input)
if len(cmd) == 0 {
return true
}
switch cmd[0] {
case "quit":
return cmdQuit()
case "list":
return cmdList(games)
case "id":
return cmdByID(cmd, games, byID)
}
return true
}
func cmdQuit() bool {
fmt.Println("bye!")
return false
}
func cmdList(games []game) bool {
for _, g := range games {
printGame(g)
}
return true
}
func cmdByID(cmd []string, games []game, byID map[int]game) bool {
if len(cmd) != 2 {
fmt.Println("wrong id")
return true
}
id, err := strconv.Atoi(cmd[1])
if err != nil {
fmt.Println("wrong id")
return true
}
g, ok := byID[id]
if !ok {
fmt.Println("sorry. i don't have the game")
return true
}
printGame(g)
return true
}

View File

@ -0,0 +1,74 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import "fmt"
const data = `
[
{
"id": 1,
"name": "god of war",
"genre": "action adventure",
"price": 50
},
{
"id": 2,
"name": "x-com 2",
"genre": "strategy",
"price": 40
},
{
"id": 3,
"name": "minecraft",
"genre": "sandbox",
"price": 20
}
]`
type item struct {
id int
name string
price int
}
type game struct {
item
genre string
}
func load() (games []game) {
games = addGame(games, newGame(1, 50, "god of war", "action adventure"))
games = addGame(games, newGame(2, 40, "x-com 2", "strategy"))
games = addGame(games, newGame(3, 20, "minecraft", "sandbox"))
return
}
func addGame(games []game, g game) []game {
return append(games, g)
}
func newGame(id, price int, name, genre string) game {
return game{
item: item{id: id, name: name, price: price},
genre: genre,
}
}
func indexByID(games []game) (byID map[int]game) {
byID = make(map[int]game)
for _, g := range games {
byID[g.id] = g
}
return
}
func printGame(g game) {
fmt.Printf("#%d: %-15q %-20s $%d\n",
g.id, g.name, "("+g.genre+")", g.price)
}

View File

@ -0,0 +1,61 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// ---------------------------------------------------------
// EXERCISE: Refactor the game store to funcs - step #3
//
// Let's continue from the previous exercise. This time,
// you're going to add json encoding and decoding using
// funcs.
//
// 1- Create a new command in a func that encodes the
// game store data to json and terminates the program.
// Lastly, add it to runCmd func.
//
// For more information, see: "Encode" exercise from
// the structs section.
//
// Name : cmdSave
// Inputs: []game
// Output: bool
//
// 2- Refactor the load() to load the games from the
// `data` constant (it's in the games.go as well).
//
// For more information, see: "Decode" exercise from
// the structs section.
//
// ---------------------------------------------------------
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
games := load()
byID := indexByID(games)
fmt.Printf("Inanc's game store has %d games.\n", len(games))
in := bufio.NewScanner(os.Stdin)
for {
fmt.Printf(`
> list : lists all the games
> id N : queries a game by id
> quit : quits
`)
if !in.Scan() || !runCmd(in.Text(), games, byID) {
break
}
}
}

View File

@ -0,0 +1,91 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
func runCmd(input string, games []game, byID map[int]game) bool {
fmt.Println()
cmd := strings.Fields(input)
if len(cmd) == 0 {
return true
}
switch cmd[0] {
case "quit":
return cmdQuit()
case "list":
return cmdList(games)
case "id":
return cmdByID(cmd, games, byID)
case "save":
return cmdSave(games)
}
return true
}
func cmdQuit() bool {
fmt.Println("bye!")
return false
}
func cmdList(games []game) bool {
for _, g := range games {
printGame(g)
}
return true
}
func cmdByID(cmd []string, games []game, byID map[int]game) bool {
if len(cmd) != 2 {
fmt.Println("wrong id")
return true
}
id, err := strconv.Atoi(cmd[1])
if err != nil {
fmt.Println("wrong id")
return true
}
g, ok := byID[id]
if !ok {
fmt.Println("sorry. i don't have the game")
return true
}
printGame(g)
return true
}
func cmdSave(games []game) bool {
// load the data into encodable game values
var jg []jsonGame
for _, g := range games {
jg = append(jg, jsonGame{g.id, g.name, g.genre, g.price})
}
out, err := json.MarshalIndent(jg, "", "\t")
if err != nil {
fmt.Println("sorry, can't save:", err)
return true
}
fmt.Println(string(out))
return false
}

View File

@ -0,0 +1,93 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"encoding/json"
"fmt"
)
const data = `
[
{
"id": 1,
"name": "god of war",
"genre": "action adventure",
"price": 50
},
{
"id": 2,
"name": "x-com 2",
"genre": "strategy",
"price": 40
},
{
"id": 3,
"name": "minecraft",
"genre": "sandbox",
"price": 20
}
]`
type item struct {
id int
name string
price int
}
type game struct {
item
genre string
}
// encodable and decodable game type
type jsonGame struct {
ID int `json:"id"`
Name string `json:"name"`
Genre string `json:"genre"`
Price int `json:"price"`
}
func load() (games []game) {
// load the initial data from json
var decoded []jsonGame
if err := json.Unmarshal([]byte(data), &decoded); err != nil {
fmt.Println("Sorry, there is a problem:", err)
return
}
// load the data into usual game values
for _, dg := range decoded {
games = addGame(games, newGame(dg.ID, dg.Price, dg.Name, dg.Genre))
}
return games
}
func addGame(games []game, g game) []game {
return append(games, g)
}
func newGame(id, price int, name, genre string) game {
return game{
item: item{id: id, name: name, price: price},
genre: genre,
}
}
func indexByID(games []game) (byID map[int]game) {
byID = make(map[int]game)
for _, g := range games {
byID[g.id] = g
}
return
}
func printGame(g game) {
fmt.Printf("#%d: %-15q %-20s $%d\n",
g.id, g.name, "("+g.genre+")", g.price)
}

View File

@ -0,0 +1,36 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
games := load()
byID := indexByID(games)
fmt.Printf("Inanc's game store has %d games.\n", len(games))
in := bufio.NewScanner(os.Stdin)
for {
fmt.Printf(`
> list : lists all the games
> id N : queries a game by id
> save : exports the data to json and quits
> quit : quits
`)
if !in.Scan() || !runCmd(in.Text(), games, byID) {
break
}
}
}

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org -100
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org FOUR
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,94 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
// result stores the parsed result for a domain
type result struct {
domain string
visits int
// add more metrics if needed
}
// parser keep tracks of the parsing
type parser struct {
sum map[string]result // metrics per domain
domains []string // unique domain names
total int // total visits for all domains
lines int // number of parsed lines (for the error messages)
}
func main() {
p := parser{sum: make(map[string]result)}
// Scan the standard-in line by line
in := bufio.NewScanner(os.Stdin)
for in.Scan() {
p.lines++
// Parse the fields
fields := strings.Fields(in.Text())
if len(fields) != 2 {
fmt.Printf("wrong input: %v (line #%d)\n", fields, p.lines)
return
}
domain := fields[0]
// Sum the total visits per domain
visits, err := strconv.Atoi(fields[1])
if visits < 0 || err != nil {
fmt.Printf("wrong input: %q (line #%d)\n", fields[1], p.lines)
return
}
// Collect the unique domains
if _, ok := p.sum[domain]; !ok {
p.domains = append(p.domains, domain)
}
// Keep track of total and per domain visits
p.total += visits
// You cannot assign to composite values
// p.sum[domain].visits += visits
// create and assign a new copy of `visit`
p.sum[domain] = result{
domain: domain,
visits: visits + p.sum[domain].visits,
}
}
// Print the visits per domain
sort.Strings(p.domains)
fmt.Printf("%-30s %10s\n", "DOMAIN", "VISITS")
fmt.Println(strings.Repeat("-", 45))
for _, domain := range p.domains {
parsed := p.sum[domain]
fmt.Printf("%-30s %10d\n", domain, parsed.visits)
}
// Print the total visits for all domains
fmt.Printf("\n%-30s %10d\n", "TOTAL", p.total)
// Let's handle the error
if err := in.Err(); err != nil {
fmt.Println("> Err:", err)
}
}