Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

sight.gno

3.53 Kb · 106 lines
  1package hex
  2
  3import "sort"
  4
  5// Height is the height of a counter or of a terrain feature for the line
  6// of sight (rule 31.3, the HEIGHTS table), at ground elevation: a higher
  7// number is higher on the map. Hill and gully elevations come with the
  8// boards that have them.
  9type Height int
 10
 11const (
 12	// HeightDown is a DOWN body counter.
 13	HeightDown Height = 3
 14	// HeightObstacle is an obstacle (36.3) or a window sill (33.5).
 15	HeightObstacle Height = 4
 16	// HeightUpright is an upright counter, a counter on an obstacle (30.32)
 17	// and a hex aimed at (31.3).
 18	HeightUpright Height = 5
 19	// HeightWall is a wall or a treetrunk, higher than anything (33.2, 38.3).
 20	HeightWall Height = 10
 21)
 22
 23// Between returns the obstacle hexes lying between two hexes for the line
 24// of sight (rule 31): those every string from one hex's printed coordinate
 25// to the other's passes through (31.2, 36.3), as the generator computed
 26// them from the board image into the between table. The order of the two
 27// hexes does not matter. It is nil when nothing lies between them, when
 28// they are the same hex or when either is unknown, and it never names one
 29// of the two hexes (36.5).
 30func (b *Board) Between(from, to string) []string {
 31	var out []string
 32	for _, o := range b.obstaclesBetween(b.Index(from), b.Index(to)) {
 33		out = append(out, b.ids[o])
 34	}
 35	return out
 36}
 37
 38// obstaclesBetween is Between on indices: the obstacle hexes between ids[i] and
 39// ids[j], as indices in ids.
 40func (b *Board) obstaclesBetween(i, j int) []int {
 41	if i < 0 || j < 0 || i == j {
 42		return nil
 43	}
 44	if i > j {
 45		i, j = j, i
 46	}
 47	// The rows are sorted by (a, b, o): a pair's rows are contiguous.
 48	k := sort.Search(len(b.between), func(k int) bool {
 49		r := b.between[k]
 50		return r[0] > i || (r[0] == i && r[1] >= j)
 51	})
 52	var out []int
 53	for ; k < len(b.between) && b.between[k][0] == i && b.between[k][1] == j; k++ {
 54		out = append(out, b.obstacles[b.between[k][2]])
 55	}
 56	return out
 57}
 58
 59// LineOfSight reports whether a character at from, of height hFrom, has a
 60// clear line of sight to a target at to, of height hTo (rule 31). Every
 61// obstacle lying between the two hexes is compared with the two heights
 62// (31.3): it blocks the sight when higher than both and not when lower
 63// than both (31.31); when it is between the two heights it blocks only if
 64// the lower end is adjacent to it (31.32; the plateau effect of 31.33
 65// needs hill or gully hexes, which no board has yet). The aim zone is not
 66// looked at here: 31.21 is InAimZone. blocker is the first obstacle
 67// blocking the sight, "" when it is clear or a hex is unknown (which
 68// blocks).
 69func (b *Board) LineOfSight(from, to string, hFrom, hTo Height) (clear bool, blocker string) {
 70	i, j := b.Index(from), b.Index(to)
 71	if i < 0 || j < 0 {
 72		return false, ""
 73	}
 74	for _, o := range b.obstaclesBetween(i, j) {
 75		if blocks(HeightObstacle, hFrom, hTo, b.adjacent(i, o), b.adjacent(j, o)) {
 76			return false, b.ids[o]
 77		}
 78	}
 79	return true, ""
 80}
 81
 82// blocks applies rules 31.31 and 31.32 to a feature of height h lying
 83// between two counters of heights h1 and h2, each adjacent to it or not.
 84func blocks(h, h1, h2 Height, adj1, adj2 bool) bool {
 85	switch {
 86	case h > h1 && h > h2:
 87		return true // higher than both (31.31)
 88	case h < h1 && h < h2:
 89		return false // lower than both (31.31)
 90	case h1 < h:
 91		return adj1 // the lower counter blocks the sight when adjacent (31.32)
 92	case h2 < h:
 93		return adj2
 94	}
 95	return false
 96}
 97
 98// adjacent reports whether ids[j] is a neighbour of ids[i].
 99func (b *Board) adjacent(i, j int) bool {
100	for _, n := range b.nbr[i] {
101		if n == j {
102			return true
103		}
104	}
105	return false
106}