218 lines
5.1 KiB
Go
218 lines
5.1 KiB
Go
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())
|
|
|
|
// initialize text placeholder
|
|
num := text.New(pixel.ZV, atlas)
|
|
|
|
// 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.Clear()
|
|
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)
|
|
}
|