Hlavní navigace

Programovací jazyk Go a 2D grafika – kostra jednoduché hry

Velmi důležitá je při tvorbě i relativně jednoduchých her či multimediálních aplikací celková struktura aplikace. Proto si v dnešním článku o knihovně go-sdl ukážeme, jak by se mohlo postupovat při postupných úpravách (stále triviální) hry.
Pavel Tišnovský
Doba čtení: 45 minut

Sdílet

11. Reakce na událost typu „ukončení aplikace“

12. Reakce na stisk kláves Escape a Q

13. Pohyb spritu pomocí kurzorových kláves

14. Úplný zdrojový kód osmého demonstračního příkladu

15. Vylepšení předchozího příkladu – reakce na stisk i puštění klávesy

16. Úplný zdrojový kód devátého demonstračního příkladu

17. Automaticky se pohybující sprite a klávesnicí ovládaný hráč

18. Úplný zdrojový kód desátého demonstračního příkladu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Programovací jazyk Go a 2D grafika – kostra jednoduché hry

Dnešní článek se bude v některých ohledech odlišovat od článků předchozích. Zatímco v dřívějších částech seriálu o programovacím jazyce Go jsme se snažili popsat co nejvíce funkcionality, dnes budeme na přání několika čtenářů postupovat odlišným – pomalejším – způsobem. Budeme totiž postupně upravovat jeden demonstrační příklad, který nakonec bude existovat v deseti verzích. První verze bude představována jednoduchou nestrukturovanou aplikací, poslední verze již bude sloužit jako poměrně slušně navržená kostra pro primitivní grafickou hříčku (výsledek se snad ani nedá nazývat „hrou“). Současně už nebudeme pro porovnání uvádět i céčkovou variantu příkladu, protože struktura céčkové hry bude od Go varianty v mnoha ohledech odlišná (tyto jazyky jsou i přes zdánlivou podobnost dosti rozdílné).

Poznámka: pokud vám nový způsob bude připadat příliš rozvláčný nebo naopak dobrý, prosím o zpětnou vazbu v komentářích.
*

Obrázek 1: Předlohou nám bude slavná starodávná hra Adventure pro osmibitovou herní konzoli Atari 2600. Zelený čtverec nalevo je hráč, žlutá „kachna“ je ve skutečnosti strašlivý a k tomu ještě hladový drak.

2. Vykreslení jednoduché scény s využitím knihovny go-sdl2

Ukažme si tedy první verzi příkladu. Ta je velmi jednoduchá a plně vychází z demonstračních příkladů, které jsme si popsali minule. Ve zdrojovém kódu se postupně provádí tyto operace:

  1. Provede se inicializace knihovny SDL funkcí sdl.Init, současně se zaregistruje kód pro ukončení SDL.
  2. Vytvoří se nové okno funkcí sdl.CreateWindow, opět se zaregistruje kód zavolaný pro uzavření okna.
  3. Získá se reference na primární kreslicí plochu, a to konkrétně metodouwindow.GetSurface (tato plocha se nijak nemusí uvolňovat).
  4. Načte se rastrový obrázek globe.png s alfa kanálem.
  5. Okno, resp. primární kreslicí plocha se vyplní konstantní barvou metodou primarySurface.FillRect.
  6. Rastrový obrázek se na primární plochu vykreslí metodouimage.Blit.
  7. Následně se počká na zobrazení okna – toto není striktně nutné v reálné aplikaci/hře se smyčkou událostí, ovšem pro jednoduchý program bez této smyčky je na některých systémech (kombinacích čipsetu a grafické karty) nutné chvíli počkat.
  8. Vynucení překreslení obsahu celého okna metodouwindow.UpdateSurface.
  9. Nakonec se po pěti sekundách (sdl.Delay) celá aplikace korektně ukončí.

Dále si povšimněte, že se testují prakticky všechny návratové kódy s chybou. To lze ověřit nástrojem errcheck, s nímž jsme se již v tomto seriálu setkali.

Obrázek 2: Bitmapa s alfa kanálem zobrazená v okně aplikace.

3. Zdrojový kód prvního demonstračního příkladu

Úplný zdrojový kód dnešního prvního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t01.go:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func main() {
        if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
                panic(err)
        }
        defer sdl.Quit()
 
        window, err := sdl.CreateWindow("SDL2 example #1", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
        defer window.Destroy()
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
        defer image.Free()
 
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - image.W/2,
                Y: height/2 - image.H/2,
                W: 0,
                H: 0,
        }
 
        err = image.Blit(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
        sdl.Delay(10)
 
        window.UpdateSurface()
 
        sdl.Delay(5000)
}
*

Obrázek 3: Drak ve hře Adventure právě dohnal hráče…

4. Rozdělení kódu aplikace do několika funkcí

V předchozím zdrojovém kódu byla celá funkcionalita soustředěna v jediné funkci main, což sice zdánlivě nemusí vadit (ostatně příklad je stále velmi krátký), ovšem s rostoucí složitostí nebude tato struktura zdrojového kódu dobře „škálovat“ a po určité době se programátor ve svém kódu doslova ztratí. První varianta úpravy může spočívat v tom, že se stav celé aplikace, což je v této chvíli trojice objektů (datových struktur splňujících určitá rozhraní), uloží do globálních proměnných:

var (
        window         *sdl.Window
        primarySurface *sdl.Surface
        image          *sdl.Surface
)

Celá aplikace se díky tomu rozdělí do trojice funkcí volaných z funkce main, která je vstupním bodem do celé aplikace:

  1. Inicializace – initialize
  2. Finalizace – finalize
  3. Překreslení obsahu hlavního okna – redraw

Úplný zdrojový kód naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t02.go:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
var (
        window         *sdl.Window
        primarySurface *sdl.Surface
        image          *sdl.Surface
)
 
func initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        window, err = sdl.CreateWindow("SDL2 example #2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        primarySurface, err = window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
}
 
func finalize() {
        primarySurface.Free()
        image.Free()
        window.Destroy()
        sdl.Quit()
}
 
func redraw() {
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - image.W/2,
                Y: height/2 - image.H/2,
                W: 0,
                H: 0,
        }
 
        err := image.Blit(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
}
 
func main() {
        initialize()
        defer finalize()
 
        sdl.Delay(10)
        redraw()
        sdl.Delay(5000)
}

5. Použití lokálních proměnných, předávání stavu aplikace do volaných funkcí

Předchozí zdrojový kód pravděpodobně nikoho neohromil, protože se v něm pro uložení stavu aplikace používají globální proměnné, což mj. do značné míry ztěžuje ladění a testování aplikace (nehledě na problémy s použitím ukazatelů ve chvíli, kdyby se nějaká část aplikace spustila ve vlastní gorutině).

Poznámka: právě stav resp. možná přesněji řečeno stavový prostor je pro mnoho aplikací kritickým parametrem, který ovlivňuje to, do jaké míry je aplikace rozšiřitelná a testovatelná. Ostatně pro příklad nemusíme chodit daleko – díky tomu, že mnoho programovacích jazyků nabízí programátorům automatickou správu paměti (garbage collector) se stavový prostor mnohdy dosti razantním způsobem zmenšuje (nemusíme u všech objektů řešit, kdo je jejich vlastník a kdo je může uvolnit z operační paměti), takže se v těchto jazycích dají psát i rozsáhlejší aplikace. Jinými slovy – pokud se stavový prostor podaří udržet v rozumných mezích, může být aplikace (měřená množstvím kódu, například počtem řádků) i velmi rozsáhlá a přesto stále dobře udržovatelná.

Větší izolaci jednotlivých funkcí zajistíme použitím parametrů nesoucích informace o stavu aplikace. Tyto parametry jsou předávány do všech funkcí, které s nimi pracují. Vzhledem k tomu, že všechny objekty nesoucí stav aplikace jsou vytvářeny ve funkci initialize, můžeme její hlavičku upravit takto:

func initialize() (*sdl.Window, *sdl.Surface, *sdl.Surface) {
    ...
    ...
    ...
}

Všechny ostatní funkce se přímo či nepřímo volají z funkce main:

func main() {
        window, primarySurface, image := initialize()
        defer finalize(window, primarySurface, image)
 
        sdl.Delay(10)
        redraw(window, primarySurface, image)
        sdl.Delay(5000)
}
Poznámka: povšimněte si, že se do všech funkcí předávají ukazatele, takže se neprovádí kopie dat a současně je možné ve funkcích modifikovat stav aplikace (což zde konkrétně nebudeme potřebovat).
*

Obrázek 4: Drak právě spapal hráče; nyní zbývá jen stlačení RESETu.

6. Zdrojový kód třetího demonstračního příkladu

Úplný zdrojový kód dnešního třetího demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t03.go:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
func initialize() (*sdl.Window, *sdl.Surface, *sdl.Surface) {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        window, err := sdl.CreateWindow("SDL2 example #3", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        primarySurface, err := window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        image, err := img.Load("globe.png")
        if err != nil {
                panic(err)
        }
 
        return window, primarySurface, image
}
 
func finalize(window *sdl.Window, primarySurface *sdl.Surface, image *sdl.Surface) {
        primarySurface.Free()
        image.Free()
        window.Destroy()
        sdl.Quit()
}
 
func redraw(window *sdl.Window, primarySurface *sdl.Surface, image *sdl.Surface) {
        primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - image.W/2,
                Y: height/2 - image.H/2,
                W: 0,
                H: 0,
        }
 
        err := image.Blit(nil, primarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        window.UpdateSurface()
}
 
func main() {
        window, primarySurface, image := initialize()
        defer finalize(window, primarySurface, image)
 
        sdl.Delay(10)
        redraw(window, primarySurface, image)
        sdl.Delay(5000)
}

7. Jediná datová struktura obsahující celý stav aplikace

Při čtení předchozí varianty zdrojového kódu vás možná napadlo, že se vlastně stále pracuje se stejnými strukturami, resp. ukazateli na ně a že by tedy mohlo být výhodné tyto struktury sloučit do jediného datového typu. To je v jazyce Go snadné, takže si vytvořme nový datový typ pojmenovaný například gameState:

type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}
Poznámka: povšimněte si, že do struktury ukládáme pouze ukazatele. O správu paměti se totiž nemusíme v Go (většinou) explicitně starat, protože sám překladač si zvolí, zda nějakou proměnnou uloží na zásobník (stack) či na haldu (heap), což je chování odlišné například od klasického jazyka C. Pokud ukazatel bude obsahovat adresu objektu (i když vytvořeného lokálně v jedné funkci), bude tento objekt automaticky alokován na haldě a správce paměti zajistí dealokaci až ve chvíli, kdy ukazatel přestane být platný.

Jakmile máme vytvořenou novou strukturu obsahující veškerý stav aplikace, zdrojový kód se může zjednodušit, protože do funkcí budeme předávat jen jediný parametr – ukazatel na danou strukturu (zde viditelnou lokálně v rámci funkce main):

func main() {
        var state gameState
        initialize(&state)
        defer finalize(&state)
 
        sdl.Delay(10)
        redraw(&state)
        sdl.Delay(5000)
}

Opět si ukažme celý zdrojový kód takto upraveného programu:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}
 
func initialize(state *gameState) {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #4", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
}
 
func finalize(state *gameState) {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func redraw(state *gameState) {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - state.Image.W/2,
                Y: height/2 - state.Image.H/2,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func main() {
        var state gameState
        initialize(&state)
        defer finalize(&state)
 
        sdl.Delay(10)
        redraw(&state)
        sdl.Delay(5000)
}

8. Použití rozhraní (interface)

Od předchozího zdrojového kódu je již jen krůček k tomu, abychom využili další vlastnost programovacího jazyka Go. Jedná se o možnost vytvářet rozhraní interface a metody (methods) pro konkrétní datový typ. Pokud nějaký datový typ obsahuje všechny metody daného rozhraní, je automaticky toto rozhraní typem uspokojeno (satisfy), takže se v Go nemusí používat obdoba deklarace objekt/typ implements rozhraní. Připomeňme si, že náš datový typ se stavem aplikace vypadá následovně:

type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}

Dále nadeklarujeme rozhraní, které bude obsahovat pouze hlavičky metod, tj. jejich názvy, případné parametry a návratové hodnoty:

type Game interface {
        initialize()
        finalize()
        redraw()
}

Nyní nám již stačí relativně malá úprava – z funkcí initialize atd. vytvoříme metody. Tj. namísto běžné funkce akceptující ukazatel na datovou strukturu:

func initialize(state *gameState) {
        ...
        ...
        ...
}

Vytvoříme metodu, jejímž příjemcem (receiver) je daná struktura popř. ukazatel na ni:

func (state *gameState) initialize() {
        ...
        ...
        ...
}

Interně se v metodě chováme k příjemci stejně, jakoby se jednalo o parametr.

Poznámka: pokud je příjemcem přímo struktura a nikoli ukazatel na ni, nebude změna stavu viditelná mimo danou metodu, protože se do metody ve skutečnosti přenese kopie struktury.

V příkladu se dále zjednoduší a zpřehlední funkce main, která přestává mít „céčkový“ ráz:

func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.redraw()
        sdl.Delay(5000)
}
*

Obrázek 5: Bludiště ve hře Adventure. Vlevo nahoře se nachází hráč (čtverec) nesoucí meč (šipku) :-)

9. Úplný zdrojový kód upraveného příkladu

Ukažme si nyní celý kód příkladu založeného na použití rozhraní:

package main
 
import (
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
}
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #5", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - state.Image.W/2,
                Y: height/2 - state.Image.H/2,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.redraw()
        sdl.Delay(5000)
}

10. Systém událostí (events)

Velmi důležitým konceptem, s nímž se v knihovně SDL setkáme, je systém událostí (events). Při běhu aplikace totiž dochází ke vzniku událostí, které jsou vyvolány jak samotným systémem (časovač…), tak i uživatelem (stisk klávesy, posun kurzoru myši, …). Na tyto události může aplikace v případě potřeby adekvátně reagovat.

Interně systém událostí pracuje přibližně takto:

  1. Knihovna SDL si při své inicializaci vytvoří takzvanou frontu událostí
  2. Po spuštění aplikace se spustí programová smyčka nazvaná většinou event loop, která postupně z fronty událostí vybírá jednotlivé události (samozřejmě jen za předpokladu, že k nim došlo)
  3. Následně se pro událost získanou z fronty zavolá příslušný programový kód

11. Reakce na událost typu „ukončení aplikace“

Prvním typem události je událost nazvaná QuitEvent. Tato událost vznikne ve chvíli, kdy se uživatel rozhodne aplikaci ukončit, typicky stiskem ikony sloužící pro uzavření okna. Celá smyčka událostí může vypadat následovně:

func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        for !done {
                event = sdl.PollEvent()
                switch event.(type) {
                case *sdl.QuitEvent:
                        log.Println("Quitting")
                        done = true
                }
                state.redraw()
                sdl.Delay(20)
        }
}
Poznámka: povšimněte si především toho, jak se provádí rozeskok na základě typu události. Jedná se o odlišný postup, než na který byste narazili v programovacím jazyku C.

Smyčka se volá z funkce main:

func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

Úplný zdrojový kód naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t06.go:

package main
 
import (
        "log"
 
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
        eventLoop()
}
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #6", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - state.Image.W/2,
                Y: height/2 - state.Image.H/2,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        for !done {
                event = sdl.PollEvent()
                switch event.(type) {
                case *sdl.QuitEvent:
                        log.Println("Quitting")
                        done = true
                }
                state.redraw()
                sdl.Delay(20)
        }
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

12. Reakce na stisk kláves Escape a Q

Snadno můžeme reagovat i na události typu „stisk klávesy“. Jedná se o událost PRESSED, přičemž struktura nesoucí informace o události obsahuje kód stisknuté klávesy. Tento kód lze porovnat s konstantami, které jsou součástí balíčku sdl a ukončit tak aplikaci například při stisku klávesy Escape popř. Q:

switch t := event.(type) {
case *sdl.QuitEvent:
        done = true
case *sdl.KeyboardEvent:
        keyCode := t.Keysym.Sym
        if t.State == sdl.PRESSED {
                switch keyCode {
                case sdl.K_ESCAPE:
                        done = true
                case sdl.K_q:
                        done = true
                }
        }
}

Upravená aplikace vypadá následovně:

package main
 
import (
        "log"
 
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
        eventLoop()
}
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #7", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: width/2 - state.Image.W/2,
                Y: height/2 - state.Image.H/2,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        for !done {
                event = sdl.PollEvent()
                switch t := event.(type) {
                case *sdl.QuitEvent:
                        done = true
                case *sdl.KeyboardEvent:
                        keyCode := t.Keysym.Sym
                        if t.State == sdl.PRESSED {
                                switch keyCode {
                                case sdl.K_ESCAPE:
                                        done = true
                                case sdl.K_q:
                                        done = true
                                }
                        }
                }
                state.redraw()
                sdl.Delay(20)
        }
        log.Println("Quitting")
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

13. Pohyb spritu pomocí kurzorových kláves

Nyní rozšíříme stav aplikace o souřadnice spritu (obrázku zeměkoule):

type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
        X, Y           int32
}

Zeměkoulí budeme pohybovat kurzorovými šipkami, což se projeví i v nepatrně odlišném kódu pro vykreslení:

dstRect := sdl.Rect{
        X: state.X,
        Y: state.Y,
        W: 0,
        H: 0,
}
 
err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
...
...
...

Teoreticky je možné reagovat na stisk klávesy, například takto:

switch keyCode {
case sdl.K_LEFT:
        state.X -= 2
case sdl.K_RIGHT:
        state.X += 2
case sdl.K_UP:
        state.Y -= 2
case sdl.K_DOWN:
        state.Y += 2
}

Ovšem po spuštění příkladu uvidíte, že se bude projevovat tzv. autorepeat klávesnice a současně nebude pohyb okamžitý.

14. Úplný zdrojový kód osmého demonstračního příkladu

Úplný zdrojový kód osmého demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t08.go:

package main
 
import (
        "log"
 
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
        eventLoop()
}
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
        X, Y           int32
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #8", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
 
        state.X = width/2 - state.Image.W/2
        state.Y = height/2 - state.Image.H/2
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: state.X,
                Y: state.Y,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        for !done {
                event = sdl.PollEvent()
                switch t := event.(type) {
                case *sdl.QuitEvent:
                        done = true
                case *sdl.KeyboardEvent:
                        keyCode := t.Keysym.Sym
                        if t.State == sdl.PRESSED {
                                switch keyCode {
                                case sdl.K_ESCAPE:
                                        done = true
                                case sdl.K_q:
                                        done = true
                                case sdl.K_LEFT:
                                        state.X -= 2
                                case sdl.K_RIGHT:
                                        state.X += 2
                                case sdl.K_UP:
                                        state.Y -= 2
                                case sdl.K_DOWN:
                                        state.Y += 2
                                }
                        }
                }
                state.redraw()
                sdl.Delay(20)
        }
        log.Println("Quitting")
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

15. Vylepšení předchozího příkladu – reakce na stisk i puštění klávesy

Z předchozího příkladu bylo patrné, že kvůli autorepeatu není pohyb hráče plynulý. Je tedy nutné použít odlišnou logiku – ta spočívá v tom, že si zapamatujeme jak stisk klávesy, tak i její puštění. Jedná se sice o stejnou událost, ale s jiným typem: PRESSED versus RELEASED:

case sdl.PRESSED:
        switch keyCode {
        case sdl.K_LEFT:
                left = true
        case sdl.K_RIGHT:
                right = true
        case sdl.K_UP:
                up = true
        case sdl.K_DOWN:
                down = true
        }
case sdl.RELEASED:
        switch keyCode {
        case sdl.K_LEFT:
                left = false
        case sdl.K_RIGHT:
                right = false
        case sdl.K_UP:
                up = false
        case sdl.K_DOWN:
                down = false
        }
Poznámka: je typické, že funkce s realizovanou smyčkou událostí bývá nejkomplikovanější částí celé aplikace. Ovšem s trochou práce je možné celou smyčku rozdělit a realizovat ji například formou callback funkcí, což je téma, kterému se pravděpodobně budeme věnovat příště.

16. Úplný zdrojový kód devátého demonstračního příkladu

Úplný zdrojový kód dnešního předposledního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t09.go:

package main
 
import (
        "log"
 
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
        eventLoop()
}
 
type gameState struct {
        Window         *sdl.Window
        PrimarySurface *sdl.Surface
        Image          *sdl.Surface
        X, Y           int32
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #9", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
 
        state.X = width/2 - state.Image.W/2
        state.Y = height/2 - state.Image.H/2
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        dstRect := sdl.Rect{
                X: state.X,
                Y: state.Y,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        left := false
        right := false
        up := false
        down := false
 
        for !done {
                event = sdl.PollEvent()
                switch t := event.(type) {
                case *sdl.QuitEvent:
                        done = true
                case *sdl.KeyboardEvent:
                        keyCode := t.Keysym.Sym
                        switch t.State {
                        case sdl.PRESSED:
                                switch keyCode {
                                case sdl.K_ESCAPE:
                                        done = true
                                case sdl.K_q:
                                        done = true
                                case sdl.K_LEFT:
                                        left = true
                                case sdl.K_RIGHT:
                                        right = true
                                case sdl.K_UP:
                                        up = true
                                case sdl.K_DOWN:
                                        down = true
                                }
                        case sdl.RELEASED:
                                switch keyCode {
                                case sdl.K_LEFT:
                                        left = false
                                case sdl.K_RIGHT:
                                        right = false
                                case sdl.K_UP:
                                        up = false
                                case sdl.K_DOWN:
                                        down = false
                                }
                        }
                }
                if left {
                        state.X -= 2
                }
                if right {
                        state.X += 2
                }
                if up {
                        state.Y -= 2
                }
                if down {
                        state.Y += 2
                }
                state.redraw()
                sdl.Delay(20)
        }
        log.Println("Quitting")
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

17. Automaticky se pohybující sprite a klávesnicí ovládaný hráč

Poslední úprava bude spočívat v tom, že necháme zeměkouli (sprite), aby se ve scéně pohybovala automaticky – odrážela se od stěn okna. Ovšem navíc do scény přidáme hráče, který bude – stejně jako ve hře Adventure – realizován pouhým obdélníkem. Celý stavový prostor hry se tedy dále rozšíří:

type gameState struct {
        Window           *sdl.Window
        PrimarySurface   *sdl.Surface
        Image            *sdl.Surface
        PlayerX, PlayerY int32
        NPCX, NPCY       int32
        NPCdX, NPCdY     int32
}
Poznámka: pravděpodobně by bylo ještě lepší reprezentovat pozice hráče i NPC, popř. relativní pohyb NPC strukturou sdl.Point.

Samotný pohyb zeměkoule (NPC) může být realizován následovně (konstanty na začátku byly získány v grafickém editoru, protože sprite okolo sebe obsahuje i neviditelné či poloprůhledné okraje):

func moveNPC(state *gameState) {
        const (
                LeftBorder   = 5
                TopBorder    = 5
                RightBorder  = 10
                BottomBorder = 10
        )
        state.NPCX += state.NPCdX
        state.NPCY += state.NPCdY
 
        if state.NPCX > state.PrimarySurface.W-state.Image.W+RightBorder {
                state.NPCdX = -state.NPCdX
        }
        if state.NPCY > state.PrimarySurface.H-state.Image.H+BottomBorder {
                state.NPCdY = -state.NPCdY
        }
        if state.NPCX < -LeftBorder {
                state.NPCdX = -state.NPCdX
        }
        if state.NPCY < -TopBorder {
                state.NPCdY = -state.NPCdY
        }
}
*

Obrázek 6: Fandové hry Adventure (stále existují!) si mohou pořídit tričko s pro tuto hry typickým drakem (který vypadá spíš jako kachna :-)

Root linux

18. Úplný zdrojový kód desátého demonstračního příkladu

Úplný zdrojový kód desátého a současně i posledního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/tes­t10.go:

package main
 
import (
        "log"
 
        "github.com/veandco/go-sdl2/img"
        "github.com/veandco/go-sdl2/sdl"
)
 
const (
        width  = 640
        height = 480
)
 
type Game interface {
        initialize()
        finalize()
        redraw()
        eventLoop()
}
 
type gameState struct {
        Window           *sdl.Window
        PrimarySurface   *sdl.Surface
        Image            *sdl.Surface
        PlayerX, PlayerY int32
        NPCX, NPCY       int32
        NPCdX, NPCdY     int32
}
 
func NewGame() gameState {
        return gameState{
                Window:         nil,
                PrimarySurface: nil,
                Image:          nil,
        }
}
 
func (state *gameState) initialize() {
        err := sdl.Init(sdl.INIT_VIDEO)
        if err != nil {
                panic(err)
        }
 
        state.Window, err = sdl.CreateWindow("SDL2 example #10", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
                width, height, sdl.WINDOW_SHOWN)
        if err != nil {
                panic(err)
        }
 
        state.PrimarySurface, err = state.Window.GetSurface()
        if err != nil {
                panic(err)
        }
 
        state.Image, err = img.Load("globe.png")
        if err != nil {
                panic(err)
        }
 
        state.NPCX = width/2 - state.Image.W/2
        state.NPCY = height/2 - state.Image.H/2
        state.NPCdX = 1
        state.NPCdY = 1
 
        state.PlayerX = 100
        state.PlayerY = 100
}
 
func (state *gameState) finalize() {
        state.PrimarySurface.Free()
        state.Image.Free()
        state.Window.Destroy()
        sdl.Quit()
}
 
func moveNPC(state *gameState) {
        const (
                LeftBorder   = 5
                TopBorder    = 5
                RightBorder  = 10
                BottomBorder = 10
        )
        state.NPCX += state.NPCdX
        state.NPCY += state.NPCdY
 
        if state.NPCX > state.PrimarySurface.W-state.Image.W+RightBorder {
                state.NPCdX = -state.NPCdX
        }
        if state.NPCY > state.PrimarySurface.H-state.Image.H+BottomBorder {
                state.NPCdY = -state.NPCdY
        }
        if state.NPCX < -LeftBorder {
                state.NPCdX = -state.NPCdX
        }
        if state.NPCY < -TopBorder {
                state.NPCdY = -state.NPCdY
        }
 
}
 
func (state *gameState) redraw() {
        state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192))
 
        playerRect := sdl.Rect{
                X: state.PlayerX,
                Y: state.PlayerY,
                W: 20,
                H: 20,
        }
        state.PrimarySurface.FillRect(&playerRect, sdl.MapRGB(state.PrimarySurface.Format, 255, 192, 192))
 
        dstRect := sdl.Rect{
                X: state.NPCX,
                Y: state.NPCY,
                W: 0,
                H: 0,
        }
 
        err := state.Image.Blit(nil, state.PrimarySurface, &dstRect)
        if err != nil {
                panic(err)
        }
 
        state.Window.UpdateSurface()
}
 
func (state *gameState) eventLoop() {
        var event sdl.Event
        done := false
        left := false
        right := false
        up := false
        down := false
 
        for !done {
                event = sdl.PollEvent()
                switch t := event.(type) {
                case *sdl.QuitEvent:
                        done = true
                case *sdl.KeyboardEvent:
                        keyCode := t.Keysym.Sym
                        switch t.State {
                        case sdl.PRESSED:
                                switch keyCode {
                                case sdl.K_ESCAPE:
                                        done = true
                                case sdl.K_q:
                                        done = true
                                case sdl.K_LEFT:
                                        left = true
                                case sdl.K_RIGHT:
                                        right = true
                                case sdl.K_UP:
                                        up = true
                                case sdl.K_DOWN:
                                        down = true
                                }
                        case sdl.RELEASED:
                                switch keyCode {
                                case sdl.K_LEFT:
                                        left = false
                                case sdl.K_RIGHT:
                                        right = false
                                case sdl.K_UP:
                                        up = false
                                case sdl.K_DOWN:
                                        down = false
                                }
                        }
                }
                if left {
                        state.PlayerX -= 2
                }
                if right {
                        state.PlayerX += 2
                }
                if up {
                        state.PlayerY -= 2
                }
                if down {
                        state.PlayerY += 2
                }
                moveNPC(state)
                state.redraw()
                sdl.Delay(10)
        }
        log.Println("Quitting")
}
 
func main() {
        game := NewGame()
        game.initialize()
        defer game.finalize()
 
        sdl.Delay(10)
        game.eventLoop()
}

19. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 test01.go vykreslení jednoduché scény s využitím knihovny go-sdl2 https://github.com/tisnik/go-root/blob/master/article63/test01.go
2 test02.go rozdělení kódu aplikace do několika funkcí https://github.com/tisnik/go-root/blob/master/article63/test02.go
3 test03.go použití lokálních proměnných, předávání stavu aplikace do volaných funkcí https://github.com/tisnik/go-root/blob/master/article63/test03.go
4 test04.go jediná datová struktura obsahující celý stav aplikace https://github.com/tisnik/go-root/blob/master/article63/test04.go
5 test05.go použití rozhraní (interface) https://github.com/tisnik/go-root/blob/master/article63/test05.go
6 test06.go reakce na událost typu „ukončení aplikace“ https://github.com/tisnik/go-root/blob/master/article63/test06.go
7 test07.go reakce na stisk kláves Escape a Q https://github.com/tisnik/go-root/blob/master/article63/test07.go
8 test08.go pohyb spritu pomocí kurzorových kláves https://github.com/tisnik/go-root/blob/master/article63/test08.go
9 test09.go vylepšení předchozího příkladu – reakce na stisk i puštění klávesy https://github.com/tisnik/go-root/blob/master/article63/test09.go
10 test10.go automaticky se pohybující sprite a klávesnicí ovládaný hráč https://github.com/tisnik/go-root/blob/master/article63/test10.go

20. Odkazy na Internetu

  1. Adventure for the Atari 2600 Video Game Console by Warren Robinett
    http://www.warrenrobinett­.com/adventure/index.html
  2. Mapa hry Adventure
    http://www.warrenrobinett­.com/adventure/adv-map1.gif
  3. Stránky projektu SDL
    http://www.libsdl.org/
  4. Simple DirectMedia Layer (Wikipedia)
    https://en.wikipedia.org/wi­ki/Simple_DirectMedia_Lay­er
  5. SDL Language Bindings
    http://www.libsdl.org/languages.php
  6. SDL version 1.2.15
    http://www.libsdl.org/download-1.2.php
  7. SDL version 2.0.1
    http://www.libsdl.org/download-2.0.php
  8. Rozhraní go-sdl2
    https://github.com/veandco/go-sdl2
  9. Dokumentace k rozhraní go-sdl2
    https://godoc.org/github.com/ve­andco/go-sdl2
  10. Dokumentace k balíčku sdl
    https://godoc.org/github.com/ve­andco/go-sdl2/sdl
  11. Dokumentace k balíčku gfx
    https://godoc.org/github.com/ve­andco/go-sdl2/gfx
  12. Cross-platform games development (part 1)
    http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/
  13. Cross-platform games development (part 2)
    http://renatoc.wait4.org/tag/sdljava/
  14. Go Data Structures: Binary Search Tree
    https://flaviocopes.com/golang-data-structure-binary-search-tree/
  15. Gobs of data
    https://blog.golang.org/gobs-of-data
  16. Formát BSON
    http://bsonspec.org/
  17. Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
    https://blog.intelligentbe­e.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/
  18. Tvorba univerzálních projevů
    http://www.kyblsoft.cz/projevy
  19. Repositář projektu Gift
    https://github.com/disinte­gration/gift
  20. Dokumentace k projektu Gift
    https://godoc.org/github.com/di­sintegration/gift
  21. Online x86 / x64 Assembler and Disassembler
    https://defuse.ca/online-x86-assembler.htm#disassembly2
  22. The Design of the Go Assembler
    https://talks.golang.org/2016/as­m.slide#1
  23. A Quick Guide to Go's Assembler
    https://golang.org/doc/asm
  24. AssemblyPolicy
    https://github.com/golang/go/wi­ki/AssemblyPolicy
  25. Geohash in Golang Assembly
    https://mmcloughlin.com/posts/geohash-assembly
  26. Command objdump
    https://golang.org/cmd/objdump/
  27. Assembly
    https://goroutines.com/asm
  28. Go & Assembly
    http://www.doxsey.net/blog/go-and-assembly
  29. A Foray Into Go Assembly Programming
    https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/
  30. Golang Capturing log.Println And fmt.Println Output
    https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4
  31. Stránka projektu plotly
    https://plot.ly/
  32. Plotly JavaScript Open Source Graphing Library
    https://plot.ly/javascript/
  33. Domain coloring
    https://en.wikipedia.org/wi­ki/Domain_coloring
  34. Michael Fogleman's projects
    https://www.michaelfogleman­.com/projects/tagged/grap­hics/
  35. Color Graphs of Complex Functions
    https://web.archive.org/web/20120511021419/htt­p://w.american.edu/cas/mat­hstat/lcrone/ComplexPlot.html
  36. A Gallery of Complex Functions
    http://wismuth.com/complex/ga­llery.html
  37. package glot
    https://godoc.org/github.com/A­rafatk/glot
  38. Gnuplotting: Output terminals
    http://www.gnuplotting.org/output-terminals/
  39. Introducing Glot the plotting library for Golang
    https://medium.com/@Arafat­./introducing-glot-the-plotting-library-for-golang-3133399948a1
  40. Introducing Glot the plotting library for Golang
    https://blog.gopheracademy.com/advent-2018/introducing-glot/
  41. Glot is a plotting library for Golang built on top of gnuplot
    https://github.com/Arafatk/glot
  42. Example plots (gonum/plot)
    https://github.com/gonum/plot/wi­ki/Example-plots
  43. A repository for plotting and visualizing data (gonum/plot)
    https://github.com/gonum/plot
  44. golang library to make https://chartjs.org/ plots
    https://github.com/brentp/go-chartjs
  45. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  46. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  47. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  48. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  49. gonum
    https://github.com/gonum
  50. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  51. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  52. Gonum Numerical Packages
    https://www.gonum.org/
  53. Stránky projektu MinIO
    https://min.io/
  54. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  55. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  56. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  57. Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
    https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/
  58. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  59. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  60. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  61. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  62. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  63. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  64. Ginkgo
    http://onsi.github.io/ginkgo/
  65. Gomega
    https://onsi.github.io/gomega/
  66. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  67. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  68. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  69. Balíček goexpect
    https://github.com/google/goexpect
  70. Balíček go-expect
    https://github.com/Netflix/go-expect
  71. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  72. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  73. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  74. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  75. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  76. goblin na GitHubu
    https://github.com/franela/goblin
  77. Mocha framework
    https://mochajs.org/
  78. frisby na GitHubu
    https://github.com/verdverm/frisby
  79. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  80. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  81. Cucumber for golang
    https://github.com/DATA-DOG/godog
  82. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  83. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  84. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  85. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  86. xml.org
    http://www.xml.org/
  87. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  88. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  89. JSON to YAML
    https://www.json2yaml.com/
  90. Data Format Converter
    https://toolkit.site/format.html
  91. Viper na GitHubu
    https://github.com/spf13/viper
  92. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  93. The fantastic ORM library for Golang
    http://gorm.io/
  94. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  95. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  96. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  97. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  98. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  99. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  100. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  101. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  102. Sémantické verzování
    https://semver.org/
  103. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  104. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  105. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  106. Modules
    https://github.com/golang/go/wi­ki/Modules
  107. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  108. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  109. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  110. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  111. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  112. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  113. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  114. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  115. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  116. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  117. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  118. gopls
    https://github.com/golang/go/wi­ki/gopls
  119. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  120. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  121. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  122. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  123. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  124. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  125. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  126. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  127. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  128. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  129. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  130. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  131. Package trace
    https://golang.org/pkg/runtime/trace/
  132. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  133. Command trace
    https://golang.org/cmd/trace/
  134. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  135. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  136. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  137. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  138. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  139. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  140. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  141. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  142. Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/
  143. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  144. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  145. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  146. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  147. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  148. The LLDB Debugger
    http://lldb.llvm.org/
  149. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  150. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  151. Go is on a Trajectory to Become the Next Enterprise Programming Language
    https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e
  152. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  153. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  154. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  155. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  156. 10 tools written in Go that every developer needs to know
    https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/
  157. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  158. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  159. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  160. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  161. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  162. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  163. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  164. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  165. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  166. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  167. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  168. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  169. go-cron
    https://github.com/rk/go-cron
  170. gocron
    https://github.com/jasonlvhit/gocron
  171. clockwork
    https://github.com/whiteShtef/cloc­kwork
  172. clockwerk
    https://github.com/onatm/clockwerk
  173. JobRunner
    https://github.com/bamzi/jobrunner
  174. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  175. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  176. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  177. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  178. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  179. go-prompt
    https://github.com/c-bata/go-prompt
  180. readline
    https://github.com/chzyer/readline
  181. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  182. go-readline
    https://github.com/fiorix/go-readline
  183. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  184. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  185. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  186. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  187. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  188. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  189. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  190. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  191. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  192. Editline Library (libedit)
    http://thrysoee.dk/editline/
  193. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  194. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  195. WinEditLine
    http://mingweditline.sourceforge.net/
  196. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  197. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  198. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  199. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  200. history(3) – Linux man page
    https://linux.die.net/man/3/history
  201. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  202. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  203. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  204. Balíček ogletest
    https://github.com/jacobsa/ogletest
  205. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  206. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  207. package testing
    https://golang.org/pkg/testing/
  208. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  209. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  210. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  211. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  212. GoConvey
    http://goconvey.co/
  213. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  214. 5 simple tips and tricks for writing unit tests in #golang
    https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
  215. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  216. package gg
    https://godoc.org/github.com/fo­gleman/gg
  217. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  218. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  219. The Go image package
    https://blog.golang.org/go-image-package
  220. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  221. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  222. YAML
    https://yaml.org/
  223. edn
    https://github.com/edn-format/edn
  224. Smile
    https://github.com/FasterXML/smile-format-specification
  225. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  226. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  227. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  228. Introducing JSON
    http://json.org/
  229. Package json
    https://golang.org/pkg/encoding/json/
  230. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  231. Go by Example: JSON
    https://gobyexample.com/json
  232. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  233. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  234. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  235. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  236. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  237. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  238. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  239. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  240. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  241. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  242. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  243. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  244. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  245. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  246. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  247. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  248. Algorithms to Go
    https://yourbasic.org/
  249. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  250. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/
  251. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  252. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  253. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  254. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  255. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  256. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  257. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  258. The Go Programming Language (home page)
    https://golang.org/
  259. GoDoc
    https://godoc.org/
  260. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  261. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  262. The Go Programming Language Specification
    https://golang.org/ref/spec
  263. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  264. Package builtin
    https://golang.org/pkg/builtin/
  265. Package fmt
    https://golang.org/pkg/fmt/
  266. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  267. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  268. Learning Go
    https://www.miek.nl/go/
  269. Go Bootcamp
    http://www.golangbootcamp.com/
  270. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  271. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  272. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  273. The Go Blog
    https://blog.golang.org/
  274. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  275. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  276. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  277. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  278. How the Go runtime implements maps efficiently (without generics)
    https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics
  279. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  280. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  281. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  282. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  283. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  284. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  285. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  286. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  287. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  288. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  289. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  290. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  291. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  292. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  293. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  294. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  295. Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
    https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/
  296. 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
    https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd
  297. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  298. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  299. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  300. Go vs. Python
    https://www.peterbe.com/plog/govspy
  301. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  302. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  303. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  304. Go by Example: Slices
    https://gobyexample.com/slices
  305. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  306. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  307. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  308. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  309. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  310. nils In Go
    https://go101.org/article/nil.html
  311. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  312. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  313. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  314. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  315. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  316. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  317. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  318. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  319. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  320. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  321. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  322. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  323. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  324. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  325. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  326. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  327. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  328. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  329. Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
    https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06
  330. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  331. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  332. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  333. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  334. Selectors
    https://golang.org/ref/spec#Selectors
  335. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  336. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  337. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  338. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  339. Part 21: Goroutines
    https://golangbot.com/goroutines/
  340. Part 22: Channels
    https://golangbot.com/channels/
  341. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  342. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  343. Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
    https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  344. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  345. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  346. Control Structures
    https://www.golang-book.com/books/intro/5
  347. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  348. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  349. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  350. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  351. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  352. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  353. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  354. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  355. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  356. Effective Go
    https://golang.org/doc/ef­fective_go.html
  357. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  358. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  359. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  360. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  361. Nils in Go
    https://www.doxsey.net/blog/nils-in-go