summaryrefslogtreecommitdiff
path: root/backend.go
blob: 3be4bd5d82f2d2e0ba50742ce2d56d61f2a8729b (plain)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package main

import (
// "fmt"
)

type parameters struct {
	vsCPU   bool
	sshGame bool
	debug   bool
}

type userError struct {
	query string
	err   error
}

// boatlist catalogs boat structures for use with icons.
// It is meant to be used with a "boatchars" slice containing said icons (with sunk and unsunk boats).
// Here are the slice values meanings:
// 0: Water
// 1: Vertical north tip (Triangle)
// 2: Vertical south tip (Triangle)
// 3: Horizontal west tip (Triangle)
// 4: Horizontal east tip (Triangle)
// 5: Vertical body section (rectangle)
// 6: Horizontal body section (rectangle)
var boatlist = [5][2][5]int{
	// Horizontal    | Vertical
	// Carrier:
	{{3, 6, 6, 6, 4}, {1, 5, 5, 5, 2}},
	// Battleship
	{{3, 6, 6, 4, 0}, {1, 5, 5, 2, 0}},
	// Destroyer
	{{3, 6, 6, 0, 0}, {1, 5, 5, 0, 0}},
	// Submarine
	{{3, 6, 4, 0, 0}, {1, 5, 2, 0, 0}},
	// PatrolBoat
	{{3, 6, 0, 0, 0}, {1, 5, 0, 0, 0}},
}

/* Boats Info:
   |------------+--------+----------------|
   | BoatName   | BoatID | HorizontalBoat |
   | Carrier    | 0      | ◁ ▭ ▭ ▭ ▷      |
   | Battleship | 1      | ◁ ▭ ▭ ▷        |
   | Destroyer  | 2      | ▭ ▭ ▷          |
   | Submarine  | 3      | ◁ ▭ ▷          |
   | PatrolBoat | 4      | ▭ ▷            |
   |------------+--------+----------------|
*/

// player contains all the environment of a player.
// primary is the grid containing his own boats.
// target stores info the player knows about the ennemy.
// gains keeps track of the ships the player has managed to sink.
type player struct {
	name    string
	primary [10][10][3]int
	// Primary Boat Tile Vector
	//  [y][x][boatID, position, hitStatus]int
	//  - [y][x]
	//	 	The last slice index defines his coordinates in the x,y axis.
	//  - BoatID:
	//  	n+1: Water
	//  	n: ID of the boat
	//  - Position:
	//  	0: Water
	//  	1: North arrow
	//  	2: South arrow
	//  	3: West  arrow
	//  	4: East  arrow
	//  	5: Vertical   middle
	//  	6: Horizontal middle
	//  - HitStatus:
	//  	0: Unhit
	//  	1: Hit
	target [10][10][2]int
	// Target Boat Tile Vector
	// [ hit, id ]
	// - hit:
	// 	true: Was hit
	// 	false: Has not been hit
	// - id:
	// 	0: water or unknown
	// 	n: ID of the boat
	gains [5]bool
	// True if a boat index (ID) is sunk
	prey *player
}

func (plyr *player) InitBoard(opponent *player) {
	// Sets the players' opponent
	plyr.prey = opponent
	for r := 0; r < 10; r++ {
		for c := 0; c < 10; c++ {
			plyr.primary[r][c] = [3]int{6, 0, 0}
			plyr.target[r][c] = [2]int{0, 6}

		}
	}
}

// initBoat places a boat on a players primary grid.
// boat sizes are defined by the boatlist variable.
// Consult it for more info.
func (plyr *player) InitBoat(boatID, orientation, x, y int) {
	boatLength := len(boatlist[boatID][0])
	if orientation == 0 { // Boat is HORIZONTAL
		for i := 0; i < boatLength; i++ {
			char := boatlist[boatID][0][i]
			if char == 0 { // Compensating for boatlist having
				break //      zeros at the end of slices
			}
			//TODO: Add error handling for stacking boats
			plyr.primary[y][x][0] = boatID
			plyr.primary[y][x][1] = char
			x++ // HORIZONTAL: Therefore the loop increments the x axis
		}
	} else { // Boat is VERTICAL
		for i := 0; i < boatLength; i++ {
			char := boatlist[boatID][1][i]
			if char == 0 {
				break
			}
			plyr.primary[y][x][0] = boatID
			plyr.primary[y][x][1] = char
			y++ // VERTICAL: Therefore the loop increments the y axis
		}
	}
}

func (plyr *player) Hit(x, y int) bool {
	// We change the coord status to hit
	// We add the id of the boat since we know it now.
	plyr.prey.primary[y][x][2] = 1
	plyr.target[y][x] = [2]int{1, plyr.prey.primary[y][x][0]}
	// If that coordinate contains a boat
	if BoatID := plyr.prey.primary[y][x][0]; BoatID < 5 {
		switch plyr.prey.primary[y][x][1] {
		case 1, 2, 5: // If the hit boat was vertical
			// We suppose the boat is sunk since it only takes one unhit coordinate to prove this wrong
			plyr.gains[plyr.prey.primary[y][x][0]] = true
			// We check the entire column iteratively
			for i := 0; i < 10; i++ {
				// If the boat ID of the coordinate on the board is the same as the boat which was hit
				// AND
				// If the boat was not hit at that coordinate
				if plyr.prey.primary[i][x][0] == plyr.prey.primary[y][x][0] && plyr.prey.primary[i][x][2] == 0 {
					// Then reset the boat to being unsunk
					plyr.gains[plyr.prey.primary[y][x][0]] = false
					break
				}
			}
		case 3, 4, 6: // If the hit boat was horizontal
			// We suppose the boat is sunk since it only takes one unhit coordinate to prove this wrong
			plyr.gains[plyr.prey.primary[y][x][0]] = true
			// We check the entire row iteratively
			for j := 0; j < 10; j++ {
				// If the boat ID of the coordinate on the board is the same as the boat which was hit
				// AND
				// If the boat was not hit at that coordinate
				if plyr.prey.primary[y][j][0] == plyr.prey.primary[y][x][0] && plyr.prey.primary[y][j][2] == 0 {
					// Then reset the boat to being unsunk
					plyr.gains[plyr.prey.primary[y][x][0]] = false
					break
				}
			}
		}
		return true // Returns true if there was a hit
	} else {
		return false // Returns false if water was hit
	}
}

const horizontal = 0
const vertical = 1