diff --git a/examples/community/sudoku/LICENSE b/examples/community/sudoku/LICENSE new file mode 100644 index 0000000..ae925dc --- /dev/null +++ b/examples/community/sudoku/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jason Wangsadinata + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/community/sudoku/README.md b/examples/community/sudoku/README.md new file mode 100644 index 0000000..73b7a1c --- /dev/null +++ b/examples/community/sudoku/README.md @@ -0,0 +1,45 @@ +# Sudoku + +A game of Sudoku written in [Go][go]. + +From [Wikipedia][sudoku-wiki]: +> Sudoku (数独 sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, originally +> called Number Place) is a logic-based, combinatorial number-placement puzzle. +> The objective is to fill a 9×9 grid with digits so that each column, each row, +> and each of the nine 3×3 subgrids that compose the grid (also called "boxes", +> "blocks", or "regions") contains all of the digits from 1 to 9. The puzzle +> setter provides a partially completed grid, which for a well-posed puzzle has +> a single solution. + +Created by [Jason Wangsadinata][jwangsadinata] using +[Pixel][pixel]. + +This example is kept to the bare minimum for demonstrating just the main +concepts of using imdraw, and batch with texts. For a game with slightly more +features, please check out [Go-Sudoku][go-sudoku] + +## Usage + +Run it the usual way: + + go run sudoku.go + +## How to Play + +- *Left mouse* click to select a box. +- *Number keys* to input a number. +- *Space* or *Backspace* to delete a number. + +## Screenshots + +![Sudoku](sudoku.png) + +## Links + +- [Go-Sudoku][go-sudoku] + +[go]: https://golang.org +[go-sudoku]: https://github.com/jwangsadinata/go-sudoku +[jwangsadinata]: https://github.com/jwangsadinata +[pixel]: https://github.com/faiface/pixel +[sudoku-wiki]: https://en.wikipedia.org/wiki/Sudoku diff --git a/examples/community/sudoku/sudoku.go b/examples/community/sudoku/sudoku.go new file mode 100644 index 0000000..882987c --- /dev/null +++ b/examples/community/sudoku/sudoku.go @@ -0,0 +1,214 @@ +package main + +import ( + "image" + "os" + "strconv" + + _ "image/png" + + "github.com/faiface/pixel" + "github.com/faiface/pixel/imdraw" + "github.com/faiface/pixel/pixelgl" + "github.com/faiface/pixel/text" + "github.com/golang/freetype/truetype" + "golang.org/x/image/colornames" + "golang.org/x/image/font/gofont/goregular" +) + +const ( + width = 900 +) + +var input bool +var x, y int + +var board = [9][9]int{} +var puzzle = [9][9]int{ + {6, 7, 2, 3, 4, 1, 5, 8, 9}, + {5, 3, 4, 9, 6, 8, 1, 2, 7}, + {8, 9, 1, 7, 5, 2, 6, 3, 4}, + {3, 5, 6, 8, 2, 9, 4, 7, 1}, + {7, 2, 8, 4, 1, 5, 3, 9, 6}, + {4, 1, 9, 6, 7, 3, 8, 5, 2}, + {1, 8, 3, 2, 9, 6, 7, 4, 5}, + {9, 6, 7, 5, 3, 4, 2, 1, 8}, + {2, 4, 5, 1, 8, 7, 9, 6, 3}, +} + +var mask = [9][9]bool{ + {false, false, true, false, false, true, true, true, false}, + {false, false, true, true, true, false, false, false, true}, + {true, false, false, false, false, false, true, true, false}, + {false, true, true, false, true, false, true, true, false}, + {false, true, false, false, false, true, false, true, false}, + {false, true, true, false, true, false, true, true, false}, + {false, true, true, false, false, false, false, false, true}, + {true, false, false, false, true, true, true, false, false}, + {false, true, true, true, false, false, true, false, false}, +} + +func loadPicture(path string) (pixel.Picture, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + img, _, err := image.Decode(file) + if err != nil { + return nil, err + } + return pixel.PictureDataFromImage(img), nil +} + +func updateBoard(value int, imd *imdraw.IMDraw) { + board[x][y] = value + imd.Clear() + input = false +} + +func run() { + // initialize window + cfg := pixelgl.WindowConfig{ + Title: "Sudoku", + Bounds: pixel.R(0, 0, width, width), + VSync: true, + } + win, err := pixelgl.NewWindow(cfg) + if err != nil { + panic(err) + } + + // initialize imdraw + imd := imdraw.New(nil) + + // initialize font + ttf, err := truetype.Parse(goregular.TTF) + if err != nil { + panic(err) + } + face := truetype.NewFace(ttf, &truetype.Options{ + Size: 64 * width / 900, + }) + atlas := text.NewAtlas(face, text.ASCII) + + // initialize batch + batch := pixel.NewBatch(&pixel.TrianglesData{}, atlas.Picture()) + + // setup game + for i := 0; i < 9; i++ { + for j := 0; j < 9; j++ { + if mask[i][j] { + board[i][j] = puzzle[i][j] + } + } + } + + for !win.Closed() { + // win condition + if board == puzzle { + win.SetClosed(true) + } + + // select a box + if win.JustPressed(pixelgl.MouseButtonLeft) { + if input { + imd.Clear() + } + pos := win.MousePosition() + x = int(pos.X) / (width / 9) + y = int(pos.Y) / (width / 9) + + if !mask[x][y] { + imd.Color = colornames.Paleturquoise + imd.Push(pixel.V(float64(x*width/9)+1, float64(y*width/9)+1), + pixel.V(float64((x+1)*width/9)-1, float64((y+1)*width/9)-1)) + imd.Rectangle(0) + input = true + } + } + // act on user input + if input && !mask[x][y] { + if win.JustPressed(pixelgl.Key1) || win.JustPressed(pixelgl.KeyKP1) { + updateBoard(1, imd) + } + if win.JustPressed(pixelgl.Key2) || win.JustPressed(pixelgl.KeyKP2) { + updateBoard(2, imd) + } + if win.JustPressed(pixelgl.Key3) || win.JustPressed(pixelgl.KeyKP3) { + updateBoard(3, imd) + } + if win.JustPressed(pixelgl.Key4) || win.JustPressed(pixelgl.KeyKP4) { + updateBoard(4, imd) + } + if win.JustPressed(pixelgl.Key5) || win.JustPressed(pixelgl.KeyKP5) { + updateBoard(5, imd) + } + if win.JustPressed(pixelgl.Key6) || win.JustPressed(pixelgl.KeyKP6) { + updateBoard(6, imd) + } + if win.JustPressed(pixelgl.Key7) || win.JustPressed(pixelgl.KeyKP7) { + updateBoard(7, imd) + } + if win.JustPressed(pixelgl.Key8) || win.JustPressed(pixelgl.KeyKP8) { + updateBoard(8, imd) + } + if win.JustPressed(pixelgl.Key9) || win.JustPressed(pixelgl.KeyKP9) { + updateBoard(9, imd) + } + if win.JustPressed(pixelgl.Key0) || win.JustPressed(pixelgl.KeyKP0) || + win.JustPressed(pixelgl.KeyBackspace) || win.JustPressed(pixelgl.KeySpace) { + updateBoard(0, imd) + } + } + + // set up lines for drawing + for i := 1; i < 9; i++ { + imd.Color = colornames.Black + if i%3 == 0 { + imd.Push(pixel.V(float64(i*width/9), 0), pixel.V(float64(i*width/9), width)) + imd.Line(6) + + imd.Push(pixel.V(0, float64(i*width/9)), pixel.V(width, float64(i*width/9))) + imd.Line(6) + } else { + imd.Push(pixel.V(float64(i*width/9), 0), pixel.V(float64(i*width/9), width)) + imd.Line(3) + + imd.Push(pixel.V(0, float64(i*width/9)), pixel.V(width, float64(i*width/9))) + imd.Line(3) + } + } + + // set up numbers for drawing + batch.Clear() + for a, sa := range board { + for b, sb := range sa { + if sb != 0 { + num := text.New(pixel.ZV, atlas) + num.WriteString(strconv.Itoa(sb)) + num.DrawColorMask(batch, + pixel.IM. + Scaled( + pixel.ZV, float64(width)/900). + Moved( + pixel.V((float64(a)+0.3)*width/9, + (float64(b)+0.25)*width/9)), + colornames.Black) + } + } + } + + // draw the scene to the window + win.Clear(colornames.Snow) + batch.Draw(win) + imd.Draw(win) + + // update the window + win.Update() + } +} + +func main() { + pixelgl.Run(run) +} diff --git a/examples/community/sudoku/sudoku.png b/examples/community/sudoku/sudoku.png new file mode 100644 index 0000000..6e317fd Binary files /dev/null and b/examples/community/sudoku/sudoku.png differ