diff --git a/x-tba/foundations/02-variables/types/main.go b/x-tba/foundations/02-variables/types/main.go new file mode 100644 index 0000000..e62bc4f --- /dev/null +++ b/x-tba/foundations/02-variables/types/main.go @@ -0,0 +1,51 @@ +// 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" + "math" + "os" + "runtime" + "time" +) + +func main() { + // int, float64, bool, string + var ( + cpus int + path, dir string + max float64 + ) + + cpus = runtime.NumCPU() + path = os.Getenv("PATH") + max = math.Max(1.5, 2.5) + dir, _ = os.Getwd() + now := time.Now() + + // cpus := runtime.NumCPU() + // path := os.Getenv("PATH") + // max := math.Max(1.5, 2.5) + // dir, _ := os.Getwd() + + // dir = `"` + dir + `"` + // dir = strconv.Quote(dir) + // cpus++ + // cpus *= 2.5 + // max++ + // max /= 2.5 + // paths = strings.Split(path, ":") + // path = paths[0] + + fmt.Printf("# of CPUS : %d\n", cpus) + fmt.Printf("Path : %s\n", path) + fmt.Printf("max(1.5, 2.5) : %g\n", max) + fmt.Printf("Current Directory: %s\n", dir) + fmt.Printf("Current Time : %s\n", now) +} diff --git a/x-tba/foundations/03-if-switch-loop/01-for-crunch-the-primes/main.go b/x-tba/foundations/03-if-switch-loop/01-for-crunch-the-primes/main.go index 3d6ee56..6720d87 100644 --- a/x-tba/foundations/03-if-switch-loop/01-for-crunch-the-primes/main.go +++ b/x-tba/foundations/03-if-switch-loop/01-for-crunch-the-primes/main.go @@ -36,12 +36,12 @@ main: switch { // prime - case n == 2 || n == 3: + case n == 2, n == 3: fmt.Print(n, " ") continue // not a prime - case n <= 1 || n%2 == 0 || n%3 == 0: + case n <= 1, n%2 == 0, n%3 == 0: continue } diff --git a/x-tba/foundations/calc/01-shortdecl-int-conv/main.go b/x-tba/foundations/calc/01-shortdecl-int-conv/main.go index 7f61903..a26524c 100644 --- a/x-tba/foundations/calc/01-shortdecl-int-conv/main.go +++ b/x-tba/foundations/calc/01-shortdecl-int-conv/main.go @@ -1,3 +1,10 @@ +// 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 ( @@ -7,6 +14,26 @@ import ( ) func main() { + // 1. + // var a int + // var b int + + // 2. + // var ( + // a int + // b int + // ) + + // 3. + // var a, b int + + // 1. + // fmt.Println(a, "+", b, "=", a+b) + + // 2. + // fmt.Printf("%v + %v = %v\n", a, b, a+b) + + // ---- // lesson: multi-return funcs, %v, and _ a, _ := strconv.Atoi(os.Args[1]) diff --git a/x-tba/foundations/calc/03-floats-conv/main.go b/x-tba/foundations/calc/03-floats-conv/main.go index dda0068..0d56d47 100644 --- a/x-tba/foundations/calc/03-floats-conv/main.go +++ b/x-tba/foundations/calc/03-floats-conv/main.go @@ -7,7 +7,7 @@ import ( ) func main() { - // lesson: floats encompass integers too + // lesson: len(), floats encompass integers too if len(os.Args) != 3 { fmt.Println("Usage: calc ") diff --git a/x-tba/foundations/calc/04-error-handling/main.go b/x-tba/foundations/calc/04-error-handling/main.go index 6f79b95..b29b221 100644 --- a/x-tba/foundations/calc/04-error-handling/main.go +++ b/x-tba/foundations/calc/04-error-handling/main.go @@ -26,5 +26,12 @@ func main() { return } + // err1 := ... + // err2 := ... + // if err1 != nil || err2 != nil { + // fmt.Println("Please provide a valid number") + // return + // } + fmt.Printf("%v + %v = %v\n", a, b, a+b) } diff --git a/x-tba/foundations/calc/05-switch/main.go b/x-tba/foundations/calc/05-switch/main.go index c9c43f8..db1fab8 100644 --- a/x-tba/foundations/calc/05-switch/main.go +++ b/x-tba/foundations/calc/05-switch/main.go @@ -26,7 +26,9 @@ func main() { return } + // multiple declare var ( + // declare & assign op = os.Args[2] res float64 ) diff --git a/x-tba/foundations/lookup/main.go b/x-tba/foundations/lookup/main.go new file mode 100644 index 0000000..456231a --- /dev/null +++ b/x-tba/foundations/lookup/main.go @@ -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" + "net" + "os" + "strings" +) + +const ( + missingHost = "Please provide at least one domain. --help for more information." + + help = ` +Host to IP Lookup: +------------------ + +It finds the ip addresses of the given hosts. You can provide hosts by separating them with spaces. + +Example: + + host google.com + host google.com uber.com` +) + +func main() { + // url := "google.com" + var message string + + args := os.Args + switch l := len(args); { + // case len(args) == 1: + case l == 1: + message = missingHost + case l == 2 && args[1] == "--help": + message = strings.TrimSpace(help) + } + + if message != "" { + fmt.Println(message) + return + } + + // for i := 0; i < len(args); i++ {} + // for i, url := range args { + for _, url := range args[1:] { + // if i == 0 { + // continue + // } + + ips, err := net.LookupIP(url) + if err != nil { + fmt.Printf("%-20s => %s\n", url, err) + // break + continue + } + + for _, ip := range ips { + if ip = ip.To4(); ip != nil { + fmt.Printf("%-20s => %s\n", url, ip) + } + } + } +} diff --git a/x-tba/swapi-api-client/fetch/main.go b/x-tba/swapi-api-client/fetch/main.go new file mode 100644 index 0000000..f8e1aea --- /dev/null +++ b/x-tba/swapi-api-client/fetch/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "os" +) + +const base = "https://swapi.co/api/" + +func main() { + if len(os.Args) != 2 { + fmt.Println("Please provide a Ship ID") + return + } + + url := base + "starships/" + os.Args[1] + + response, err := http.Get(url) + if err != nil { + fmt.Println(err) + return + } + + if code := response.StatusCode; code != http.StatusOK { + fmt.Println("Error:", http.StatusText(code)) + return + } + + // var r *http.Response + // _ = r + + bodyBytes, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatal(err) + } + + body := string(bodyBytes) + fmt.Println(body) +} diff --git a/x-tba/tictactoe-experiments/00-without-bufio/main.go b/x-tba/tictactoe-experiments/00-without-bufio/main.go new file mode 100644 index 0000000..169d278 --- /dev/null +++ b/x-tba/tictactoe-experiments/00-without-bufio/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "fmt" + "math/rand" + "strings" + "time" + + rainbow "github.com/guineveresaenger/golang-rainbow" +) + +const ( + maxTurn = 9 + + // skin options :-) + empty = " " + player1 = " X " + player2 = " O " + header = "---+---+---" + footer = "---+---+---" + separator = "|" + + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` +) + +// ------------------------------------------------- +// INITIALIZE THE GAME +// ------------------------------------------------- +var ( + turn int + won bool + + board = [][]string{ + {empty, empty, empty}, + {empty, empty, empty}, + {empty, empty, empty}, + } + + player = player1 +) + +func main() { + rand.Seed(time.Now().UnixNano()) + rainbow.Rainbow(banner, strings.Count(banner, "\n")) + + for { + // ------------------------------------------------- + // PRINT THE BOARD AND THE PROMPT + // ------------------------------------------------- + fmt.Printf("\n %s\n", header) + for _, line := range board { + fmt.Printf(" %s\n", strings.Join(line, separator)) + fmt.Printf(" %s\n", footer) + } + + // ------------------------------------------------- + // IS THERE A WINNER? OR IS IT A TIE? + // ------------------------------------------------- + for i := 1; i <= 2; i++ { + m := player2 + if i == 1 { + m = player1 + } + + b, mmm := board, strings.Repeat(m, 3) + + /* horizontals */ + hor := strings.Join(b[0], "") == mmm || + strings.Join(b[1], "") == mmm || + strings.Join(b[2], "") == mmm + + /* verticals */ + ver := b[0][0]+b[1][0]+b[2][0] == mmm || + b[0][1]+b[1][1]+b[2][1] == mmm || + b[0][2]+b[1][2]+b[2][2] == mmm + + /* diagonals */ + diag := b[0][0]+b[1][1]+b[2][2] == mmm || + b[0][2]+b[1][1]+b[2][0] == mmm + + won = hor || ver || diag + + if won { + player = m + break + } + } + + if won { + player = strings.TrimSpace(player) + fmt.Printf("\n>>> WINNER: %s\n", player) + break + } else if turn == maxTurn { + fmt.Printf("\n>>> TIE!\n") + break + } + + // ------------------------------------------------- + // PLAY + // ------------------------------------------------- + + pos := rand.Intn(9) + 1 + fmt.Printf("\nPlayer %s plays to %d\n", player, pos) + + // ------------------------------------------------- + // IS IT A VALID MOVE? + // ------------------------------------------------- + + var row int + switch { + case pos <= 3: + row = 0 + case pos <= 6: + row = 1 + case pos <= 9: + row = 2 + default: + fmt.Println(">>>", "wrong position!") + continue + } + + col := pos - row*3 - 1 + + if board[row][col] != empty { + fmt.Println(">>>", "already played!") + continue + } + + // ------------------------------------------------- + // MARK THE MOVE AND INCREMENT THE TURN + // ------------------------------------------------- + + // put a mark on the board + board[row][col] = player + + // switch to the next player + if player == player1 { + player = player2 + } else { + player = player1 + } + + turn++ + // time.Sleep(time.Millisecond * 100) + } +} diff --git a/x-tba/tictactoe/01-without-funcs/main.go b/x-tba/tictactoe-experiments/01-without-funcs/main.go similarity index 100% rename from x-tba/tictactoe/01-without-funcs/main.go rename to x-tba/tictactoe-experiments/01-without-funcs/main.go diff --git a/x-tba/tictactoe/02-with-funcs/main.go b/x-tba/tictactoe-experiments/02-with-funcs/main.go similarity index 100% rename from x-tba/tictactoe/02-with-funcs/main.go rename to x-tba/tictactoe-experiments/02-with-funcs/main.go diff --git a/x-tba/tictactoe/03-with-structs/main.go b/x-tba/tictactoe-experiments/03-with-structs/main.go similarity index 100% rename from x-tba/tictactoe/03-with-structs/main.go rename to x-tba/tictactoe-experiments/03-with-structs/main.go diff --git a/x-tba/tictactoe/04-with-methods/main.go b/x-tba/tictactoe-experiments/04-with-methods/main.go similarity index 100% rename from x-tba/tictactoe/04-with-methods/main.go rename to x-tba/tictactoe-experiments/04-with-methods/main.go diff --git a/x-tba/tictactoe/05-with-pointers/main.go b/x-tba/tictactoe-experiments/05-with-pointers/main.go similarity index 100% rename from x-tba/tictactoe/05-with-pointers/main.go rename to x-tba/tictactoe-experiments/05-with-pointers/main.go diff --git a/x-tba/tictactoe/06-refactor/game.go b/x-tba/tictactoe-experiments/06-refactor/game.go similarity index 100% rename from x-tba/tictactoe/06-refactor/game.go rename to x-tba/tictactoe-experiments/06-refactor/game.go diff --git a/x-tba/tictactoe/06-refactor/logger.go b/x-tba/tictactoe-experiments/06-refactor/logger.go similarity index 100% rename from x-tba/tictactoe/06-refactor/logger.go rename to x-tba/tictactoe-experiments/06-refactor/logger.go diff --git a/x-tba/tictactoe/06-refactor/main.go b/x-tba/tictactoe-experiments/06-refactor/main.go similarity index 100% rename from x-tba/tictactoe/06-refactor/main.go rename to x-tba/tictactoe-experiments/06-refactor/main.go diff --git a/x-tba/tictactoe/06-refactor/resources.md b/x-tba/tictactoe-experiments/06-refactor/resources.md similarity index 100% rename from x-tba/tictactoe/06-refactor/resources.md rename to x-tba/tictactoe-experiments/06-refactor/resources.md diff --git a/x-tba/tictactoe/06-refactor/skins.go b/x-tba/tictactoe-experiments/06-refactor/skins.go similarity index 100% rename from x-tba/tictactoe/06-refactor/skins.go rename to x-tba/tictactoe-experiments/06-refactor/skins.go diff --git a/x-tba/tictactoe/README.md b/x-tba/tictactoe-experiments/README.md similarity index 100% rename from x-tba/tictactoe/README.md rename to x-tba/tictactoe-experiments/README.md diff --git a/x-tba/tictactoe/00-print/main.go b/x-tba/tictactoe/00-print/main.go new file mode 100644 index 0000000..23194b5 --- /dev/null +++ b/x-tba/tictactoe/00-print/main.go @@ -0,0 +1,50 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ +func main() { + // VERSION #1: String Concat + + /* + fmt.Print("" + + " TIC~TAC~TOE\n" + + "\n" + + "/---+---+---\\\n" + + "| X | O | X |\n" + + "+---+---+---+\n" + + "| X | X | |\n" + + "+---+---+---+\n" + + "| O | O | O |\n" + + "\\---+---+---/\n") + */ + + // VERSION #2: String Concat + + /* + fmt.Println("" + + " TIC~TAC~TOE\n" + + "\n" + + "/---+---+---\\\n" + + "| X | O | X |\n" + + "+---+---+---+\n" + + "| X | X | |\n" + + "+---+---+---+\n" + + "| O | O | O |\n" + + "\\---+---+---/") + */ + + // VERSION #3: Raw Literals (multi line strings) + fmt.Println(` + TIC~TAC~TOE + +/---+---+---\ +| X | O | X | ++---+---+---+ +| X | X | | ++---+---+---+ +| O | O | O | +\---+---+---/`) +} diff --git a/x-tba/tictactoe/01-vars/main.go b/x-tba/tictactoe/01-vars/main.go new file mode 100644 index 0000000..82c6801 --- /dev/null +++ b/x-tba/tictactoe/01-vars/main.go @@ -0,0 +1,96 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ +func main() { + /* + VERSION #1: Declare variables + + Every type has a zero-value: + numeric types => 0 + bool => false + string => "" + */ + + // var banner string + // var board string + // var turn int + // var maxTurns int + // var won bool + + /* + VERSION #2: Declare variables parallel (same as above) + + turn and lastPos are int + won and wrongMove are bool + */ + // var banner, board string + // var turn, maxTurns int + // var won bool + + /* + VERSION #3: Declare variables in a group and parallel (same as above) + */ + // var ( + // banner, board string + // turn, maxTurns int + // won bool + // ) + + /* + VERSION #4: Declare variables in a group (same as above) + */ + var ( + banner string // tictactoe banner + board string // tictactoe board + + turn int // total valid turns played + maxTurns int // maximum number of turns + + won bool // is there any winner? + + progress float64 // remaining progress + ) + + /* + #5: Assignment + */ + banner = " TIC~TAC~TOE" + board = ` +/---+---+---\ +| | X | | ++---+---+---+ +| | O | | ++---+---+---+ +| | | | +\---+---+---/` + + // maxTurns = 9 + // turn = 2 + + // multiple assignment + maxTurns, turn = 9, 2 + + // cannot assign int to float + // progress = 1 - (turn / maxTurns) * 100 + // convert ints to float so that the result will be float + // literals are typeless: they automatically get converted to the surrounding operands + progress = (1 - (float64(turn) / float64(maxTurns))) * 100 + + fmt.Println(banner) + fmt.Println(board) + + fmt.Println() + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) + + // This is also valid: the expression is evaluated on the fly. + // fmt.Printf("Turns left : %.1f%%\n", + // (1 - (float64(turn) / float64(maxTurns))) * 100) +} diff --git a/x-tba/tictactoe/02-short-decl/main.go b/x-tba/tictactoe/02-short-decl/main.go new file mode 100644 index 0000000..709eae2 --- /dev/null +++ b/x-tba/tictactoe/02-short-decl/main.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ +func main() { + var won bool // is there any winner? + + banner := " TIC~TAC~TOE" + board := ` +/---+---+---\ +| | | | ++---+---+---+ +| | | | ++---+---+---+ +| | | | +\---+---+---/` + + // short declaration (type-inference) + maxTurns, turn := 9, 0 + progress := (1 - (float64(turn) / float64(maxTurns))) * 100 + + fmt.Println(banner) + fmt.Println(board) + fmt.Println() + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/03-consts/main.go b/x-tba/tictactoe/03-consts/main.go new file mode 100644 index 0000000..07e3ae5 --- /dev/null +++ b/x-tba/tictactoe/03-consts/main.go @@ -0,0 +1,71 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ +func main() { + var ( + won bool + turn int + ) + + // VERSION 1 + // const banner = " TIC~TAC~TOE" + // const board = ` + // /---+---+---\ + // | X | O | X | + // +---+---+---+ + // | X | X | | + // +---+---+---+ + // | O | O | O | + // \---+---+---/` + // + // const maxTurns = 9 + + // VERSION 2 + // Benefit of constants: + // + Resolved to literals at compile-time + // + Fast at runtime + // + Provides overwriting unlike variables + // + Typeless: Can change type + const ( + banner = ` + TIC~TAC~TOE + +/---+---+---\ +| X | O | X | ++---+---+---+ +| X | X | | ++---+---+---+ +| O | O | O | +\---+---+---/` + + maxTurns = 9 + ) + + // Constants have default types + // 1 => int + // 1.5 => float64 + // true => bool + // "hi" => string + // 'a' => rune + + // You cannot assign to constants + // banner = "TIC TAC TOE" + // maxTurns = 10 + + // no need: float64(maxTurns) — constants are typeless (like basic literals) + // if maxTurns was `const maxTurns int`; then it'd be needed. + progress := (1 - (float64(turn) / maxTurns)) * 100 + + fmt.Println(banner) + // fmt.Println(board) + fmt.Println() + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/04-funcs/main.go b/x-tba/tictactoe/04-funcs/main.go new file mode 100644 index 0000000..32ab77b --- /dev/null +++ b/x-tba/tictactoe/04-funcs/main.go @@ -0,0 +1,52 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const ( + banner = ` + TIC~TAC~TOE + +/---+---+---\ +| X | O | X | ++---+---+---+ +| X | X | | ++---+---+---+ +| O | O | O | +\---+---+---/` + + maxTurns = 9 +) + +var ( + won bool + turn int +) + +func main() { + // you need to call the other functions but the main + printBoard() + printStatus() +} + +// printBoard cannot use the banner +func printBoard() { + // it can only use the package-level names (identifiers) + fmt.Println(banner) +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/05-testing/board_test.go b/x-tba/tictactoe/05-testing/board_test.go new file mode 100644 index 0000000..747f238 --- /dev/null +++ b/x-tba/tictactoe/05-testing/board_test.go @@ -0,0 +1,23 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + // let the printBoard function print an output + + printBoard() + + // the output should exactly match the following (after Output:) + + // Output: + // TIC~TAC~TOE + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/05-testing/main.go b/x-tba/tictactoe/05-testing/main.go new file mode 100644 index 0000000..f995101 --- /dev/null +++ b/x-tba/tictactoe/05-testing/main.go @@ -0,0 +1,52 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const ( + banner = ` + TIC~TAC~TOE + +/---+---+---\ +| | | | ++---+---+---+ +| | | | ++---+---+---+ +| | | | +\---+---+---/` + + maxTurns = 9 +) + +var ( + won bool + turn int +) + +func main() { + // you need to call the other functions but the main + printBoard() + printStatus() +} + +// printBoard cannot use the banner +func printBoard() { + // it can only use the package-level names (identifiers) + fmt.Println(banner) +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/06-if-switch/board_test.go b/x-tba/tictactoe/06-if-switch/board_test.go new file mode 100644 index 0000000..747f238 --- /dev/null +++ b/x-tba/tictactoe/06-if-switch/board_test.go @@ -0,0 +1,23 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + // let the printBoard function print an output + + printBoard() + + // the output should exactly match the following (after Output:) + + // Output: + // TIC~TAC~TOE + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/06-if-switch/main.go b/x-tba/tictactoe/06-if-switch/main.go new file mode 100644 index 0000000..db94074 --- /dev/null +++ b/x-tba/tictactoe/06-if-switch/main.go @@ -0,0 +1,87 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const ( + banner = ` + TIC~TAC~TOE + +/---+---+---\ +| | | | ++---+---+---+ +| | | | ++---+---+---+ +| | | | +\---+---+---/` + + maxTurns = 9 +) + +var ( + won bool + turn int +) + +func main() { + // you need to call the other functions but the main + printBoard() + printStatus() + printEnding() +} + +// printBoard cannot use the banner +func printBoard() { + // it can only use the package-level names (identifiers) + fmt.Println(banner) +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + fmt.Println() + + // creates a new variable that belongs to printEnding() + // current player + player := "X" + + // accesses to the package-level vars: won, turn + // won = true + // turn = maxTurns + + // if won { + // fmt.Printf(">>> WINNER: %s\n", player) + // } else if turn == maxTurns { // != >= <= < > + // fmt.Println(">>> TIE!") + // } else { + // fmt.Println(">> NEXT TURN!") + // } + + switch { + case won: + // player := "X" + fmt.Printf(">>> WINNER: %s\n", player) + case turn == maxTurns: + fmt.Println(">>> TIE!") + default: + fmt.Println(">> NEXT TURN!", player) + + } + + // invalid if the player is within the scope of the switch: + // fmt.Println(">> Current Player: ", player) +} diff --git a/x-tba/tictactoe/07-loop/board.go b/x-tba/tictactoe/07-loop/board.go new file mode 100644 index 0000000..2761778 --- /dev/null +++ b/x-tba/tictactoe/07-loop/board.go @@ -0,0 +1,54 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | O | X | + // +---+---+---+ + // | O | X | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + const cellsPerLine = 3 + + // Prevents the Println '\n' warning + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i := 0; i < maxTurns; i++ { + lineStarts := i%cellsPerLine == 0 + lineEnds := (i+1)%cellsPerLine == 0 + lastLine := (i + 1) == maxTurns + + if lineStarts { + fmt.Print(sepCell) + } + + switchPlayer() + fmt.Printf(" %s ", player) + + if lineEnds { + fmt.Println(sepCell) + } + + if lineEnds && !lastLine { + fmt.Println(sepLine) + } + + if lineEnds { + continue // prevents printing the sepCell below + } + + // print the cell separator until 3 cells per line + fmt.Print(sepCell) + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/07-loop/board_test.go b/x-tba/tictactoe/07-loop/board_test.go new file mode 100644 index 0000000..aff3e55 --- /dev/null +++ b/x-tba/tictactoe/07-loop/board_test.go @@ -0,0 +1,25 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + // let the printBoard function print an output + + printBoard() + + // the output should exactly match the following (after Output:) + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | O | X | + // +---+---+---+ + // | O | X | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/07-loop/main.go b/x-tba/tictactoe/07-loop/main.go new file mode 100644 index 0000000..9356f16 --- /dev/null +++ b/x-tba/tictactoe/07-loop/main.go @@ -0,0 +1,61 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool + turn int + player string // current player +) + +func main() { + player = player1 + turn = maxTurns + + // you need to call the other functions but the main + printBoard() + printStatus() + printEnding() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + fmt.Println() + + switch { + case won: + fmt.Printf(">>> WINNER: %s\n", player) + case turn == maxTurns: + fmt.Println(">>> TIE!") + default: + fmt.Println(">> NEXT TURN!", player) + } +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/07-loop/skin.go b/x-tba/tictactoe/07-loop/skin.go new file mode 100644 index 0000000..71c1aad --- /dev/null +++ b/x-tba/tictactoe/07-loop/skin.go @@ -0,0 +1,25 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" + + /* + Try it with this instead :) + + sepHeader = "╔═══╦═══╦═══╗" + sepLine = "╠═══╬═══╬═══╣" + sepFooter = "╚═══╩═══╩═══╝" + sepCell = "║" + */ +) diff --git a/x-tba/tictactoe/08-multi-loop/board.go b/x-tba/tictactoe/08-multi-loop/board.go new file mode 100644 index 0000000..c3bb20f --- /dev/null +++ b/x-tba/tictactoe/08-multi-loop/board.go @@ -0,0 +1,37 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | O | X | + // +---+---+---+ + // | O | X | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < maxTurns; i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + switchPlayer() + fmt.Printf(" %s %s", player, sepCell) + } + fmt.Println() + + if lastLine := (i + step); lastLine != maxTurns { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/08-multi-loop/board_test.go b/x-tba/tictactoe/08-multi-loop/board_test.go new file mode 100644 index 0000000..aff3e55 --- /dev/null +++ b/x-tba/tictactoe/08-multi-loop/board_test.go @@ -0,0 +1,25 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + // let the printBoard function print an output + + printBoard() + + // the output should exactly match the following (after Output:) + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | O | X | + // +---+---+---+ + // | O | X | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/08-multi-loop/main.go b/x-tba/tictactoe/08-multi-loop/main.go new file mode 100644 index 0000000..c80939b --- /dev/null +++ b/x-tba/tictactoe/08-multi-loop/main.go @@ -0,0 +1,62 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool + turn int + player string // current player +) + +func main() { + player = player1 + turn = maxTurns + + // you need to call the other functions but the main + printBoard() + printStatus() + printEnding() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + fmt.Println() + + switch { + case won: + fmt.Printf(">>> WINNER: %s\n", player) + case turn == maxTurns: + fmt.Println(">>> TIE!") + default: + switchPlayer() + fmt.Println(">> NEXT TURN!", player) + } +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/08-multi-loop/skin.go b/x-tba/tictactoe/08-multi-loop/skin.go new file mode 100644 index 0000000..fa0d244 --- /dev/null +++ b/x-tba/tictactoe/08-multi-loop/skin.go @@ -0,0 +1,16 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/09-slices/board.go b/x-tba/tictactoe/09-slices/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/09-slices/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/09-slices/board_test.go b/x-tba/tictactoe/09-slices/board_test.go new file mode 100644 index 0000000..46d1d26 --- /dev/null +++ b/x-tba/tictactoe/09-slices/board_test.go @@ -0,0 +1,44 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + initCells() + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + initCells() + + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/09-slices/init.go b/x-tba/tictactoe/09-slices/init.go new file mode 100644 index 0000000..ac032eb --- /dev/null +++ b/x-tba/tictactoe/09-slices/init.go @@ -0,0 +1,33 @@ +package main + +// initCells initialize the played cells to empty +func initCells() { + // // create a string with empty cells + // // " , , , , , , , , ," + // var s string + + // // number of cells = maxTurns + // for i := 1; i <= maxTurns; i++ { + // s += emptyCell // add an empty move + // s += "," // separate the cells with a comma + // } + + // // strings are immutable — you should create a new one + // // fortunately: most of this happens in the stack memory + // // " , , , , , , , , ," -> // " , , , , , , , , " + // s = strings.TrimSuffix(s, ",") + + // // store the cells in a slice (slice = list, array in other langs) + // // Split() returns a list of strings: []string (a string slice) + // // [" ", " ", " ", " ", " ", " ", " ", " ", " " ] + // cells = strings.Split(s, ",") + + // Right way: + // cells = []string{" ", " ", " ", " ", " ", " ", " ", " ", " "} + // + // Or: + cells = make([]string, maxTurns) + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/09-slices/main.go b/x-tba/tictactoe/09-slices/main.go new file mode 100644 index 0000000..1f5783c --- /dev/null +++ b/x-tba/tictactoe/09-slices/main.go @@ -0,0 +1,55 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool // is there any winner? + turn int // total valid turns played + player string // current player + cells []string // used to draw the board: contains the players' moves +) + +func main() { + player = player1 + + initCells() + + play() + + printBoard() + printStatus() + printEnding() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + fmt.Println() + + switch { + case won: + fmt.Printf(">>> WINNER: %s\n", player) + case turn == maxTurns: + fmt.Println(">>> TIE!") + default: + switchPlayer() + fmt.Println(">> NEXT TURN!", player) + } +} diff --git a/x-tba/tictactoe/09-slices/play.go b/x-tba/tictactoe/09-slices/play.go new file mode 100644 index 0000000..2eee356 --- /dev/null +++ b/x-tba/tictactoe/09-slices/play.go @@ -0,0 +1,38 @@ +package main + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // [" ", " ", " ", " ", " ", " ", " ", " ", " " ] -> cells slice + // 0 1 2 3 4 5 6 7 8 -> indexes + + // /---+---+---\ + // | 0 | 1 | 2 | + // +---+---+---+ + // | 3 | 4 | 5 | + // +---+---+---+ + // | 6 | 7 | 8 | + // \---+---+---/ + + // current player plays to the 4th position (index) + // play to a fixed position "for now". + pos := 4 + + // register the move: put the player's sign on the board + cells[pos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/09-slices/skin.go b/x-tba/tictactoe/09-slices/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/09-slices/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/10-arrays/board.go b/x-tba/tictactoe/10-arrays/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/10-arrays/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/10-arrays/board_test.go b/x-tba/tictactoe/10-arrays/board_test.go new file mode 100644 index 0000000..46d1d26 --- /dev/null +++ b/x-tba/tictactoe/10-arrays/board_test.go @@ -0,0 +1,44 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + initCells() + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + initCells() + + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/10-arrays/init.go b/x-tba/tictactoe/10-arrays/init.go new file mode 100644 index 0000000..d1894c4 --- /dev/null +++ b/x-tba/tictactoe/10-arrays/init.go @@ -0,0 +1,8 @@ +package main + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/10-arrays/main.go b/x-tba/tictactoe/10-arrays/main.go new file mode 100644 index 0000000..e6e7ed2 --- /dev/null +++ b/x-tba/tictactoe/10-arrays/main.go @@ -0,0 +1,55 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool // is there any winner? + turn int // total valid turns played + player string // current player + cells [maxTurns]string // used to draw the board: contains the players' moves +) + +func main() { + player = player1 + + initCells() + + play() + + printBoard() + printStatus() + printEnding() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + fmt.Println() + + switch { + case won: + fmt.Printf(">>> WINNER: %s\n", player) + case turn == maxTurns: + fmt.Println(">>> TIE!") + default: + switchPlayer() + fmt.Println(">> NEXT TURN!", player) + } +} diff --git a/x-tba/tictactoe/10-arrays/play.go b/x-tba/tictactoe/10-arrays/play.go new file mode 100644 index 0000000..2eee356 --- /dev/null +++ b/x-tba/tictactoe/10-arrays/play.go @@ -0,0 +1,38 @@ +package main + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // [" ", " ", " ", " ", " ", " ", " ", " ", " " ] -> cells slice + // 0 1 2 3 4 5 6 7 8 -> indexes + + // /---+---+---\ + // | 0 | 1 | 2 | + // +---+---+---+ + // | 3 | 4 | 5 | + // +---+---+---+ + // | 6 | 7 | 8 | + // \---+---+---/ + + // current player plays to the 4th position (index) + // play to a fixed position "for now". + pos := 4 + + // register the move: put the player's sign on the board + cells[pos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/10-arrays/skin.go b/x-tba/tictactoe/10-arrays/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/10-arrays/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/11-randomization/board.go b/x-tba/tictactoe/11-randomization/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/11-randomization/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/11-randomization/board_test.go b/x-tba/tictactoe/11-randomization/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/11-randomization/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/11-randomization/init.go b/x-tba/tictactoe/11-randomization/init.go new file mode 100644 index 0000000..d6a4bfd --- /dev/null +++ b/x-tba/tictactoe/11-randomization/init.go @@ -0,0 +1,20 @@ +package main + +import ( + "math/rand" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/11-randomization/main.go b/x-tba/tictactoe/11-randomization/main.go new file mode 100644 index 0000000..7e1285f --- /dev/null +++ b/x-tba/tictactoe/11-randomization/main.go @@ -0,0 +1,69 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool // is there any winner? + turn int // total valid turns played + player string // current player + + cells [maxTurns]string // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? +) + +func main() { + player = player1 + printBoard() + + for i := 0; i < 4; i++ { + wait() + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + printEnding() + } +} + +func wait() { + fmt.Println() + fmt.Scanln() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} + +func printEnding() { + switch { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won: + fmt.Printf(">>> WINNER: %s\n", player) + + case turn == maxTurns: + fmt.Println(">>> TIE!") + } +} diff --git a/x-tba/tictactoe/11-randomization/play.go b/x-tba/tictactoe/11-randomization/play.go new file mode 100644 index 0000000..ae74a7b --- /dev/null +++ b/x-tba/tictactoe/11-randomization/play.go @@ -0,0 +1,48 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // [" ", " ", " ", " ", " ", " ", " ", " ", " " ] -> cells slice + // 0 1 2 3 4 5 6 7 8 -> indexes + + // /---+---+---\ + // | 0 | 1 | 2 | + // +---+---+---+ + // | 3 | 4 | 5 | + // +---+---+---+ + // | 6 | 7 | 8 | + // \---+---+---/ + + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/11-randomization/skin.go b/x-tba/tictactoe/11-randomization/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/11-randomization/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/12-infinite-loop/board.go b/x-tba/tictactoe/12-infinite-loop/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/12-infinite-loop/board_test.go b/x-tba/tictactoe/12-infinite-loop/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/12-infinite-loop/init.go b/x-tba/tictactoe/12-infinite-loop/init.go new file mode 100644 index 0000000..d6a4bfd --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/init.go @@ -0,0 +1,20 @@ +package main + +import ( + "math/rand" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/12-infinite-loop/main.go b/x-tba/tictactoe/12-infinite-loop/main.go new file mode 100644 index 0000000..4fd6e3d --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/main.go @@ -0,0 +1,74 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won bool // is there any winner? + turn int // total valid turns played + player = player1 // current player + + cells [maxTurns]string // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? +) + +func main() { + printBoard() + + // alternative: + // for won || tie {} + + // this a label: it can be used by break, continue and goto +theGameLoop: + // loop forever until the game ends (tie or win) + for { + wait() + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + + // simple statement + switch tie := turn == maxTurns; { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won, tie: + if won { + fmt.Println(">>> WINNER:", player) + } else { + fmt.Println(">>> TIE!") + } + break theGameLoop + } + } +} + +func wait() { + fmt.Println() + fmt.Scanln() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/12-infinite-loop/play.go b/x-tba/tictactoe/12-infinite-loop/play.go new file mode 100644 index 0000000..ae74a7b --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/play.go @@ -0,0 +1,48 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // [" ", " ", " ", " ", " ", " ", " ", " ", " " ] -> cells slice + // 0 1 2 3 4 5 6 7 8 -> indexes + + // /---+---+---\ + // | 0 | 1 | 2 | + // +---+---+---+ + // | 3 | 4 | 5 | + // +---+---+---+ + // | 6 | 7 | 8 | + // \---+---+---/ + + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/12-infinite-loop/skin.go b/x-tba/tictactoe/12-infinite-loop/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/12-infinite-loop/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/13-detect-winning/board.go b/x-tba/tictactoe/13-detect-winning/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/13-detect-winning/board_test.go b/x-tba/tictactoe/13-detect-winning/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/13-detect-winning/ending.go b/x-tba/tictactoe/13-detect-winning/ending.go new file mode 100644 index 0000000..6bc751a --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/ending.go @@ -0,0 +1,55 @@ +package main + +// ------------------------------------------------- +// IS THERE A WINNER? OR IS IT A TIE? +// ------------------------------------------------- + +// /---+---+---\ +// | 0 | 1 | 2 | +// +---+---+---+ +// | 3 | 4 | 5 | +// +---+---+---+ +// | 6 | 7 | 8 | +// \---+---+---/ + +func checkWinOrTie() { + // intentional bug: tie shouldn't happen before winning detection + if tie = turn == maxTurns; tie { + // if tie don't check for the winning + return + } + + // loop over all the players + for i := 1; i <= 2; i++ { + // check for the next player + p := player2 + if i == 1 { + p = player1 + } + + /* check horizontals */ + hor := (cells[0] == p && cells[1] == p && cells[2] == p) || + (cells[3] == p && cells[4] == p && cells[5] == p) || + (cells[6] == p && cells[7] == p && cells[8] == p) + + /* check verticals */ + ver := (cells[0] == p && cells[3] == p && cells[6] == p) || + (cells[1] == p && cells[4] == p && cells[7] == p) || + (cells[2] == p && cells[5] == p && cells[8] == p) + + /* check diagonals */ + diag := (cells[0] == p && cells[4] == p && cells[8] == p) || + (cells[2] == p && cells[4] == p && cells[6] == p) + + // any winner? + if hor || ver || diag { + won = true + + // this player wins + player = p + + // there is a winner so don't check for tie! + return + } + } +} diff --git a/x-tba/tictactoe/13-detect-winning/init.go b/x-tba/tictactoe/13-detect-winning/init.go new file mode 100644 index 0000000..d6a4bfd --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/init.go @@ -0,0 +1,20 @@ +package main + +import ( + "math/rand" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/13-detect-winning/main.go b/x-tba/tictactoe/13-detect-winning/main.go new file mode 100644 index 0000000..d588d5f --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/main.go @@ -0,0 +1,124 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won, tie bool // is there any winner or a tie? + turn int // total valid turns played + player = player1 // current player + + cells [maxTurns]string // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? +) + +// +// VERSION 2: HELPER FUNC +// +func main() { + printBoard() + wait() + + for nextTurn() { + wait() + } + + // loop forever until the game ends (tie or win) + // for { + // // wait() + // if !nextTurn() { + // break + // } + // } +} + +func nextTurn() bool { + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + + // the switch below is about winning and tie conditions. + // so it is good have checkWinOrTie() as a simple statement. + // totally optional. + switch checkWinOrTie(); { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won, tie: + if won { + fmt.Println(">>> WINNER:", player) + } else { + fmt.Println(">>> TIE!") + } + return false + } + return true +} + +// +// VERSION 1: LABELED BREAK +// +// func main() { +// printBoard() + +// // this a label: it can be used by break, continue and goto +// theGameLoop: +// // loop forever until game ends (tie or win) +// for { +// // wait() +// play() +// printBoard() + +// fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + +// // the switch below is about winning and tie conditions. +// // so it is good have checkWinOrTie() as a simple statement. +// // totally optional. +// switch checkWinOrTie(); { +// default: +// printStatus() + +// case wrongMove: +// fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") +// wrongMove = false // reset for the next turn + +// case won, tie: +// if won { +// fmt.Println(">>> WINNER:", player) +// } else { +// fmt.Println(">>> TIE!") +// } +// break theGameLoop +// } +// } +// } + +func wait() { + fmt.Println() + fmt.Scanln() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/13-detect-winning/play.go b/x-tba/tictactoe/13-detect-winning/play.go new file mode 100644 index 0000000..72c18b2 --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/play.go @@ -0,0 +1,37 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/13-detect-winning/skin.go b/x-tba/tictactoe/13-detect-winning/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/13-detect-winning/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/14-more-tests/board.go b/x-tba/tictactoe/14-more-tests/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/14-more-tests/board_test.go b/x-tba/tictactoe/14-more-tests/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/14-more-tests/ending.go b/x-tba/tictactoe/14-more-tests/ending.go new file mode 100644 index 0000000..7e975cc --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/ending.go @@ -0,0 +1,58 @@ +package main + +// ------------------------------------------------- +// IS THERE A WINNER? OR IS IT A TIE? +// ------------------------------------------------- + +// /---+---+---\ +// | 0 | 1 | 2 | +// +---+---+---+ +// | 3 | 4 | 5 | +// +---+---+---+ +// | 6 | 7 | 8 | +// \---+---+---/ + +func checkWinOrTie() { + // intentional bug: tie shouldn't happen before winning detection + // if tie = turn == maxTurns; tie { + // // if tie don't check for the winning + // return + // } + + // loop over all the players + for i := 1; i <= 2; i++ { + // check for the next player + p := player2 + if i == 1 { + p = player1 + } + + /* check horizontals */ + hor := (cells[0] == p && cells[1] == p && cells[2] == p) || + (cells[3] == p && cells[4] == p && cells[5] == p) || + (cells[6] == p && cells[7] == p && cells[8] == p) + + /* check verticals */ + ver := (cells[0] == p && cells[3] == p && cells[6] == p) || + (cells[1] == p && cells[4] == p && cells[7] == p) || + (cells[2] == p && cells[5] == p && cells[8] == p) + + /* check diagonals */ + diag := (cells[0] == p && cells[4] == p && cells[8] == p) || + (cells[2] == p && cells[4] == p && cells[6] == p) + + // any winner? + if hor || ver || diag { + won = true + + // this player wins + player = p + + // there is a winner so don't check for tie! + return + } + } + + // check for tie + tie = turn == maxTurns +} diff --git a/x-tba/tictactoe/14-more-tests/ending_test.go b/x-tba/tictactoe/14-more-tests/ending_test.go new file mode 100644 index 0000000..629c22b --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/ending_test.go @@ -0,0 +1,59 @@ +package main + +import "testing" + +func TestWin(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | O | O | X | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player2 + cells[4] = player2 + cells[5] = player1 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !won { + t.Errorf("won = %t; want true", won) + } + + // TestWin was messing up with the results. + // Test ordering shouldn't be important. + initCells() +} + +func TestTie(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | X | O | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player1 + cells[4] = player2 + cells[5] = player2 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !tie { + t.Errorf("tie = %t; want true", tie) + } + + initCells() +} diff --git a/x-tba/tictactoe/14-more-tests/init.go b/x-tba/tictactoe/14-more-tests/init.go new file mode 100644 index 0000000..d6a4bfd --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/init.go @@ -0,0 +1,20 @@ +package main + +import ( + "math/rand" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} diff --git a/x-tba/tictactoe/14-more-tests/main.go b/x-tba/tictactoe/14-more-tests/main.go new file mode 100644 index 0000000..7e0f7f2 --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/main.go @@ -0,0 +1,78 @@ +package main + +import "fmt" + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const maxTurns = 9 + +var ( + won, tie bool // is there any winner or a tie? + turn int // total valid turns played + player = player1 // current player + + cells [maxTurns]string // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? +) + +// main is only responsible for the game loop, that's it. +func main() { + printBoard() + wait() + + for nextTurn() { + wait() + } +} + +// nextTurn prints the board for the next turn and checks for the winning conditions. +// if win or tie: returns false, otherwise true. +func nextTurn() bool { + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + + // the switch below is about winning and tie conditions. + // so it is good have checkWinOrTie() as a simple statement. + // totally optional. + switch checkWinOrTie(); { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won, tie: + if won { + fmt.Println(">>> WINNER:", player) + } else { + fmt.Println(">>> TIE!") + } + return false + } + return true +} + +func wait() { + fmt.Println() + fmt.Scanln() +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/14-more-tests/play.go b/x-tba/tictactoe/14-more-tests/play.go new file mode 100644 index 0000000..72c18b2 --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/play.go @@ -0,0 +1,37 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/14-more-tests/play_test.go b/x-tba/tictactoe/14-more-tests/play_test.go new file mode 100644 index 0000000..6c3a161 --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/play_test.go @@ -0,0 +1,26 @@ +package main + +import "testing" + +func TestWrongMove(t *testing.T) { + // /---+---+---\ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // \---+---+---/ + + // fill the board with artificial cells + for i := range cells { + cells[i] = player1 + } + + // any move beyond this point is wrong. + // reason: every cell is occupied. + if play(); !wrongMove { + t.Errorf("wrongMove = %t; want true", wrongMove) + } + + initCells() +} diff --git a/x-tba/tictactoe/14-more-tests/skin.go b/x-tba/tictactoe/14-more-tests/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/14-more-tests/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/15-os-args/board.go b/x-tba/tictactoe/15-os-args/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/15-os-args/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/15-os-args/board_test.go b/x-tba/tictactoe/15-os-args/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/15-os-args/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/15-os-args/ending.go b/x-tba/tictactoe/15-os-args/ending.go new file mode 100644 index 0000000..7e975cc --- /dev/null +++ b/x-tba/tictactoe/15-os-args/ending.go @@ -0,0 +1,58 @@ +package main + +// ------------------------------------------------- +// IS THERE A WINNER? OR IS IT A TIE? +// ------------------------------------------------- + +// /---+---+---\ +// | 0 | 1 | 2 | +// +---+---+---+ +// | 3 | 4 | 5 | +// +---+---+---+ +// | 6 | 7 | 8 | +// \---+---+---/ + +func checkWinOrTie() { + // intentional bug: tie shouldn't happen before winning detection + // if tie = turn == maxTurns; tie { + // // if tie don't check for the winning + // return + // } + + // loop over all the players + for i := 1; i <= 2; i++ { + // check for the next player + p := player2 + if i == 1 { + p = player1 + } + + /* check horizontals */ + hor := (cells[0] == p && cells[1] == p && cells[2] == p) || + (cells[3] == p && cells[4] == p && cells[5] == p) || + (cells[6] == p && cells[7] == p && cells[8] == p) + + /* check verticals */ + ver := (cells[0] == p && cells[3] == p && cells[6] == p) || + (cells[1] == p && cells[4] == p && cells[7] == p) || + (cells[2] == p && cells[5] == p && cells[8] == p) + + /* check diagonals */ + diag := (cells[0] == p && cells[4] == p && cells[8] == p) || + (cells[2] == p && cells[4] == p && cells[6] == p) + + // any winner? + if hor || ver || diag { + won = true + + // this player wins + player = p + + // there is a winner so don't check for tie! + return + } + } + + // check for tie + tie = turn == maxTurns +} diff --git a/x-tba/tictactoe/15-os-args/ending_test.go b/x-tba/tictactoe/15-os-args/ending_test.go new file mode 100644 index 0000000..629c22b --- /dev/null +++ b/x-tba/tictactoe/15-os-args/ending_test.go @@ -0,0 +1,59 @@ +package main + +import "testing" + +func TestWin(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | O | O | X | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player2 + cells[4] = player2 + cells[5] = player1 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !won { + t.Errorf("won = %t; want true", won) + } + + // TestWin was messing up with the results. + // Test ordering shouldn't be important. + initCells() +} + +func TestTie(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | X | O | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player1 + cells[4] = player2 + cells[5] = player2 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !tie { + t.Errorf("tie = %t; want true", tie) + } + + initCells() +} diff --git a/x-tba/tictactoe/15-os-args/init.go b/x-tba/tictactoe/15-os-args/init.go new file mode 100644 index 0000000..1d76da3 --- /dev/null +++ b/x-tba/tictactoe/15-os-args/init.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "math/rand" + "os" + "strconv" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} + +func setGameSpeed() { + // args can be used within the if block + // gs and err can be used in the else if and else branches + if args := os.Args; len(args) == 1 { + fmt.Println("Setting game speed to default.") + } else if gs, err := strconv.Atoi(args[1]); err != nil { + fmt.Println("Wrong game speed. Provide an integer.") + } else { + gameSpeed = time.Duration(gs) * time.Second + } + + fmt.Printf("Game speed is %q.\n", gameSpeed) +} diff --git a/x-tba/tictactoe/15-os-args/main.go b/x-tba/tictactoe/15-os-args/main.go new file mode 100644 index 0000000..883808e --- /dev/null +++ b/x-tba/tictactoe/15-os-args/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "time" +) + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const ( + maxTurns = 9 + defaultGameSpeed = time.Second * 2 // time between plays +) + +var ( + won, tie bool // is there any winner or a tie? + turn int // total valid turns played + + cells [maxTurns]string // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? + + player = player1 // current player + gameSpeed = defaultGameSpeed // sets the default game speed +) + +// main is only responsible for the game loop, that's it. +func main() { + setGameSpeed() + printBoard() + wait() + + for nextTurn() { + wait() + } +} + +func wait() { + fmt.Println() + time.Sleep(gameSpeed) // player thinks... +} diff --git a/x-tba/tictactoe/15-os-args/play.go b/x-tba/tictactoe/15-os-args/play.go new file mode 100644 index 0000000..72c18b2 --- /dev/null +++ b/x-tba/tictactoe/15-os-args/play.go @@ -0,0 +1,37 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/15-os-args/play_test.go b/x-tba/tictactoe/15-os-args/play_test.go new file mode 100644 index 0000000..6c3a161 --- /dev/null +++ b/x-tba/tictactoe/15-os-args/play_test.go @@ -0,0 +1,26 @@ +package main + +import "testing" + +func TestWrongMove(t *testing.T) { + // /---+---+---\ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // \---+---+---/ + + // fill the board with artificial cells + for i := range cells { + cells[i] = player1 + } + + // any move beyond this point is wrong. + // reason: every cell is occupied. + if play(); !wrongMove { + t.Errorf("wrongMove = %t; want true", wrongMove) + } + + initCells() +} diff --git a/x-tba/tictactoe/15-os-args/skin.go b/x-tba/tictactoe/15-os-args/skin.go new file mode 100644 index 0000000..477b6b0 --- /dev/null +++ b/x-tba/tictactoe/15-os-args/skin.go @@ -0,0 +1,17 @@ +package main + +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + // skin options :-) + player1, player2 = "X", "O" + emptyCell = " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/15-os-args/turn.go b/x-tba/tictactoe/15-os-args/turn.go new file mode 100644 index 0000000..65bb1af --- /dev/null +++ b/x-tba/tictactoe/15-os-args/turn.go @@ -0,0 +1,45 @@ +package main + +import "fmt" + +// nextTurn prints the board for the next turn and checks for the winning conditions. +// if win or tie: returns false, otherwise true. +func nextTurn() bool { + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + + // the switch below is about winning and tie conditions. + // so it is good have checkWinOrTie() as a simple statement. + // totally optional. + switch checkWinOrTie(); { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won, tie: + if won { + fmt.Println(">>> WINNER:", player) + } else { + fmt.Println(">>> TIE!") + } + return false + } + return true +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +} diff --git a/x-tba/tictactoe/16-types/board.go b/x-tba/tictactoe/16-types/board.go new file mode 100644 index 0000000..ee5335d --- /dev/null +++ b/x-tba/tictactoe/16-types/board.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// printBoard prints the board +func printBoard() { + fmt.Printf("%s\n\n", banner) + fmt.Printf("%s\n", sepHeader) + + for i, step := 0, 3; i < len(cells); i += step { + fmt.Print(sepCell) + + for j := 0; j < step; j++ { + move := cells[i+j] + fmt.Printf(" %s %s", move, sepCell) + } + + fmt.Println() + + if lastLine := (i + step); lastLine != len(cells) { + fmt.Println(sepLine) + } + } + + fmt.Printf("%s\n", sepFooter) +} diff --git a/x-tba/tictactoe/16-types/board_test.go b/x-tba/tictactoe/16-types/board_test.go new file mode 100644 index 0000000..c2b0e01 --- /dev/null +++ b/x-tba/tictactoe/16-types/board_test.go @@ -0,0 +1,41 @@ +package main + +// Examples are normally used for showing how to use your package. +// But you can also use them as output testing. + +func ExamplePrintBoard() { + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | | | | + // +---+---+---+ + // | | | | + // +---+---+---+ + // | | | | + // \---+---+---/ +} + +func ExamplePrintBoardCells() { + cells[0] = player1 + cells[4] = player2 + cells[8] = player1 + printBoard() + + // Output: + // ~~~~~~~~~~~~~~~ + // TIC~TAC~TOE + // ~~~~~~~~~~~~~~~ + // + // /---+---+---\ + // | X | | | + // +---+---+---+ + // | | O | | + // +---+---+---+ + // | | | X | + // \---+---+---/ +} diff --git a/x-tba/tictactoe/16-types/ending.go b/x-tba/tictactoe/16-types/ending.go new file mode 100644 index 0000000..7e975cc --- /dev/null +++ b/x-tba/tictactoe/16-types/ending.go @@ -0,0 +1,58 @@ +package main + +// ------------------------------------------------- +// IS THERE A WINNER? OR IS IT A TIE? +// ------------------------------------------------- + +// /---+---+---\ +// | 0 | 1 | 2 | +// +---+---+---+ +// | 3 | 4 | 5 | +// +---+---+---+ +// | 6 | 7 | 8 | +// \---+---+---/ + +func checkWinOrTie() { + // intentional bug: tie shouldn't happen before winning detection + // if tie = turn == maxTurns; tie { + // // if tie don't check for the winning + // return + // } + + // loop over all the players + for i := 1; i <= 2; i++ { + // check for the next player + p := player2 + if i == 1 { + p = player1 + } + + /* check horizontals */ + hor := (cells[0] == p && cells[1] == p && cells[2] == p) || + (cells[3] == p && cells[4] == p && cells[5] == p) || + (cells[6] == p && cells[7] == p && cells[8] == p) + + /* check verticals */ + ver := (cells[0] == p && cells[3] == p && cells[6] == p) || + (cells[1] == p && cells[4] == p && cells[7] == p) || + (cells[2] == p && cells[5] == p && cells[8] == p) + + /* check diagonals */ + diag := (cells[0] == p && cells[4] == p && cells[8] == p) || + (cells[2] == p && cells[4] == p && cells[6] == p) + + // any winner? + if hor || ver || diag { + won = true + + // this player wins + player = p + + // there is a winner so don't check for tie! + return + } + } + + // check for tie + tie = turn == maxTurns +} diff --git a/x-tba/tictactoe/16-types/ending_test.go b/x-tba/tictactoe/16-types/ending_test.go new file mode 100644 index 0000000..629c22b --- /dev/null +++ b/x-tba/tictactoe/16-types/ending_test.go @@ -0,0 +1,59 @@ +package main + +import "testing" + +func TestWin(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | O | O | X | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player2 + cells[4] = player2 + cells[5] = player1 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !won { + t.Errorf("won = %t; want true", won) + } + + // TestWin was messing up with the results. + // Test ordering shouldn't be important. + initCells() +} + +func TestTie(t *testing.T) { + // /---+---+---\ + // | O | X | X | + // +---+---+---+ + // | X | O | O | + // +---+---+---+ + // | X | O | X | + // \---+---+---/ + + cells[0] = player2 + cells[1] = player1 + cells[2] = player1 + cells[3] = player1 + cells[4] = player2 + cells[5] = player2 + cells[6] = player1 + cells[7] = player2 + cells[8] = player1 + turn = maxTurns + + if checkWinOrTie(); !tie { + t.Errorf("tie = %t; want true", tie) + } + + initCells() +} diff --git a/x-tba/tictactoe/16-types/init.go b/x-tba/tictactoe/16-types/init.go new file mode 100644 index 0000000..1d76da3 --- /dev/null +++ b/x-tba/tictactoe/16-types/init.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "math/rand" + "os" + "strconv" + "time" +) + +// init is another special function +// Go calls it before the main function +func init() { + rand.Seed(time.Now().UnixNano()) + initCells() +} + +// initCells initialize the played cells to empty +func initCells() { + for i := range cells { + cells[i] = emptyCell + } +} + +func setGameSpeed() { + // args can be used within the if block + // gs and err can be used in the else if and else branches + if args := os.Args; len(args) == 1 { + fmt.Println("Setting game speed to default.") + } else if gs, err := strconv.Atoi(args[1]); err != nil { + fmt.Println("Wrong game speed. Provide an integer.") + } else { + gameSpeed = time.Duration(gs) * time.Second + } + + fmt.Printf("Game speed is %q.\n", gameSpeed) +} diff --git a/x-tba/tictactoe/16-types/main.go b/x-tba/tictactoe/16-types/main.go new file mode 100644 index 0000000..1ad0480 --- /dev/null +++ b/x-tba/tictactoe/16-types/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "time" +) + +/* +~ TICTACTOE GAME IN GO ~ ++ This example uses the very basics of the Go language. ++ The goal is learning all the basics. +*/ + +const ( + maxTurns = 9 + defaultGameSpeed = time.Second * 2 // time between plays +) + +var ( + won, tie bool // is there any winner or a tie? + turn int // total valid turns played + + cells [maxTurns]cell // used to draw the board: contains the players' moves + lastPos int // last played position + wrongMove bool // was the last move wrong? + + player = player1 // current player + gameSpeed = defaultGameSpeed // sets the default game speed +) + +// main is only responsible for the game loop, that's it. +func main() { + setGameSpeed() + printBoard() + wait() + + for nextTurn() { + wait() + } +} + +func wait() { + fmt.Println() + time.Sleep(gameSpeed) // player thinks... +} diff --git a/x-tba/tictactoe/16-types/play.go b/x-tba/tictactoe/16-types/play.go new file mode 100644 index 0000000..72c18b2 --- /dev/null +++ b/x-tba/tictactoe/16-types/play.go @@ -0,0 +1,37 @@ +package main + +import "math/rand" + +// play plays the game for the current player. +// + registers the player's move in the board. +// if the move is valid: +// + increases the turn. +func play() { + // pick a random move (very intelligent AI!) + // it can play to the same position! + lastPos = rand.Intn(maxTurns) + + // is it a valid move? + if cells[lastPos] != emptyCell { + wrongMove = true + + // skip the rest of the function from running + return + } + + // register the move: put the player's sign on the board + cells[lastPos] = player + + // increment the current turns + turn++ +} + +// switchPlayer switches to the next player +func switchPlayer() { + // switch the player + if player == player1 { + player = player2 + } else { + player = player1 + } +} diff --git a/x-tba/tictactoe/16-types/play_test.go b/x-tba/tictactoe/16-types/play_test.go new file mode 100644 index 0000000..6c3a161 --- /dev/null +++ b/x-tba/tictactoe/16-types/play_test.go @@ -0,0 +1,26 @@ +package main + +import "testing" + +func TestWrongMove(t *testing.T) { + // /---+---+---\ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // +---+---+---+ + // | X | X | X | + // \---+---+---/ + + // fill the board with artificial cells + for i := range cells { + cells[i] = player1 + } + + // any move beyond this point is wrong. + // reason: every cell is occupied. + if play(); !wrongMove { + t.Errorf("wrongMove = %t; want true", wrongMove) + } + + initCells() +} diff --git a/x-tba/tictactoe/16-types/skin.go b/x-tba/tictactoe/16-types/skin.go new file mode 100644 index 0000000..8855b7e --- /dev/null +++ b/x-tba/tictactoe/16-types/skin.go @@ -0,0 +1,19 @@ +package main + +// cell represents a tictactoe board cell +type cell string + +// skin options :-) +const ( + banner = ` +~~~~~~~~~~~~~~~ + TIC~TAC~TOE +~~~~~~~~~~~~~~~` + + player1, player2, emptyCell cell = "X", "O", " " + + sepHeader = `/---+---+---\` + sepLine = `+---+---+---+` + sepFooter = `\---+---+---/` + sepCell = "|" +) diff --git a/x-tba/tictactoe/16-types/turn.go b/x-tba/tictactoe/16-types/turn.go new file mode 100644 index 0000000..65bb1af --- /dev/null +++ b/x-tba/tictactoe/16-types/turn.go @@ -0,0 +1,45 @@ +package main + +import "fmt" + +// nextTurn prints the board for the next turn and checks for the winning conditions. +// if win or tie: returns false, otherwise true. +func nextTurn() bool { + play() + printBoard() + + fmt.Printf("\n>>> PLAYER %q PLAYS to %d\n", player, lastPos+1) + + // the switch below is about winning and tie conditions. + // so it is good have checkWinOrTie() as a simple statement. + // totally optional. + switch checkWinOrTie(); { + default: + switchPlayer() + printStatus() + + case wrongMove: + fmt.Printf(">>> CELL IS OCCUPIED: PLAY AGAIN!\n") + wrongMove = false // reset for the next turn + + case won, tie: + if won { + fmt.Println(">>> WINNER:", player) + } else { + fmt.Println(">>> TIE!") + } + return false + } + return true +} + +// printStatus prints the current status of the game +// it cannot access to the names (vars, consts, etc) inside any other func +func printStatus() { + fmt.Println() + + progress := (1 - (float64(turn) / maxTurns)) * 100 + fmt.Printf("Current Turn : %d\n", turn) + fmt.Printf("Is there a winner : %t\n", won) + fmt.Printf("Turns left : %.1f%%\n", progress) +}