File: xy.go

package info (click to toggle)
golang-golang-x-exp 0.0~git20230522.2e198f4-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 6,404 kB
  • sloc: ansic: 1,900; objc: 276; sh: 272; asm: 48; makefile: 26
file content (133 lines) | stat: -rw-r--r-- 4,188 bytes parent folder | download | duplicates (4)
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}
}