Trie.cs 3.28 KB
using LAViD.Unity.Utils;
using LAViD.Utils;
using System.Collections.Generic;

namespace LAViD.Structures
{
	public class Trie
	{
		private char[] characters;
		private Dictionary<char, int> keys;
		private Node root;

		private readonly static JSONObject<Trie> Parser = new JSONObject<Trie>(delegate () { return new Trie(); })
			.Add("keys", delegate (JSONParser jsonParser, Trie obj)
			{
				PlayerLogger.Log("T", "FJ", "Checking 'keys'.");
				obj.keys = jsonParser.ParseDictionary<char, int>(char.Parse, JSONParser.IntParseCallback);
			})
			.Add("trie", delegate (JSONParser jsonParser, Trie obj)
			{
				PlayerLogger.Log("T", "FJ", "Checking 'trie'.");
				obj.root = Node.FromJSON(jsonParser, obj.keys.Count);
			})
			.Add("characters", delegate (JSONParser jsonParser, Trie obj)
			{
				PlayerLogger.Log("T", "FJ", "Checking 'characters'.");
				obj.characters = jsonParser.ParseList<char>(char.Parse).ToArray();
			});

		public static Trie FromJSON(JSONParser json) {
			return Trie.Parser.Parse(json);
		}

		public void Add(string word)
		{
			Node node = this.root;

			foreach (char c in word)
			{
				int key = this.keys[c];

				if (node.children[key] == null)
					node.children[key] = new Node(this.root.maxChildren);

				node = node.children[key];
			}

			node.end = true;
		}

		public bool Contains(string word)
		{
			Node node = this.root;
			if (node == null) return false;
			
			foreach (char c in word)
			{
				node = node.children[this.keys[c]];
				if (node == null) break;
			}

			if (node == null) return false;
			else return node.end;
		}

		public List<string> StartsWith(string word)
		{
			PlayerLogger.Log("T", "SW", "Searching for '" + word + "'.");

			List<string> list = new List<string>();
			Node node = this.root;
			if (node == null) return list;

			foreach (char c in word)
			{
				node = node.children[this.keys[c]];
				if (node == null) break;
			}

			if (node != null) feed(list, word, node);

			return list;
		}

		private void feed(List<string> list, string word, Node node)
		{
			if (node.end) list.Add(word);

			for (int i = 0; i < node.children.Length; i++)
				if (node.children[i] != null)
					feed(list, word + this.characters[i], node.children[i]);
		}


		private class Node
		{
			public bool end = false;
			public Node[] children = null;
			public int maxChildren;

			public Node(int maxChildren) {
				this.maxChildren = maxChildren;
				this.children = new Node[maxChildren];
			}

			private readonly static JSONObject<Node> Parser = new JSONObject<Node>()
				.Add("keys", delegate (JSONParser jsonParser, Node obj)
				{
					jsonParser.ParseList<int>(JSONParser.IntParseCallback);
				})
				.Add("end", delegate (JSONParser jsonParser, Node obj)
				{
					obj.end = jsonParser.ParseBoolean();
				})
				.Add("children", delegate (JSONParser jsonParser, Node obj)
				{
					Dictionary<int, Node> children = jsonParser.ParseDictionary<int, Node>(
						int.Parse,
						delegate (JSONParser innerJSONParser) {
							return Node.FromJSON(innerJSONParser, obj.maxChildren);
						}
					);
					
					foreach (KeyValuePair<int, Node> pair in children)
						obj.children[pair.Key] = pair.Value;
				});

			public static Node FromJSON(JSONParser json, int maxChildren) {
				return Node.Parser.Parse(json, delegate () { return new Node(maxChildren); });
			}
		}
	}
}