online multiplayer chess game (note server currently down)
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
extends Node
class_name PGN


func parse(pgn: String, tags := true) -> Dictionary:
	# put tags into a dictionary,
	# and the moves into a array

	var movetextex = SanParse.compile(
		"([NBKRQ]?[a-h]?[1-8]?[\\-x]?[a-h][1-8](?:=?[nbrqkNBRQK])?|[PNBRQK]?@[a-h][1-8]|--|Z0|0000|@@@@|O-O(?:-O)?|0-0(?:-0)?)|(\\{.*)|(;.*)|(\\$[0-9]+)|(\\()|(\\))|(\\*|1-0|0-1|1\\/2-1\\/2)|([\\?!]{1,2})",
		false
	)
	var lines = Array(pgn.split("\n"))
	var headers := {}
	if tags:
		var tagex = SanParse.compile('^\\[([A-Za-z0-9_]+)\\s+"([^\\r]*)"\\]\\s*$', false)
		var tagnameex = SanParse.compile("^[A-Za-z0-9_]+\\Z", false)
		# get headers
		while !lines.empty():
			var line = lines[0].strip_edges()
			if !line or line[0] in ["%", ";"]:
				lines.pop_front()
				continue

			if line[0] != "[":
				break

			lines.pop_front()
			var tag_match = tagex.search(line)
			if tag_match:
				var cap = tag_match.strings
				if tagnameex.search(cap[1]):
					headers[cap[1]] = cap[2]
				else:
					# invalid headers
					push_error("invalid headers")
					return {}
			else:
				break
	var movetext := PoolStringArray()
	while !lines.empty():
		var line = lines.pop_front().strip_edges()
		if !line:
			break
		if line[0] in ["%", ";"]:
			continue
		for found in movetextex.search_all(line):
			if found.strings[1]:
				movetext.append(found.strings[1])
	return {"headers": headers, "moves": movetext}