1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build example
// +build example
//
// This build tag means that "go install golang.org/x/exp/shiny/..." doesn't
// install this example program. Use "go run main.go board.go xy.go" to run it
// or "go install -tags=example" to install it.
package main
import (
"fmt"
"image"
)
// Note that a "square" is not a drawn square on the board, but
// the rectangle (sic) centered on the game point.
type Dims struct {
dim int // Size of board, always square. Full size is 19.
percent int // Scale.
xInset int // From left edge to left edge of first square.
yInset int // From top edge to top edge of first square.
stoneDiam int // Diameter of stone in pixels.
stoneRad2 int // Stone radius squared.
squareWidth int // Width of square in pixels.
squareHeight int // Height of square in pixels.
lineWidth int // Width of lines.
}
// Initial values, in pixels. These numbers match the images that are loaded; they are resized.
const (
// These numbers are tuned for the images in asset/.
xInset0 = 100 // Distance from the edge of the board image to the left side of the first stone.
yInset0 = 115 // Distance from the top of the board image to the top side of the first stone.
stoneSize0 = 256 // Size of a stone on the board.
stoneDiam0 = 225 // Diameter of the circular part of the stone within the square.
// The square is a little smaller than the stone, for crowding.
squareWidth0 = 215 // Width of a square on the board.
squareHeight0 = 218 // Height of a square on the board.
stoneRad2 = stoneDiam0 * stoneDiam0 / 4
)
func (d *Dims) Init(dim, percent int) {
d.dim = dim
d.Resize(percent)
}
func (d *Dims) Resize(percent int) {
d.percent = percent
d.xInset = xInset0 * percent / 100
d.yInset = yInset0 * percent / 100
d.stoneDiam = stoneDiam0 * percent / 100
d.squareWidth = squareWidth0 * percent / 100
d.squareHeight = squareHeight0 * percent / 100
d.stoneRad2 = d.stoneDiam * d.stoneDiam / 4
d.lineWidth = 4 * percent / 100
if d.lineWidth < 2 {
d.lineWidth = 2
}
if d.lineWidth > 2 {
d.lineWidth = 4
}
}
// An XY represents a pixel in the board image. Y is downwards.
type XY struct {
x, y int
}
// An IJ represents a position on the board. It is 1-indexed and J is upwards.
type IJ struct {
i, j int
}
func (ij IJ) String() string {
return fmt.Sprintf("%c%d", 'A'+int(ij.i-1), ij.j)
}
// A go board is played on centers, not on squares, but we think of it internally
// as IJ squares (1, 1) through (19, 19), and draw the lines through the middle
// of those squares. That is how the arithmetic is done converting between
// IJ and XY.
// IJ converts a position in the board image to a Go position (IJ) on the board.
// The boolean is false if the point does not represent a Go position.
func (xy XY) IJ(d *Dims) (IJ, bool) {
x, y := xy.x, xy.y
x -= d.xInset
y -= d.yInset
i := x / d.squareWidth
j := y / d.squareHeight
// Now zero indexed. Make j goes up and switch to 1-indexed.
j = d.dim - 1 - j
i++
j++
if 1 <= i && i <= d.dim && 1 <= j && j <= d.dim {
return IJ{i, j}, true
}
return IJ{}, false
}
// XY converts a Go position to the upper left corner of the square for that position
// on the board image.
func (ij IJ) XY(d *Dims) XY {
// Change to 0-indexed.
ij.i--
ij.j--
// j goes down.
ij.j = (d.dim - 1) - ij.j
return XY{d.xInset + ij.i*d.squareWidth, d.yInset + ij.j*d.squareHeight}
}
// IJtoXYCenter converts a Go position to the center of the square for that position
// on the board image.
func (ij IJ) XYCenter(d *Dims) XY {
xy := ij.XY(d)
xy.x += d.squareWidth / 2
xy.y += d.squareHeight / 2
return xy
}
// IJtoXYStone converts a Go position to the square holding the stone for that position
// on the board image.
func (ij IJ) XYStone(d *Dims) image.Rectangle {
center := ij.XYCenter(d)
min := image.Point{center.x - d.stoneDiam/2, center.y - d.stoneDiam/2}
max := image.Point{center.x + d.stoneDiam/2, center.y + d.stoneDiam/2}
return image.Rectangle{Min: min, Max: max}
}
|