├── LICENSE.md ├── README.md ├── ctrl ├── doc.go └── engine.go ├── golab-screenshot.png ├── golab.go ├── model ├── const.go ├── doc.go ├── embedded_imgs.go ├── images.go └── lab.go ├── resources ├── bulldog-down.png ├── bulldog-left.png ├── bulldog-right.png ├── bulldog-up.png ├── door.png ├── gopher-dead.png ├── gopher-down.png ├── gopher-left.png ├── gopher-right.png ├── gopher-up.png ├── marker.png ├── source.txt ├── wall.png └── won.png └── view ├── const.go ├── doc.go ├── handlers.go ├── help_html.go └── play_html.go /LICENSE.md: -------------------------------------------------------------------------------- 1 | GoLab LICENSE 2 | === 3 | 4 | Copyright (c) 2015 Andras Belicza. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | - Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | - Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GoLab 2 | === 3 | 4 | _This game is reincarnated in [icza/golab](https://github.com/icza/golab)._ 5 | 6 | 7 | Introduction 8 | --- 9 | 10 | **Gopher's Labyrinth** (or just **GoLab**) is a 2-dimensional Labyrinth game where you control [Gopher](http://golang.org/doc/gopher/frontpage.png) (who else) and your goal is to get to the Exit point of the Labyrinth. But beware of the bloodthirsty _Bulldogs_, the ancient enemies of gophers who are endlessly roaming the Labyrinth! 11 | 12 | Controlling Gopher is very easy: just click with your _left_ mouse button to where you want him to move (but there must be a free straight line to it). You can even queue multiple target points forming a _path_ on which Gopher will move along. If you click with the _right_ mouse button, the path will be cleared. 13 | 14 | GoLab Screenshot 15 | 16 | GoLab is written completely in [Go](http://golang.org/), but there is a thin HTML layer because the User Interface (UI) of the game is an HTML page (web page). GoLab doesn't use any platform dependent or native code, so you can start the application on any platforms supported by a Go compiler (including Windows, Linux and MAC OS-X). Since the UI is a simple HTML page, you can play the game from any browsers on any platforms, even from mobile phones and tablets (no HTML5 capable browser is required). Also the device you play from doesn't need to be the same computer where you start the application, so for example you can start the game on your desktop computer and connect to it and play the game from your smart phone. The solution used (web UI server) provides multi-player support out-of-the-box, although this Labyrinth game doesn't make use of it (the same Gopher can be controlled by all clients). Everything is stored in the (Go) application, you can close the browser and reopen it (even on a different device) and nothing will be lost. 17 | 18 | How to get it or install it 19 | --- 20 | 21 | Of course in the _"Go"_ way using `"go get"`: 22 | 23 | `go get github.com/gophergala/golab` 24 | 25 | The executable binary `golab` (produced by `"go install"`) is _self-contained_: it contains all resources embedded (e.g. images, html templates), nothing else is required for it to run. On startup by default the application opens the UI web page in your default browser. 26 | 27 | Configuration and Tweaking 28 | --- 29 | 30 | GoLab can be configured and tweaked through command line parameters or flags. Execute `golab -h` to see the available command line options and their description. For completeness and for those who didn't install GoLab, here is the output: 31 | 32 | Usage of golab: 33 | -autoOpen=true: Auto-opens the UI web page in the default browser 34 | -bulldogs=10: the number of Bulldogs in an area of 1,000 Blocks; valid range: 0..50 35 | -cols=33: the number of columns in the Labyrinth; must be odd; valid range: 9..99 36 | -loopDelay=50: loop delay of the game engine, in milliseconds; valid range: 10..100 37 | -port=1234: Port to start the UI web server on; valid range: 0..65535 38 | -rows=33: the number of rows in the Labyrinth; must be odd; valid range: 9..99 39 | -v=80: moving speed of Gopher and the Bulldogs in pixel/sec; valid range: 20..200 40 | -viewHeight=700: height of the view image in pixels in the UI web page; valid range: 150..2000 41 | -viewWidth=700: width of the view image in pixels in the UI web page; valid range: 150..2000 42 | 43 | Used Packages 44 | --- 45 | 46 | GoLab uses only the standard library that comes with the Official Go distributions. GoLab doesn't rely on any external or 3rd party libraries. 47 | 48 | Used packages from the standard library and their utilisation: 49 | 50 | - [http/net](http://golang.org/pkg/net/http/) package is used as the UI server 51 | - [image](http://golang.org/pkg/image/) package and its sub-packages ([image/color](http://golang.org/pkg/image/color/) and [image/draw](http://golang.org/pkg/image/draw/)) are used to draw the graphics of GoLab 52 | - [image/png](http://golang.org/pkg/image/png/) is used to read image resources of the game 53 | - [image/jpeg](http://golang.org/pkg/image/jpeg/) is used to generate the view of the game (labyrinth) for HTTP clients (browsers) 54 | - [html/template](http://golang.org/pkg/html/template/) package is used to generate the UI web page 55 | - [encoding/base64](http://golang.org/pkg/encoding/base64/) package is used to generate and decode embedded image resources to/form Base64 strings 56 | - [flag](http://golang.org/pkg/flag/) package is used to enable basic configuration through the command line 57 | 58 | Under the Hood (Implementation) 59 | --- 60 | 61 | **Game Engine / Simulation** 62 | 63 | As mentioned earlier, everything is calculated and stored in the (Go) application. As an architectural pattern, I chose [Model-View-Controller (MVC)](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). Although I did not enforce everything but logically this pattern is followed. 64 | 65 | The `model` package defines the basic types and data structures of the game. The `view` package is responsible for the UI of the game. The UI is a thin HTML layer, it contains an HTML page with some embedded JavaScript. No external JavaScript libraries are used, everything is "self-made". At the GoLab "side" the `net/http` package is used to serve the HTTP clients (browsers). 66 | 67 | The `ctrl` package is the controller or the _engine_ of the game, it implements all the game logic. It runs in an endless loop, and processes events from the UI client(s), performs calculation of moving objects, performs certain checks (like winning and dying) and updates the image / view of the Labyrinth. 68 | 69 | Since there might be multiple goroutines running parallel, communication between the `view` and the `ctrl/model` is done via channels. Also to prevent incomplete/flickering images sent to the clients, the engine performs explicit "model" locking while the next phase of the game is being calculated. 70 | 71 | **Communication between the (Go) application and the browser (UI):** 72 | 73 | - When GoLab is started, it starts an HTTP(web) server. 74 | - Either GoLab auto-opens the UI web page in the default browser (default) or the player manually opens it. 75 | - The UI web page is served by the web server. 76 | - The UI web page presents the view of the game in the form of an HTML image. This image is then periodically refreshed (by JavaScript code). 77 | - Clicks on the view image is detected by JavaScript code and are sent back to the server via AJAX calls. The server processes them. 78 | - Quality is a parameter which is attached to the image urls when the view is requested. 79 | - The FPS parameter is just used at the client side to time image refreshing. 80 | - New Game requests are also sent via AJAX calls. 81 | - The Cheat link opens a new browser tab directed to a URL whose handler sends a snapshot image of the whole Labyrinth. 82 | - The web page constantly monitors the application, and if the application is closed or network error occurs, proper notification/error messages are displayed to the user. The web page automatically "reconnects" if the application becomes available again. 83 | - The web page also automatically detects if the application is restarted, and in this case will reload itself. 84 | 85 | Usefulness 86 | --- 87 | 88 | Since GoLab is a game, its usefulness might be questioned. GoLab's usefulness is that it is an example solution and a reference implementation that you can create portable games or applications with graphics in Go with an implicit portable UI with just using the standard library of Go. GoLab doesn't rely on any external or 3rd party libraries. 89 | 90 | LICENSE 91 | --- 92 | 93 | See [LICENSE](https://github.com/gophergala/golab/blob/master/LICENSE.md) 94 | 95 | GoLab's Gopher is a derivative work based on the Go gopher which was designed by Renee French. ([http://reneefrench.blogspot.com/](http://reneefrench.blogspot.com/)). Licensed under the Creative Commons 3.0 Attributions license. 96 | 97 | The source of other images can be found in the [resources/source.txt](https://github.com/gophergala/golab/blob/master/resources/source.txt) file. 98 | -------------------------------------------------------------------------------- /ctrl/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package ctrl implements the game logic. 3 | This can be thought of as the Controller part of an MVC architecture. 4 | 5 | This package, the engine processes events from the clients (received and forwarded by the view package), 6 | and is responsible to calculate the next phases of the game, move objects, and update the image of the Labyrinth. 7 | */ 8 | package ctrl 9 | -------------------------------------------------------------------------------- /ctrl/engine.go: -------------------------------------------------------------------------------- 1 | package ctrl 2 | 3 | import ( 4 | "github.com/gophergala/golab/model" 5 | "github.com/gophergala/golab/view" 6 | "image" 7 | "image/draw" 8 | "math" 9 | "math/rand" 10 | "time" 11 | ) 12 | 13 | // LoopDelay is the delay between the iterations of the main loop of the game engine, in milliseconds. 14 | var LoopDelay = 50 // ~20 FPS 15 | 16 | // InitNew initializes a new game. 17 | func initNew() { 18 | // Initialize random number generator 19 | rand.Seed(time.Now().Unix()) 20 | 21 | model.InitNew() 22 | view.InitNew() 23 | } 24 | 25 | // StartEngine starts the game engine in a new goroutine and returns as soon as possible. 26 | func StartEngine() { 27 | model.NewGameCh <- 1 // Cannot block as application was just started, no incoming requests processed yet 28 | 29 | model.Mutex.Lock() 30 | 31 | go simulate() 32 | } 33 | 34 | // Delta time since our last iteration 35 | var dt float64 36 | 37 | // simulate implements the game cycle 38 | func simulate() { 39 | t := time.Now().UnixNano() 40 | 41 | for { 42 | // Check if we have to start a new game 43 | select { 44 | case <-model.NewGameCh: 45 | initNew() 46 | default: 47 | } 48 | 49 | // First erase target images. We have to do this before handling mouse clicks 50 | // as they may change the target positions 51 | eraseDrawTargetPoss(true) 52 | 53 | // Process mouse clicks 54 | clickLoop: 55 | for { 56 | select { 57 | case click := <-model.ClickCh: 58 | handleClick(click) 59 | default: 60 | break clickLoop 61 | } 62 | } 63 | 64 | // Next clear moving objects from the lab image: 65 | model.Gopher.EraseImg() 66 | for _, bd := range model.Bulldogs { 67 | bd.EraseImg() 68 | } 69 | 70 | model.DrawImgAt(model.ExitImg, model.ExitPos.X, model.ExitPos.X) 71 | 72 | if !model.Dead { 73 | // Draw target positions 74 | eraseDrawTargetPoss(false) 75 | } 76 | 77 | now := time.Now().UnixNano() 78 | dt = float64(now-t) / 1e9 79 | 80 | // Now step moving objects 81 | 82 | stepGopher() 83 | stepBulldogs() 84 | 85 | // Check if Gopher reached the exit point 86 | if int(model.Gopher.Pos.X) == model.ExitPos.X && int(model.Gopher.Pos.Y) == model.ExitPos.Y { 87 | handleWinning() 88 | } 89 | 90 | t = now 91 | 92 | // Sleep some time. 93 | // Iterations might not be exact, but we don't rely on it: 94 | // We calculate delta time and calculate moving and next positions 95 | // based on the delta time. 96 | 97 | model.Mutex.Unlock() // While sleeping, clients can request view images 98 | if model.Won { 99 | // If won, nothing has to be done, just wait for a new game signal 100 | <-model.NewGameCh // Blocking receive 101 | // Send back value to detect it at the proper place 102 | model.NewGameCh <- 1 103 | } 104 | time.Sleep(time.Millisecond * time.Duration(LoopDelay)) 105 | model.Mutex.Lock() // We will modify model now, labyrinth image might change so lock. 106 | } 107 | } 108 | 109 | // handleClick handles a mouse click 110 | func handleClick(c model.Click) { 111 | if model.Dead { 112 | return 113 | } 114 | 115 | Gopher := model.Gopher 116 | 117 | if c.Btn == model.MouseBtnRight { 118 | model.TargetPoss = model.TargetPoss[0:0] 119 | } 120 | 121 | // If target buffer is full, do nothing: 122 | if len(model.TargetPoss) == cap(model.TargetPoss) { 123 | return 124 | } 125 | 126 | // Last target pos: 127 | var TargetPos image.Point 128 | if len(model.TargetPoss) == 0 { 129 | TargetPos = Gopher.TargetPos 130 | } else { 131 | TargetPos = model.TargetPoss[len(model.TargetPoss)-1] 132 | } 133 | 134 | // Check if new desired target is in the same row/column as the last target and if there is a free passage to there. 135 | pCol, pRow := TargetPos.X/model.BlockSize, TargetPos.Y/model.BlockSize 136 | tCol, tRow := c.X/model.BlockSize, c.Y/model.BlockSize 137 | 138 | // sorted simply returns its parameters in ascendant order: 139 | sorted := func(a, b int) (int, int) { 140 | if a < b { 141 | return a, b 142 | } else { 143 | return b, a 144 | } 145 | } 146 | 147 | if pCol == tCol { // Same column 148 | for row, row2 := sorted(pRow, tRow); row <= row2; row++ { 149 | if model.Lab[row][tCol] == model.BlockWall { 150 | return // Wall in the route 151 | } 152 | } 153 | } else if pRow == tRow { // Same row 154 | for col, col2 := sorted(pCol, tCol); col <= col2; col++ { 155 | if model.Lab[tRow][col] == model.BlockWall { 156 | return // Wall in the route 157 | } 158 | } 159 | } else { 160 | return // Only the same row or column can be commanded 161 | } 162 | 163 | // Target pos is allowed and reachable. 164 | // Use target position rounded to the center of the target block: 165 | model.TargetPoss = append(model.TargetPoss, image.Pt(tCol*model.BlockSize+model.BlockSize/2, tRow*model.BlockSize+model.BlockSize/2)) 166 | } 167 | 168 | // eraseDrawTargetPoss either erases or draws target positions of Gopher, both the current and the buffered ones. 169 | func eraseDrawTargetPoss(erase bool) { 170 | var img image.Image 171 | if erase { 172 | img = model.EmptyImg 173 | } else { 174 | img = model.TargetImg 175 | } 176 | // dtp: drawTargetPos 177 | dtp := func(TargetPos image.Point) { 178 | rect := model.TargetImg.Bounds() 179 | rect = rect.Add(image.Pt(TargetPos.X-rect.Dx()/2, TargetPos.Y-rect.Dy()/2)) 180 | draw.Draw(model.LabImg, rect, img, image.Point{}, draw.Over) 181 | } 182 | 183 | dtp(model.Gopher.TargetPos) 184 | for _, TargetPos := range model.TargetPoss { 185 | dtp(TargetPos) 186 | } 187 | } 188 | 189 | // stepGopher handles moving the Gopher and also handles the multiple target positions of Gopher. 190 | func stepGopher() { 191 | Gopher := model.Gopher 192 | 193 | if model.Dead { 194 | Gopher.DrawWithImg(model.DeadImg) 195 | return 196 | } 197 | 198 | // Check if reached current target position: 199 | if int(Gopher.Pos.X) == Gopher.TargetPos.X && int(Gopher.Pos.Y) == Gopher.TargetPos.Y { 200 | // Check if we have more target positions in our path: 201 | if len(model.TargetPoss) > 0 { 202 | // Set the next target as the current 203 | Gopher.TargetPos = model.TargetPoss[0] 204 | // and remove it from the targets: 205 | model.TargetPoss = model.TargetPoss[:copy(model.TargetPoss, model.TargetPoss[1:])] 206 | } 207 | } 208 | 209 | // Step Gopher 210 | stepMovingObj(Gopher) 211 | } 212 | 213 | // stepBulldogs iterates over all Bulldogs, generates new random target if they reached their current, and steps them. 214 | func stepBulldogs() { 215 | // Gopher's position: 216 | gpos := model.Gopher.Pos 217 | 218 | for _, bd := range model.Bulldogs { 219 | x, y := int(bd.Pos.X), int(bd.Pos.Y) 220 | 221 | if bd.TargetPos.X == x && bd.TargetPos.Y == y { 222 | row, col := y/model.BlockSize, x/model.BlockSize 223 | // Generate new, random target. 224 | // For this we shuffle all the directions, and check them sequentially. 225 | // Firts one in which direction there is a free path wins (such path surely exists). 226 | 227 | // Shuffle the directions slice: 228 | for i := len(directions) - 1; i > 0; i-- { // last is already random, no use switching with itself 229 | r := rand.Intn(i + 1) 230 | directions[i], directions[r] = directions[r], directions[i] 231 | } 232 | 233 | var drow, dcol int 234 | for _, dir := range directions { 235 | switch dir { 236 | case model.DirLeft: 237 | dcol = -1 238 | case model.DirRight: 239 | dcol = 1 240 | case model.DirUp: 241 | drow = -1 242 | case model.DirDown: 243 | drow = 1 244 | } 245 | if model.Lab[row+drow][col+dcol] == model.BlockEmpty { 246 | // Direction is good, check if we can even step 2 bocks in this way: 247 | if model.Lab[row+drow*2][col+dcol*2] == model.BlockEmpty { 248 | drow *= 2 249 | dcol *= 2 250 | } 251 | break 252 | } 253 | drow, dcol = 0, 0 254 | } 255 | 256 | bd.TargetPos.X += dcol * model.BlockSize 257 | bd.TargetPos.Y += drow * model.BlockSize 258 | } 259 | 260 | stepMovingObj(bd) 261 | 262 | if !model.Dead { 263 | // Check if this Bulldog reached Gopher 264 | if math.Abs(gpos.X-bd.Pos.X) < model.BlockSize*0.75 && math.Abs(gpos.Y-bd.Pos.Y) < model.BlockSize*0.75 { 265 | handleDying() 266 | } 267 | } 268 | } 269 | } 270 | 271 | // handleDying handles the death of Gopher event. 272 | func handleDying() { 273 | model.Dead = true 274 | } 275 | 276 | // handleWinning handles the winning of game event. 277 | func handleWinning() { 278 | model.Won = true 279 | 280 | r := model.WonImg.Bounds() 281 | r = r.Add(image.Point{view.Pos.X + view.ViewWidth/2 - r.Dx()/2, view.Pos.Y + view.ViewHeight/2 - r.Dy()/2}) 282 | draw.Draw(model.LabImg, r, model.WonImg, image.Point{}, draw.Over) 283 | } 284 | 285 | // stepMovingObj steps the specified MovingObj and draws its image to its new position onto the LabImg. 286 | func stepMovingObj(m *model.MovingObj) { 287 | x, y := int(m.Pos.X), int(m.Pos.Y) 288 | 289 | // Only horizontal or vertical movement is allowed! 290 | if x != m.TargetPos.X { 291 | dx := math.Min(dt*model.V, math.Abs(float64(m.TargetPos.X)-m.Pos.X)) 292 | if x > m.TargetPos.X { 293 | dx = -dx 294 | m.Direction = model.DirLeft 295 | } else { 296 | m.Direction = model.DirRight 297 | } 298 | m.Pos.X += dx 299 | } else if y != m.TargetPos.Y { 300 | dy := math.Min(dt*model.V, math.Abs(float64(m.TargetPos.Y)-m.Pos.Y)) 301 | if y > m.TargetPos.Y { 302 | dy = -dy 303 | m.Direction = model.DirUp 304 | } else { 305 | m.Direction = model.DirDown 306 | } 307 | m.Pos.Y += dy 308 | } 309 | 310 | // Draw image at new position 311 | m.DrawImg() 312 | } 313 | 314 | // directions is a reused slice of all directions 315 | var directions = make([]model.Dir, model.DirLength) 316 | 317 | func init() { 318 | // Populate the directions slice 319 | for i := model.Dir(0); i < model.DirLength; i++ { 320 | directions[i] = i 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /golab-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/golab-screenshot.png -------------------------------------------------------------------------------- /golab.go: -------------------------------------------------------------------------------- 1 | // Package main of GoLab is the main package defining the entry point 2 | // and which compiles into the GoLab executable. 3 | // 4 | // Home page: https://github.com/gophergala/golab 5 | package main 6 | 7 | import ( 8 | "flag" 9 | "fmt" 10 | "github.com/gophergala/golab/ctrl" 11 | "github.com/gophergala/golab/model" 12 | "github.com/gophergala/golab/view" 13 | "log" 14 | "net/http" 15 | "os/exec" 16 | "runtime" 17 | ) 18 | 19 | // port tells on which port to open the UI web server 20 | var port int 21 | 22 | // autoOpen tells if the UI web page should be auto-opened in the users's default browser 23 | var autoOpen bool 24 | 25 | // processFlags registers flags, parses them and validates them. 26 | // Returns nil if everything is ok, else an error. 27 | func processFlags() error { 28 | 29 | // General flags 30 | flag.IntVar(&port, "port", 1234, "Port to start the UI web server on; valid range: 0..65535") 31 | flag.BoolVar(&autoOpen, "autoOpen", true, "Auto-opens the UI web page in the default browser") 32 | 33 | // Model package flags 34 | flag.IntVar(&model.Rows, "rows", 33, "the number of rows in the Labyrinth; must be odd; valid range: 9..99") 35 | flag.IntVar(&model.Cols, "cols", 33, "the number of columns in the Labyrinth; must be odd; valid range: 9..99") 36 | flag.Float64Var(&model.BulldogDensity, "bulldogs", 10, "the number of Bulldogs in an area of 1,000 Blocks; valid range: 0..50") 37 | 38 | // Control/Engine flags 39 | flag.IntVar(&ctrl.LoopDelay, "loopDelay", 50, "loop delay of the game engine, in milliseconds; valid range: 10..100") 40 | flag.Float64Var(&model.V, "v", model.BlockSize*2.0, "moving speed of Gopher and the Bulldogs in pixel/sec; valid range: 20..200") 41 | 42 | // View package flags 43 | flag.IntVar(&view.ViewWidth, "viewWidth", 700, "width of the view image in pixels in the UI web page; valid range: 150..2000") 44 | flag.IntVar(&view.ViewHeight, "viewHeight", 700, "height of the view image in pixels in the UI web page; valid range: 150..2000") 45 | 46 | flag.Parse() 47 | 48 | if port < 0 || port > 65535 { 49 | return fmt.Errorf("port %d is outside of valid range", port) 50 | } 51 | 52 | if model.Rows < 9 || model.Rows > 99 { 53 | return fmt.Errorf("rows %d is outside of valid range", model.Rows) 54 | } 55 | 56 | if model.Cols < 9 || model.Cols > 99 { 57 | return fmt.Errorf("cols %d is outside of valid range", model.Cols) 58 | } 59 | 60 | if model.Rows&0x01 == 0 { 61 | return fmt.Errorf("rows %d must be odd", model.Rows) 62 | } 63 | 64 | if model.Cols&0x01 == 0 { 65 | return fmt.Errorf("cols %d must be odd", model.Cols) 66 | } 67 | 68 | model.LabWidth = model.Cols * model.BlockSize 69 | model.LabHeight = model.Rows * model.BlockSize 70 | 71 | if ctrl.LoopDelay < 10 || ctrl.LoopDelay > 100 { 72 | return fmt.Errorf("loopDelay %d is outside of valid range", ctrl.LoopDelay) 73 | } 74 | 75 | if model.V < 20 || model.V > 200 { 76 | return fmt.Errorf("v %f is outside of valid range", model.V) 77 | } 78 | 79 | if view.ViewWidth < 150 || view.ViewWidth > 2000 { 80 | return fmt.Errorf("viewWidth %d is outside of valid range", view.ViewWidth) 81 | } 82 | 83 | if view.ViewHeight < 150 || view.ViewHeight > 2000 { 84 | return fmt.Errorf("viewHeight %d is outside of valid range", view.ViewHeight) 85 | } 86 | 87 | if model.BulldogDensity < 0 || model.BulldogDensity > 50 { 88 | return fmt.Errorf("bulldogs %f is outside of valid range", model.BulldogDensity) 89 | } 90 | 91 | if view.ViewWidth > model.LabWidth { 92 | fmt.Printf("Warning: viewWidth is trimmed to cols * %d = %d\n", model.BlockSize, model.LabWidth) 93 | view.ViewWidth = model.LabWidth 94 | } 95 | 96 | if view.ViewHeight > model.LabHeight { 97 | fmt.Printf("Warning: viewHeight is trimmed to rows * %d = %d\n", model.BlockSize, model.LabHeight) 98 | view.ViewHeight = model.LabHeight 99 | } 100 | 101 | return nil 102 | } 103 | 104 | // main is the entry point of GoLab. 105 | // Processes the command line flags, initializes the game engine 106 | // and starts the UI webserver. 107 | func main() { 108 | runtime.GOMAXPROCS(runtime.NumCPU()) 109 | 110 | if err := processFlags(); err != nil { 111 | fmt.Println(err) 112 | flag.Usage() 113 | return 114 | } 115 | 116 | ctrl.StartEngine() 117 | 118 | fmt.Printf("Starting GoLab webserver on port %d...\n", port) 119 | url := fmt.Sprintf("http://localhost:%d/", port) 120 | if autoOpen { 121 | fmt.Printf("Opening %s...\n", url) 122 | if err := open(url); err != nil { 123 | fmt.Println("Auto-open failed:", err) 124 | fmt.Printf("Open %s in your browser.\n", url) 125 | } 126 | } else { 127 | fmt.Printf("Auto-open not enabled, open %s in your browser.\n", url) 128 | } 129 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) 130 | } 131 | 132 | // open opens the specified URL in the default browser of the user. 133 | func open(url string) error { 134 | var cmd string 135 | var args []string 136 | 137 | switch runtime.GOOS { 138 | case "windows": 139 | cmd = "cmd" 140 | args = []string{"/c", "start"} 141 | case "darwin": 142 | cmd = "open" 143 | default: // "linux", "freebsd", "openbsd", "netbsd" 144 | cmd = "xdg-open" 145 | } 146 | args = append(args, url) 147 | 148 | return exec.Command(cmd, args...).Start() 149 | } 150 | -------------------------------------------------------------------------------- /model/const.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | // BlockSize is the size of the labyrinth unit in pixels. 5 | BlockSize = 40 6 | ) 7 | 8 | var ( 9 | // Rows is the number of rows in the Labyrinth 10 | Rows int 11 | // Cols is the number of columns in the Labyrinth 12 | Cols int 13 | 14 | // LabWidth is the width of the labyrinth's image in pixels. 15 | LabWidth int 16 | 17 | // LabHeight is the height of the labyrinth's image in pixels. 18 | LabHeight int 19 | ) 20 | 21 | // V is the moving speed of Gopher and the Buddlogs in pixel/sec. 22 | var V float64 23 | 24 | // "Bulldog density", it tells how many Bulldogs to generate for average of 1,000 blocks. 25 | // For example if this is 10.0 and rows*cols = 21*21 = 441, 10.0*441/1000 = 4.41 => 4 Bulldogs will be generated. 26 | var BulldogDensity float64 27 | 28 | // Type of the unit of the labyrinth 29 | type Block int 30 | 31 | // Block types of the labyrinth 32 | const ( 33 | // Empty block (free passage) 34 | BlockEmpty Block = iota 35 | // Wall block 36 | BlockWall 37 | ) 38 | 39 | type Dir int 40 | 41 | // Directions of Gopher (facing directions) 42 | const ( 43 | DirRight Dir = iota 44 | DirLeft 45 | DirUp 46 | DirDown 47 | 48 | // Not a valid direction: just to tell how many directions are there 49 | DirLength 50 | ) 51 | 52 | func (d Dir) String() string { 53 | switch d { 54 | case DirRight: 55 | return "right" 56 | case DirLeft: 57 | return "left" 58 | case DirUp: 59 | return "up" 60 | case DirDown: 61 | return "down" 62 | } 63 | return "" 64 | } 65 | -------------------------------------------------------------------------------- /model/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package model defines the basic types and data structures of the game. 3 | This can be thought of as the Model part of an MVC architecture. 4 | 5 | It is "shared", used by the view and ctrl packages. 6 | */ 7 | package model 8 | -------------------------------------------------------------------------------- /model/embedded_imgs.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Embedded images mapped from image (file) name to file content encoded in Base64 format. 4 | // Whether these will be used depends on the useEmbeddedImages const in images.go. 5 | var base64Imgs = map[string]string{ 6 | "gopher-right.png": "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", 7 | "bulldog-right.png": "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", 8 | "gopher-left.png": "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAGw0lEQVRYw7WYa1RU1xXH//c5b4YBeQykCkLlIQhWKEWNWusjLtvaZNVUJBpM0yxr0pDSR1pj2q64TJemTTW1aboSiVlJmmqS1kdXsD5iBHRhfARjoyJBZhy5MjA4MzBz53nP6QdtG5YCM4N3fz3/s+9v9tl7nz2HQYLGieKUinUN0wW9rlqXMqFMNJryOVFjBQBKFL8SDvWGvJ7OoMfd5vy0vfnzpn2tAEi832Hi1WdXzSzP/cZ9h0tr16RwogiiKACld3RNyM01XquF7chBtGx6dqn3andT0QPfM1jyCvjzbzcGh6RrwfEATpv19K/fEU1JSe07Xt5QUrvmB1NXrJ4lXfgMesmOMFGgmfE1pGRYQb8AyWm1uLF3Nx4qL0ZuTg6OtLSixZIFS24+Wjdt6Pnqkz9PYwVBDAwMDL21qHoGgM64AQWtbl5NU/PRtKISREMh2I4eQnJxKea57Fg+swoGsxkAIDkceL7pCMjcxWAoBSUEsx0XsXLxwmH+JIcD9cc/gbVyJj59ewdYXsDUB1fh+pmT9P0V3zICkOM6yqV/fuPq2vM2yuv0tKRmNX2iy0Vf3NdER7JHDzTTxy/30tU7/0b9Ph/t6Oi4TbO3+Thdd7GH1tvd1JiZRZ9yDNLHO67T3IVLikcCYUcCNE/KYUkkAqoomPubzYgQgjnWVJjNZuTn59+2ITMwBPACpkVkFBYVoaCgAG1tbcM0RbmTAIZBRJax6A+vQAmHEA0E0H2oyRMvIPlw/Y9fEgwmLNzyEighoACuXL6MwcFB1NfXw+l0Dt+hKGAYBu5wCBqNBjk5ORBFcbjkC7WkTbZAOtWG/Y89dD8AaSRAfqSF3vazW/Y/WnOpZMWqvQAgMADNnoRdu3aBZVlkZGQM0w8kpUAj8HCWVqHj0iXY7HZMnjx5mGbbgcNg772Zm6kFxXh1et76oNezZ9R2Ntqi96otPG/jC/WcIAKE4JzkxKqKMsyqrv6fZtDjwU//0gi7HMae2u+g68i/0OryYMFXysFGIwgFAnB6B/Hsrr+DX7QMJBq5mUMsAzAQHcebXx+NgR9t0ZL35UJtsgVKOAwASJ5SiM3eMNy/+yOKTXpIcgD+0gpwhWU4WfcAhnr74JOugZ1Tja0yj+gNL6gShWg0AbMXgAT+X6hUUZA5vTLrViehCQGml5Zn3BZyQcSEby+H89bmJNmHXw4dxu/3boLT5YVRr0VWmhlvnngDp7/+GJhw6I6+KSFIumeiQWNKYkJDgzTeIgEAiEaT7s4lRMAQAhACMAxs0gBskhs9Xh6ukB52Rx8QCY8SF/z3mLXWiiom4SOmRBnz7mQ0OrxZuQ6/4n3gbwygvLwc393xDtLm14KNhMbaLRgzrUgYMOj1+GPp6oIShicaQN+t1qPheXDMmAEEAF4wGBIH9HR3uWO6dxQFfxqQEdBnYP9Hp2CuqAJVlJhuLE4QEwd0Xfh3f6wDD5uaDsOteSqOEYlhWG50v2M46At63VDNGDBgGWZcgD7pGtQ0hmHHFUFZ7u9TE49NzsmjiQJmPHlfSVXI71czgOxcqWVNdoalLC7A4vx7ZnQe2tq7bfuGtnBUUY2OgEFD3ZJXLx/c2r5kbnlDzIATUpLWppiNOH36IhhRoxogL4p47d2jEHgOwWDEGvM0Y+/pP2jQaewrf/Zy3fTauqeN1ix1MpBSbKypm9lp7939z6Nn3wIQjvdPU+rqDz92Ga3ZqgBSQvBaZeGDEdn/bqJVnGZSCQ4AWJ4Hy3Fp42kzqawoqtoHDemZpoQB06aWWaCyMTzHJgxoSE/Tqw0YdN+QEwbkeIFTE45Eowj7fFLCgEGvN6gmYDQQAK/VnksYsOfjE/0Mw6gHGAqShVu2d42niju8V23qHXEk4jq28Rk6HsD+aydP+FTpgYKAzz/Y0+m1XyHjAcTAxc+eUwPQ39eL41s2/nDMHzKW4NK+93b6rkvAXcxFlufhaD12DMD5u/LCaszMemTlgdYdvOYuTDYMA1fHBbJ72YIvjfZoFHMEAcDXKzW219eeDQVD42NjOVz/5AxyP9juBuCMZU8sjVj3/vaG9s1PLCvLtp3CmfNd4PNLwLAsKIntTZzTaOC1d0Paue1K4706yzfnV+jzJ2bO/8ehU6+POTOOJfjtT2oqeY6bqhAKkUblwL6dv2h8qqF73nMvPJIypXAGJ2om6lInQJtkBisIoJQgIssIDLgQ8fuCEVm+YPvo8LEzr2zbDMD5Xsb3z61YOmtav3tw9t3K6eStzzzs+euLP/ICSB9BkwdgMYDlAJYBqAKgHcnh+rX3t8ypLHo4lo//B55rzuqdnhrKAAAAAElFTkSuQmCC", 9 | "bulldog-left.png": "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", 10 | "gopher-up.png": "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEdklEQVRYw7XYfUxVZRwH8O95vRfuC3B5vYAEg4wQBQJDxQ1WyWTVWi0twDVgy96WW2zmRlSbzLasLS3nXKFzjVbD2sxaODReAs0UBSQhAkQQLpc34cLl3nNfzjn9of3nvdx7Ds/33/PcPZ8993l+5/ccCgrD8Pz6vLerc7jQkK0hpqgsXm9IY3iNGQBkSVwR3S6ry7Y4JCwuXJm+2fPHcNO5TgBSsPNQwY5PyN+WnfL0zosbyytNDMdDkkRAln3/gKZBMyxGfz+PjkMfPWsbH216/KVXdBGpj7F9350Sli0TghrgpoIDH3/PG4zGnpPHazPLK1/PeLmsgNFq/aIePhMF2etF5ycfTj657/1omuN45/z8ckPx1lwAQ0EDOW1IUWlTR6txXRJomsFYRwuSCgohejxQE4bjcauxARt274EkemHt7pJ/evV5PQDHw8bTvuDFX5z41pi4DpLbjd7TXyNxy3bVOAAQPW5k7CrDaGszZElCXE4elbKjJNnXeJ/AsEeSaVkUsWyZRGZ5BWRJwlpF8nrBh+rA8Bp4nU6MXmhaDBYotdS89yUoCrP9N9cU93+0pkhYrv2JX/bueRGAxeeW8PXAbp26NN17ozt2U3ZpeEramgN1sWb88FxRzcLtoXp/42h/D8c7WvsStmwHiciSiCfeeLdktXF+gRGpj6ZrwyPIAEURcTmb41crdX6BMRuzY0EosiTBmJik0xiMyoG83hACgqFoSmvOy1cOlCVRAtFQnD7OrHwPCrbFFbJAsJxOpxy4ODqyQBhIMRyvHDjX//ds8A1PkC0EzSgHApgRbAQXkQIFmqJUAe2WCRBeQlUr6HDMzhAtNOHJqbJSYOy+nZn5rhWiB5kutHRUJsRGZAUFzEhLzB26cMR69FjtFbdXJKaTQKG6ouSbf5uP9JQUZlcHDIwyGd80henR1TUAiteQK4I8j/ozreBYBoLgMQfcbo1NzjbrQjRjZfuPV+SUVxzQm+PJ7EBZRl1pxbahMWvjr603GgC4g700Rb7WcnVOb04g1jDUb07f7XGsnFF6iqMNhHAAQLMsaIaJVlNmImmeJ1oHdTFxBsXA6A1ZESAcimVoxUBdTHQoaaCwcM+hGMiwHEMSJ3m9cNvtFhX9oE0gCfQ6nWC12l7FwMmrl2cpily75XUJ0o7Dx0bUnOJB2/gdcn+xxzPXXveBrAY4O/HXZTuRGshxGP7t7JBt7LakBoj5gVsHSQBXZqy4dLjuLVUXdwD459yPp+1TFmAN9yLNsrjb2d4OoG/1pjuA6OPiq8rOd55kNWvQ2VAU5gb75cYXnkn099Eo4BW8/yHJcqrrndJrLpdbZf/MYKr7OoSvatoDwQUMBIC9xZlh++81wdt29v5LnmUDhjEaDZYmxjH4ee3oIcMA9Fru58DvVYEnvGrXU7XC0tLdxra+kaKDn1WZ1qfnMrwmKSQyClpjGGiOgyxL8DgccM7PwbNiFzwOR/+dtovt108c/RTANIA0AMMkgP6S+mBi44Om0wqgF4DqN9F/rNaaIny43Z0AAAAASUVORK5CYII=", 11 | "bulldog-up.png": "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", 12 | "gopher-down.png": "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", 13 | "bulldog-down.png": "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAID0lEQVRYw82Ya4xdVRXHf+uce1733rkzd3pnpo9p6VsKQjVFqGLTEAVfSCBCFKyxYhCVD4rRRCRIouIHPhAfUTAijRGJaGPQIBFUgjRgESm2pRRaC9N22pnpvO773vPayw+3H3wgUD1Vd3I+nJP93+d//v+11l77CBmNu69Zl9u8JC7XvdGR52Y4/NG7Hmtksa6VFcGz83PXFuLpE5UTv9/bmXhxS1brZkLwti98bkkcNj4eJzVSx0oGAhnNiqD8J+Btn3rHcntq9535tLrJs1IfsPMOxKlELQ1erueXf/lj9+776f+E4H3XbzynPvbnJzXtFn1b8HPgWBAZMAZEevdpYdEtV99//Gv/VYsfvfXy/s743u+aJCyWPKHsQyWAsq8MBzCUBz8H1RCGzORXH71uxQf+XYL2qQIeuesruUM7tt+ThvX3VgIo5mDAh3IAri0M+uDloOT25isWC3Kdt73v/LU7f7Jrevy0W/zDDy2/qT1z5OtFRyk6UPaFRAGF1CjjLcG1YLRPWDusLHCVpoGX6/3PzUTuxvfce6J1Ku/LvZ5J+q0N5af2n7j0aNNaarenby7mFS8HrkCYKov6hHYMSSJsGFYKrtCOlSQS7IJSGgC/VXtj01lzMZx4IFOC11x+lUxNPr71goUzd5zfTTk6K7RToS8H/QWhFSmduGfFYPnvvWlGhumGUG/BgRosGqldCzyQaZLccG59cOeh9tYdU4XnY9c2pbwwXFBKA0quaBgaVJYtVN6wRlk8qiwehpGCsmJACVPYPaXYiSCRUrGr77/qk98sZZokFy3Rj5xZqG7tRBb9+bjoRIgj4FuQU5CkF385czKiU1ABI9DvwzPHhXYs9PsQhimDjWenfvF886nMFAyimc+WC+T6pDvSmUWaIbRCiNMe2BgggXYL5qcAB8QDy+59/dtHlSM1JYyUo/N2e2Ux3ZqZxTdd/pYLl/Z11j12MNZ629CIhMm2ktjgFCCxBFzQPshXoDzSI2gFiu0qngXdGFwLjjVhwgz+aJrKJ+6/eUtfJkmSdqrpeLGyfYE3ceWxuoVnGWwRbBQ7BvEVgr8pWD4Q0/NYoSHCsqVwpAFjNbBdSldu2/807M9GwdsfPrgzicyhkgcGmO1YzHfBtoV2Tjg0J4zPW+BDEgskYMLeqsc7ws/3WXxjB0x3hcVFoZDUrlZVK9MsLjjm3YmBalcp+9BNlZmuEPigiXBiQpmfFqZmhZlJodUU5ieFsXHhwYOGozU4bwXMdCCQiDuuu2R9pnXQjhrnNmOh5EHgKPkE+ovK1BTYquQEpAtDecXNKSaBsAsr++CWCy0G+5R9xwyzHeHMQeWlYy+8E3g2MwXjOBYAozDdVvI2dFqgIhxvCaPDMB9ClCrqguRBXGGmA8OBMldTogTWlnsNhSvxeZlarF6RkqfMhzDfgUYMOaPUGsqqspIaiDsw3xI0AtOGsKUUXTgwqyzJg0EYLUHBAbEsP1OC3TA57gh4ljDVgfEGVCNwLGXAhnpTGB0CT5SWCHYZvKLQiJQ1/bBrUjhrAawsQ6oQpbI7WwUtqx4b2DSqlD1hqg2Ha0Jq4NlJYWHBkEsUUiFuCHQhTcGxBAul6Bl2TUEjhHoodFP7YKYEQ5ObcG3oJlDylEFfsAQmmkI3MQC4OagUlIF+Ax7k+5UFfcp0F2wLPFtpR8pES6kEOpqtgsWFtzUShwEP1AjDeUVVqUW97lkSMDFIDiwH1PQKdSmAqXZvzx4qgOP0LPZGz3ko2zLTmnliyvi/TGuNyxIVatHJbLRBAVugGUEcCuVYaSOEBoiFUtEiigxGlVakFPuHD374Ow9lG4MPRxdEqVpP2pZF2YdBTxjwBccWVEEVYu3Zro4SeAZPDXMNpdlUYoVqRzhSE5rBoi+dagf/mgre+6sHzbuuGnlmRX+7tTBICvUQapEw0+1tf2EqybwOPPSX2Tg3UJONSWriRursspPuKiFc6yAMehB4Sn+J6mk51e1deMUfDre8Hc0IHFtxLaUWWqab2Mx1BXvxm2+7Z59ccaQbrB7rBGduvm/u0r1z7DEK5yxVNp5tWD2sDFqNzZkrCHD7t+9qVS5beXefNbZ5zQBByQPPsZuHC+svdhYNmA03P/IngJ/trUcAW8A6o+wGebuLb/XOyIENpe7sWaeFIMC6Ed8uxpYETkpsoORRSmb/eGDD9//ZNvkxsj0NrcADTXuZbgEvVJ3p02Lx4zesX70sHfvi8kXG94tg20qlL9i/bMky84qALZK21H8pNKKqvUdHqzDOwh2ZK7j/+sFCnrHtlaHOet8XyIOJhJla7re75YwOHHlFnCkt3pOEjdiy1E1iqCdBOsLcbzJX0Awt39zv1NcHzsmWJoRqC+qh2Xv9D3bE/wp39PjUZF9OU0TRFCp5e+doIW1nTnB40KnUrWIDD7oqaArN2DtyWBc98ao43ywreNg4glMA45HEJjaZE4wbM9v9Yt+LnbbQ7bg0ImEm7r/ruvv2Pf9quMpgWW1LEA/IQ7WZvHVPvGo48xgslwqdVux9sNopvymXz8/X6rXlm7Yd2PZauN+NcWDdKk3adVw3glwYuvW5458BbsyUYHDjHgVeOnm97rHUr18UGfwDk1D2es3qpgXVT58qwcz+Uf/jWFMKVywewRopCgtKELiwptJ2b/38jef+XxAcKBWfy7kWc21FfaWmLrPWwu+tueSGF07LTnKqIxhee2fHH3p6wpo7q2zZQ+6yJb+upn1Pb7lkdXQq6/wVaJqjDyP5bWIAAAAASUVORK5CYII=", 14 | "wall.png": "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAABG0lEQVRYw+3Xva5EQBwF8EMYIgqtB+AFNqLUexS111OIRkJLKZFoJQoRJj62sDfXtZtbjdXMaRDJ/PKfjMQBbooAIAgC3/cNw5im6WpP1/UkScIwlAAYhmFZlm3b35xYBFBVVRRFcRwPw/AFsu97ABIARVHats2yDIDruoSQdV2Ze5Ik/XncL7Is932fpikA5vC6roSQx+NxtKXja0oppXS/Zwt/2IDf8y0I4k/YH6W3NcW7vmMOc5jDHOYwhznMYQ5zmMMMqtT7L/9FTeK07Bm+rjtRSlVV/QCLojjPc57nzMfd2yIAx3E0TftvYrbZtm1Zlr1/e56nKMoLJoQcN+GijONYlqVpml3XveC6ri+a9ZSiKJqm2eHb8gQldHKbOjeEqgAAAABJRU5ErkJggg==", 15 | "gopher-dead.png": "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", 16 | "door.png": "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", 17 | "marker.png": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACL0lEQVQ4y32ST0gVQRzHPzu7+54+s+wPmWnQRahOQV0KikKqQxHUpboU0SWyg0QEXoQiuhRG6EWwTkEQJEQkiRfBoKA6aUQGgYWapD3T3bc7M7szHXoPHq+1HwwMM7/Ph+/8ccio4dkzu7fW7+9W5vceg7F1TtP7b+Ho7ZPbXn6s7XVqF0ZnL3QL4d0JzA/yXhPGaOJkgUbRhrGm61jr4werCoamO446DiOOcKnPNdO0thWdBiwtzxDrBRzjonR68Fz7+HiFEdWCWC/fl2YJMEy+nafz8BBdR0aY+lAEDLEpotKgt5qpEQS7rEkJgxK9lz6xPJ8SLAj6r8yglCRNDZEO9lYzXmVy702LJ7XCdQVzn1fI5328XA7f9/FcwdxXxbo2jdaazATX980lSus4lpKWnZZCYz2+7+Pncqzf1MCG7QqpJFLrNDMBgJTqobV0Jibl6qNmJp5vwc+57DgxTRDGSKVRSj1d9RVujW1s8Fw38H0P1xUIYbBYTOKSpAlKJSSp3XyzY/Fn5iX2HFoMY6muhVFMqRQThppSqAmjiDCSxEp1VsOZHwngxnBhyhWi3XEcrLUYazDGvr57PDpQ2+tlCSIpTwMTFbvBMvnKnhUudSZFA6a8ZUWWoO9UOunAC5y/GeMlp39swCYmpQEoALlK+kwBgFxxLvueh+d6dvBi2gesKcP5am5VwcD5ZNYV7pPidzEI1AES+FUeUeUYHv+puCh63j2TBeBLGfqn/gA1mwntfiET+gAAAABJRU5ErkJggg==", 18 | "won.png": "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"} 19 | -------------------------------------------------------------------------------- /model/images.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "fmt" 7 | "image" 8 | "image/color" 9 | "image/draw" 10 | "image/png" 11 | "io/ioutil" 12 | ) 13 | 14 | // Tells if the embedded images are to be used. If false, images from files will be loaded. 15 | const useEmbeddedImages = true 16 | 17 | // Image of the labyrinth 18 | var LabImg *image.RGBA 19 | 20 | // Gopher images for each direction, each has zero Min point 21 | var GopherImgs []*image.RGBA = make([]*image.RGBA, DirLength) 22 | 23 | // Dead Gopher image. 24 | var DeadImg *image.RGBA 25 | 26 | // Bulldog images for each direction, each has zero Min point 27 | var BulldogImgs []*image.RGBA = make([]*image.RGBA, DirLength) 28 | 29 | // Image of the wall block 30 | //var WallImg = image.NewUniform(WallCol) 31 | var WallImg *image.RGBA 32 | 33 | // Image of the empty block 34 | var EmptyImg = image.NewUniform(color.RGBA{A: 0xff}) 35 | 36 | // Image of the empty block 37 | var TargetImg *image.RGBA 38 | 39 | // Image of a door, this is the exit sign 40 | var ExitImg *image.RGBA 41 | 42 | // Image of a congratulation 43 | var WonImg *image.RGBA 44 | 45 | func init() { 46 | for i := Dir(0); i < DirLength; i++ { 47 | // Load Gopher images 48 | GopherImgs[i] = loadImg(fmt.Sprintf("gopher-%s.png", i), true) 49 | // Load Bulldog images 50 | BulldogImgs[i] = loadImg(fmt.Sprintf("bulldog-%s.png", i), true) 51 | } 52 | 53 | WallImg = loadImg("wall.png", true) 54 | DeadImg = loadImg("gopher-dead.png", true) 55 | ExitImg = loadImg("door.png", true) 56 | 57 | TargetImg = loadImg("marker.png", false) 58 | WonImg = loadImg("won.png", false) 59 | } 60 | 61 | // loadImg loads a PNG image from the specified file, and converts it to image.RGBA and makes sure image has zero Min point. 62 | // This function only used during development as the result contains the images embedded. 63 | // blockSize tells if the image must be of the size of a block (else panics). 64 | func loadImg(name string, blockSize bool) *image.RGBA { 65 | var data []byte 66 | var err error 67 | 68 | if useEmbeddedImages { 69 | data, err = base64.StdEncoding.DecodeString(base64Imgs[name]) 70 | } else { 71 | data, err = ioutil.ReadFile(name) 72 | } 73 | if err != nil { 74 | panic(err) 75 | } 76 | return decodeImg(data, blockSize) 77 | } 78 | 79 | // decodeImg decodes an image from the specified data which must be of PNG format. 80 | // blockSize tells if the image must be of the size of a block (else panics). 81 | func decodeImg(data []byte, blockSize bool) *image.RGBA { 82 | src, err := png.Decode(bytes.NewBuffer(data)) 83 | if err != nil { 84 | panic(err) 85 | } 86 | 87 | // Convert to image.RGBA, also make sure result image has zero Min point 88 | b := src.Bounds() 89 | if blockSize && (b.Dx() != BlockSize || b.Dy() != BlockSize) { 90 | panic("Invalid image size!") 91 | } 92 | 93 | img := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) 94 | draw.Draw(img, src.Bounds(), src, b.Min, draw.Src) 95 | 96 | return img 97 | } 98 | 99 | // printBase64Imgs prints the Base64 encoded strings of the images. 100 | // The printed text is a valid go source format created a map with file names mapped to their base64 encoded contents. 101 | // Used only during development to include those Base64 strings here in the source file 102 | // in order to embed them in the executable native binary. 103 | func printBase64Imgs() { 104 | var names []string 105 | for i := Dir(0); i < DirLength; i++ { 106 | // Gopher images 107 | names = append(names, fmt.Sprintf("gopher-%s.png", i)) 108 | // Bulldog images 109 | names = append(names, fmt.Sprintf("bulldog-%s.png", i)) 110 | } 111 | 112 | names = append(names, "wall.png") 113 | names = append(names, "gopher-dead.png") 114 | names = append(names, "door.png") 115 | names = append(names, "marker.png") 116 | names = append(names, "won.png") 117 | 118 | // Generate output 119 | fmt.Print("var base64Imgs = map[string]string{") 120 | for i, name := range names { 121 | data, err := ioutil.ReadFile(name) 122 | if err != nil { 123 | panic(err) 124 | } 125 | 126 | if i > 0 { 127 | fmt.Print(",") 128 | } 129 | 130 | fmt.Printf("\n\t\"%s\": \"%s\"", name, base64.StdEncoding.EncodeToString(data)) 131 | } 132 | fmt.Print("}") 133 | } 134 | -------------------------------------------------------------------------------- /model/lab.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "image" 5 | "image/draw" 6 | "math/rand" 7 | "sync" 8 | ) 9 | 10 | // Mutex to be used to synchronize model modifications 11 | var Mutex sync.Mutex 12 | 13 | // The model/data of the labyrinth 14 | var Lab [][]Block 15 | 16 | // MovingObj is a struct describing a moving object. 17 | type MovingObj struct { 18 | // The position in the labyrinth in pixel coordinates 19 | Pos struct { 20 | X, Y float64 21 | } 22 | 23 | // Direction where the object is facing toward 24 | Direction Dir 25 | 26 | // Target position the object is moving to 27 | TargetPos image.Point 28 | 29 | // Images for each direction, each has zero Min point 30 | Imgs []*image.RGBA 31 | } 32 | 33 | // DrawImg draws the image of the MovingObj to the LabImg. 34 | func (m *MovingObj) DrawImg() { 35 | m.DrawWithImg(m.Imgs[m.Direction]) 36 | } 37 | 38 | // EraseImg erases the image of the MovingObj from the LabImg by drawing empty block to it. 39 | func (m *MovingObj) EraseImg() { 40 | m.DrawWithImg(EmptyImg) 41 | } 42 | 43 | // DrawWithImage draws the specified image at the position of the moving object onto the LabImg. 44 | func (m *MovingObj) DrawWithImg(img image.Image) { 45 | DrawImgAt(img, int(m.Pos.X), int(m.Pos.Y)) 46 | } 47 | 48 | // DrawImgAt draws the specified image at the specified position which specifies the center of the area to draw. 49 | // The size of the image draw is the block size. 50 | func DrawImgAt(img image.Image, x, y int) { 51 | r := image.Rect(0, 0, BlockSize, BlockSize).Add(image.Point{x - BlockSize/2, y - BlockSize/2}) 52 | draw.Draw(LabImg, r, img, image.Point{}, draw.Over) 53 | } 54 | 55 | // Gopher is our hero, the moving object the user can control. 56 | var Gopher = new(MovingObj) 57 | 58 | // Dead tells if Gopher died 59 | var Dead bool 60 | 61 | // Tells if we won 62 | var Won bool 63 | 64 | // For Gopher we maintain multiple target positions which define a path on which Gopher will move along 65 | var TargetPoss = make([]image.Point, 0, 20) 66 | 67 | // Slice of Bulldogs, the ancient enemy of Gophers. 68 | var Bulldogs []*MovingObj 69 | 70 | // Exit position 71 | var ExitPos = image.Point{} 72 | 73 | // Channel to signal new game 74 | var NewGameCh = make(chan int, 1) 75 | 76 | // Constant for the right Mouse button value in the Click struct. 77 | // Button value for left and middle may not be the same for older browsers, but right button always has this value. 78 | const MouseBtnRight = 2 79 | 80 | // Click describes a mouse click. 81 | type Click struct { 82 | // X, Y are the mouse coordinates in pixel, in the coordinate system of the Labyrinth 83 | X, Y int 84 | // Btn is the mouse button 85 | Btn int 86 | } 87 | 88 | // Channel to receive mouse clicks on (view package sends, ctrl package (engine) processes them) 89 | var ClickCh = make(chan Click, 10) 90 | 91 | // InitNew initializes a new game. 92 | func InitNew() { 93 | LabImg = image.NewRGBA(image.Rect(0, 0, LabWidth, LabHeight)) 94 | 95 | Bulldogs = make([]*MovingObj, int(float64(Rows*Cols)*BulldogDensity/1000)) 96 | 97 | Dead = false 98 | Won = false 99 | 100 | initLab() 101 | 102 | initGopher() 103 | 104 | initBulldogs() 105 | 106 | initLabImg() 107 | 108 | ExitPos.X, ExitPos.Y = (Cols-2)*BlockSize+BlockSize/2, (Rows-2)*BlockSize+BlockSize/2 109 | } 110 | 111 | // initLab initializes and generates a new Labyrinth. 112 | func initLab() { 113 | Lab = make([][]Block, Rows) 114 | for i := range Lab { 115 | Lab[i] = make([]Block, Cols) 116 | } 117 | 118 | // Zero value of the labyrinth is full of empty blocks 119 | 120 | // generate labyrinth 121 | genLab() 122 | } 123 | 124 | // initGopher initializes Gopher. 125 | func initGopher() { 126 | // Position Gopher to top left corner 127 | Gopher.Pos.X = BlockSize + BlockSize/2 128 | Gopher.Pos.Y = Gopher.Pos.X 129 | Gopher.Direction = DirRight 130 | Gopher.TargetPos.X, Gopher.TargetPos.Y = int(Gopher.Pos.X), int(Gopher.Pos.Y) 131 | Gopher.Imgs = GopherImgs 132 | 133 | // Throw away queued targets 134 | TargetPoss = TargetPoss[0:0] 135 | } 136 | 137 | // initBulldogs creates and initializes the Bulldogs. 138 | func initBulldogs() { 139 | for i := 0; i < len(Bulldogs); i++ { 140 | bd := new(MovingObj) 141 | Bulldogs[i] = bd 142 | 143 | // Place bulldog at a random position 144 | var row, col = int(Gopher.Pos.Y) / BlockSize, int(Gopher.Pos.X) / BlockSize 145 | // Give some space to Gopher: do not generate Bulldogs too close: 146 | for gr, gc := row, col; (row-gr)*(row-gr) <= 16 && (col-gc)*(col-gc) <= 16; row, col = rPassPos(0, Rows), rPassPos(0, Cols) { 147 | } 148 | 149 | bd.Pos.X = float64(col*BlockSize + BlockSize/2) 150 | bd.Pos.Y = float64(row*BlockSize + BlockSize/2) 151 | 152 | bd.TargetPos.X, bd.TargetPos.Y = int(bd.Pos.X), int(bd.Pos.Y) 153 | bd.Imgs = BulldogImgs 154 | } 155 | } 156 | 157 | // initLabImg initializes and draws the image of the Labyrinth. 158 | func initLabImg() { 159 | // Clear the labyrinth image 160 | draw.Draw(LabImg, LabImg.Bounds(), EmptyImg, image.Pt(0, 0), draw.Over) 161 | 162 | // Draw walls 163 | zeroPt := image.Point{} 164 | for ri, row := range Lab { 165 | for ci, block := range row { 166 | if block == BlockWall { 167 | x, y := ci*BlockSize, ri*BlockSize 168 | rect := image.Rect(x, y, x+BlockSize, y+BlockSize) 169 | draw.Draw(LabImg, rect, WallImg, zeroPt, draw.Over) 170 | } 171 | } 172 | } 173 | } 174 | 175 | // genLab generates a random labyrinth. 176 | func genLab() { 177 | // Create a "frame": 178 | for ri := range Lab { 179 | Lab[ri][0] = BlockWall 180 | Lab[ri][Cols-1] = BlockWall 181 | } 182 | for ci := range Lab[0] { 183 | Lab[0][ci] = BlockWall 184 | Lab[Rows-1][ci] = BlockWall 185 | } 186 | 187 | genLabArea(0, 0, Rows-1, Cols-1) 188 | } 189 | 190 | // genLabArea generates a random labyrinth inside the specified area, borders exclusive. 191 | // This is a recursive implementation, each iteration divides the area into 2 parts. 192 | func genLabArea(x1, y1, x2, y2 int) { 193 | dx, dy := x2-x1, y2-y1 194 | 195 | // Exit condition from the recursion: 196 | if dx <= 2 || dy <= 2 { 197 | return 198 | } 199 | 200 | // Decide if we do a veritcal or horizontal split 201 | var vert bool 202 | if dy > dx { 203 | vert = false 204 | } else if dx > dy { 205 | vert = true 206 | } else if rand.Intn(2) == 0 { // Area is square, choose randomly 207 | vert = true 208 | } 209 | 210 | if vert { 211 | // Add vertical split 212 | var x int 213 | if dx > 6 { // To avoid long straight paths, only use random in smaller areas 214 | x = midWallPos(x1, x2) 215 | } else { 216 | x = rWallPos(x1, x2) 217 | } 218 | // A whole in it: 219 | y := rPassPos(y1, y2) 220 | for i := y1; i <= y2; i++ { 221 | if i != y { 222 | Lab[i][x] = BlockWall 223 | } 224 | } 225 | 226 | genLabArea(x1, y1, x, y2) 227 | genLabArea(x, y1, x2, y2) 228 | } else { 229 | // Add horizontal split 230 | var y int 231 | if dy > 6 { // To avoid long straight paths, only use random in smaller areas 232 | y = midWallPos(y1, y2) 233 | } else { 234 | y = rWallPos(y1, y2) 235 | } 236 | // A whole in it: 237 | x := rPassPos(x1, x2) 238 | for i := x1; i <= x2; i++ { 239 | if i != x { 240 | Lab[y][i] = BlockWall 241 | } 242 | } 243 | 244 | genLabArea(x1, y1, x2, y) 245 | genLabArea(x1, y, x2, y2) 246 | } 247 | } 248 | 249 | // rWallPos returns a random wall position which is an even number between the specified min and max. 250 | func rWallPos(min, max int) int { 251 | return min + (rand.Intn((max-min)/2-1)+1)*2 252 | } 253 | 254 | // midWallPos returns the wall position being at the middle of the specified min and max. 255 | func midWallPos(min, max int) int { 256 | n := (min + max) / 2 257 | // make sure it's even 258 | if n&0x01 == 1 { 259 | n-- 260 | } 261 | return n 262 | } 263 | 264 | // rPassPos returns a random passage position which is an odd number between the specified min and max. 265 | func rPassPos(min, max int) int { 266 | return rWallPos(min, max+2) - 1 267 | } 268 | -------------------------------------------------------------------------------- /resources/bulldog-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/bulldog-down.png -------------------------------------------------------------------------------- /resources/bulldog-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/bulldog-left.png -------------------------------------------------------------------------------- /resources/bulldog-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/bulldog-right.png -------------------------------------------------------------------------------- /resources/bulldog-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/bulldog-up.png -------------------------------------------------------------------------------- /resources/door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/door.png -------------------------------------------------------------------------------- /resources/gopher-dead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/gopher-dead.png -------------------------------------------------------------------------------- /resources/gopher-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/gopher-down.png -------------------------------------------------------------------------------- /resources/gopher-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/gopher-left.png -------------------------------------------------------------------------------- /resources/gopher-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/gopher-right.png -------------------------------------------------------------------------------- /resources/gopher-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/gopher-up.png -------------------------------------------------------------------------------- /resources/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/marker.png -------------------------------------------------------------------------------- /resources/source.txt: -------------------------------------------------------------------------------- 1 | These resources are not required at runtime, they are embedded into the executable binary. 2 | Whether the embedded images are used is controlled by the useEmbeddedImages constant/variable in model/images.go file. 3 | If it is set to false, these images are searched for in the current directory. 4 | 5 | 6 | Original Gopher image from: 7 | https://github.com/golang-samples/gopher-vector 8 | 9 | Original Bulldog images from: 10 | http://www.3dcadbrowser.com/download.aspx?3dmodel=14738 11 | 12 | Wall image from: 13 | http://gamedesign.wdfiles.com/local--files/spriteart%3Asprite-art-101-basic-depth/sprite_art_depth_tutorial_1.png 14 | 15 | Target image (marker): 16 | https://www.iconfinder.com/icons/73052/base_biswajit_chartreuse_con_map_marker_outside_pixe_icon 17 | 18 | Door (Exit sign) image from: 19 | http://www.fengshuiatwork.com/blog/wp-content/uploads/2011/09/front-door.png 20 | 21 | Congratulations image from: 22 | http://www.wetumpkaband.com/images/Congratulations.png 23 | 24 | -------------------------------------------------------------------------------- /resources/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/wall.png -------------------------------------------------------------------------------- /resources/won.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gophergala/golab/6c50e3f612dc324fa36a21e61516988b1eca81ba/resources/won.png -------------------------------------------------------------------------------- /view/const.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | // Title as the application - as it appears in the Browser title 4 | const AppTitle = "Gopher's Labyrinth - First Gopher Gala (2015)" 5 | 6 | var ( 7 | // Width of the client view in pixels 8 | ViewWidth int 9 | // Width of the client view in pixels 10 | ViewHeight int 11 | ) 12 | -------------------------------------------------------------------------------- /view/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package view is responsible for the UI of the game. 3 | This can be thought of as the View part of an MVC architecture. 4 | 5 | The UI is a thin HTML layer, it contains an HTML page with some embedded JavaScript. 6 | No external JavaScript libraries are used, everything is "self-made". 7 | 8 | The net/http package is used to serve the HTTP clients (browsers). 9 | */ 10 | package view 11 | -------------------------------------------------------------------------------- /view/handlers.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gophergala/golab/model" 6 | "html/template" 7 | "image" 8 | "image/jpeg" 9 | "net/http" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | var Params = struct { 15 | Title string 16 | Width, Height *int 17 | RunId int64 18 | ShowFreezeBtn bool 19 | }{AppTitle, &ViewWidth, &ViewHeight, time.Now().Unix(), false} 20 | 21 | // Template of the play html page 22 | var playTempl = template.Must(template.New("t").Parse(play_html)) 23 | 24 | // Template of the help html page 25 | var helpTempl = template.Must(template.New("t").Parse(help_html)) 26 | 27 | // The client's (browser's) view position inside the Labyrinth image. This is the top-left point of the view. 28 | var Pos image.Point 29 | 30 | // init registers the http handlers. 31 | func init() { 32 | http.HandleFunc("/", playHtmlHandle) 33 | http.HandleFunc("/runid", runIdHandle) 34 | http.HandleFunc("/img", imgHandle) 35 | http.HandleFunc("/clicked", clickedHandle) 36 | http.HandleFunc("/cheat", cheatHandle) 37 | http.HandleFunc("/new", newGameHandle) 38 | http.HandleFunc("/help", helpHtmlHandle) 39 | } 40 | 41 | // InitNew initializes a new game. 42 | func InitNew() { 43 | Pos = image.Point{} 44 | } 45 | 46 | // playHtmlHandle serves the html page where the user can play. 47 | func playHtmlHandle(w http.ResponseWriter, r *http.Request) { 48 | playTempl.Execute(w, Params) 49 | } 50 | 51 | // runidHandle serves the running app id which changes if app is restarted 52 | // (so browser clients can detect if app was restarted). 53 | func runIdHandle(w http.ResponseWriter, r *http.Request) { 54 | fmt.Fprintf(w, "%d", Params.RunId) 55 | } 56 | 57 | // imgHandle serves images of the player's view. 58 | func imgHandle(w http.ResponseWriter, r *http.Request) { 59 | quality, err := strconv.Atoi(r.FormValue("quality")) 60 | if err != nil || quality < 0 || quality > 100 { 61 | quality = 70 62 | } 63 | 64 | // Center Gopher in view if possible 65 | gpos := model.Gopher.Pos 66 | rect := image.Rect(0, 0, ViewWidth, ViewHeight).Add(image.Pt(int(gpos.X)-ViewWidth/2, int(gpos.Y)-ViewHeight/2)) 67 | 68 | // But needs correction at the edges of the view (it can't be centered) 69 | corr := image.Point{} 70 | if rect.Min.X < 0 { 71 | corr.X = -rect.Min.X 72 | } 73 | if rect.Min.Y < 0 { 74 | corr.Y = -rect.Min.Y 75 | } 76 | if rect.Max.X > model.LabWidth { 77 | corr.X = model.LabWidth - rect.Max.X 78 | } 79 | if rect.Max.Y > model.LabHeight { 80 | corr.Y = model.LabHeight - rect.Max.Y 81 | } 82 | rect = rect.Add(corr) 83 | 84 | model.Mutex.Lock() 85 | jpeg.Encode(w, model.LabImg.SubImage(rect), &jpeg.Options{quality}) 86 | model.Mutex.Unlock() 87 | 88 | // Store the new view's position: 89 | Pos = rect.Min 90 | } 91 | 92 | // clickedHandle receives mouse click (mouse button pressed) events with mouse coordinates. 93 | func clickedHandle(w http.ResponseWriter, r *http.Request) { 94 | x, err := strconv.Atoi(r.FormValue("x")) 95 | if err != nil { 96 | return 97 | } 98 | y, err := strconv.Atoi(r.FormValue("y")) 99 | if err != nil { 100 | return 101 | } 102 | btn, err := strconv.Atoi(r.FormValue("b")) 103 | if err != nil { 104 | return 105 | } 106 | 107 | // x, y are in the coordinate system of the client's view. 108 | // Translate them to the Labyrinth's coordinate system: 109 | select { 110 | case model.ClickCh <- model.Click{Pos.X + x, Pos.Y + y, btn}: 111 | default: 112 | } 113 | } 114 | 115 | // cheatHandle serves the whole image of the Labyrinth. 116 | func cheatHandle(w http.ResponseWriter, r *http.Request) { 117 | model.Mutex.Lock() 118 | jpeg.Encode(w, model.LabImg, &jpeg.Options{70}) 119 | model.Mutex.Unlock() 120 | } 121 | 122 | // newGameHandle signals to start a newgame. 123 | func newGameHandle(w http.ResponseWriter, r *http.Request) { 124 | // Use non-blocking send 125 | select { 126 | case model.NewGameCh <- 1: 127 | default: 128 | } 129 | } 130 | 131 | // helpHtmlHandle serves the help html page. 132 | func helpHtmlHandle(w http.ResponseWriter, r *http.Request) { 133 | helpTempl.Execute(w, Params) 134 | } 135 | -------------------------------------------------------------------------------- /view/help_html.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | const help_html = ` 4 | 5 | {{.Title}} 6 | 12 | 13 | 14 | 15 | 16 |

{{.Title}}

17 | 18 |
19 |

20 | Gopher's Labyrinth (or just GoLab) is a 2-dimensional Labyrinth game where you control 21 | Gopher (who else) 22 | and your goal is to get to the Exit point of the Labyrinth. But beware of the bloodthirsty Bulldogs, 23 | the ancient enemies of gophers who are endlessly roaming the Labyrinth! 24 |

25 |

26 | Controlling Gopher is very easy: just click with your left mouse button to where you want him to move 27 | (but there must be a free straight line to it). You can even queue multiple target points forming a path 28 | on which Gopher will move along. If you click with the right mouse button, the path will be cleared. 29 |

30 |
31 | 32 |
33 | 34 |
35 | 36 | 39 | 40 | 41 | 42 | ` 43 | -------------------------------------------------------------------------------- /view/play_html.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | const play_html = ` 4 | 5 | {{.Title}} 6 | 17 | 18 | 19 | 20 | 21 | 26 | 27 |

{{.Title}}

28 | 29 |
30 | Quality: 31 | 44 | 45 | FPS: 46 | 57 | 58 | 60 | 61 | 62 | 63 | Help 64 | 65 | Cheat 66 | 67 | Home page 68 |
69 | 70 |
71 | 75 |
Connection Error or Application Closed!
76 |
77 | 78 | 81 | 82 | 164 | 165 | 166 | 167 | ` 168 | --------------------------------------------------------------------------------