public ActionResult AI_vs_AI(string id, int?version, int[] difficulty) { VariantService variants = GetService <VariantService>(); VariantVersion versionToPlay = DeterminePlayVersion(id, version, variants); if (versionToPlay == null) { return(HttpNotFound("Cannot determine variant version to play")); } var model = new GamePlayModel(versionToPlay, GameMode.AI_vs_AI); var AIs = variants.ListAiDifficulties(); model.Players = new PlayerModel[versionToPlay.Variant.PlayerCount]; for (var i = 0; i < model.Players.Length && i < difficulty.Length; i++) { model.Players[i] = AIs.Single(ai => ai.ID == difficulty[i]); } for (var i = difficulty.Length; i < model.Players.Length; i++) { model.Players[i] = model.Players[difficulty.Length]; } return(View("Play", model)); }
private VariantVersion DeterminePlayVersion(string variantTag, int?versionID, VariantService variants) { var variant = variants.GetByTag(variantTag); if (variant == null) { return(null); } if (versionID.HasValue && variant.CreatedBy.Name == User.Identity.Name) { VariantVersion version = variants.GetVersionNumber(variant, versionID.Value); if (version == null || version.VariantID != variant.ID) { return(null); } return(version); } else { return(variant.PublicVersion); } }
public bool CanDelete(VariantVersion version) { // versions can be deleted only if they are associated with no games at all, active or otherwise. // public versions can not be deleted. return(!version.Games.Any() && (!version.Variant.PublicVersionID.HasValue || version.Variant.PublicVersionID != version.ID) && version.Variant.AllVersions.Count > 1); }
public void SaveLinkData(VariantVersion version, string linkData) { var definition = GetDefinition(version); var board = definition.Board; SaveLinkData(definition, board, linkData); definition.Board = board; version.LastModified = DateTime.Now; Entities.SaveChanges(); }
public ActionResult Definition(string id, int?version) { VariantService variants = GetService <VariantService>(); VariantVersion versionToPlay = DeterminePlayVersion(id, version, variants); if (versionToPlay == null) { return(HttpNotFound("Cannot determine variant version to play")); } return(Content(versionToPlay.Definition, "text/xml")); }
public XmlDocument GetBoardSVG(VariantVersion version, bool addArrowheadDef = false, bool showCellRefs = false) { var board = GetDefinition(version).Board; XmlDocument svgDoc = new XmlDocument(); svgDoc.AppendChild(svgDoc.CreateElement("svg")); if (addArrowheadDef) { // add a <defs> section containing an arrowhead marker var defs = svgDoc.CreateElement("defs"); defs.InnerXml = @"<marker id=""arrowhead"" viewbox=""0 0 10 10"" refX=""1"" refY=""5"" markerWidth=""6"" markerHeight=""6"" orient=""auto""><path d=""M 0 0 L 10 5 L 0 10 z"" /></marker>"; svgDoc.DocumentElement.AppendChild(defs); } var attr = svgDoc.CreateAttribute("xmlns"); attr.Value = "http://www.w3.org/2000/svg"; svgDoc.DocumentElement.Attributes.Append(attr); attr = svgDoc.CreateAttribute("id"); attr.Value = "render"; svgDoc.DocumentElement.Attributes.Append(attr); attr = svgDoc.CreateAttribute("viewBox"); attr.Value = board.Attributes["viewBox"].Value; svgDoc.DocumentElement.Attributes.Append(attr); foreach (XmlNode node in board.ChildNodes) { if (node.Name == "cell") { WriteCellToSVG(node, svgDoc); } else if (node.Name == "line") { WriteLineToSVG(node, svgDoc); } } if (showCellRefs) // done last, so that references appear on top of lines { foreach (XmlNode node in board.SelectNodes("cell")) { WriteCellRefToSVG(node, svgDoc); } } return(svgDoc); }
public VariantVersion CreateNewVersion(VariantVersion version) { var newestVersion = version.Variant.AllVersions.OrderByDescending(v => v.Number).FirstOrDefault(); int versionNum = newestVersion == null ? 1 : newestVersion.Number + 1; var newVersion = Entities.Entry(version).GetDatabaseValues().ToObject() as VariantVersion; newVersion.LastModified = DateTime.Now; newVersion.Number = (short)versionNum; Entities.VariantVersions.Add(newVersion); Entities.SaveChanges(); return(newVersion); }
public string GetCellLinks(VariantVersion version) { var board = GetDefinition(version).Board; var sb = new StringBuilder(); foreach (XmlNode cell in board.SelectNodes("cell")) { foreach (XmlNode link in cell.SelectNodes("link")) { sb.AppendFormat(";{0}:{1}:{2}", cell.Attributes["id"].Value, link.Attributes["dir"].Value, link.Attributes["to"].Value); } } return(sb.ToString()); }
public void SaveCellReferenceChanges(VariantVersion version, string renameData) { var definition = GetDefinition(version); var board = definition.Board; var renames = renameData.Split(outerSep, StringSplitOptions.RemoveEmptyEntries); foreach (var rename in renames) { var parts = rename.Split(innerSep); if (parts.Length != 2) { continue; } var from = parts[0]; var to = parts[1]; var alreadyExists = board.SelectSingleNode(string.Format("cell[@id='{0}']", to)); if (alreadyExists != null) { continue; } // find the "from" cell, and change its ID to the "to" value. var cell = board.SelectSingleNode(string.Format("cell[@id='{0}']", from)); if (cell == null) { continue; } cell.Attributes["id"].Value = to; // do the same for ALL links to this cell var links = board.SelectNodes(string.Format("cell/link[@to='{0}']", from)); foreach (XmlNode link in links) { link.Attributes["to"].Value = to; } } definition.Board = board; version.LastModified = DateTime.Now; Entities.SaveChanges(); }
public IEnumerable <string> ListGlobalDirections(VariantVersion version) { SortedSet <string> directions = new SortedSet <string>(); var board = GetDefinition(version).Board; foreach (XmlNode fromCell in board.SelectNodes("cell")) { foreach (XmlNode link in fromCell.ChildNodes) { var dir = link.Attributes["dir"].Value; if (!directions.Contains(dir)) { directions.Add(dir); } } } return(directions); }
public string GetDirectionGroups(VariantVersion version) { var definition = GetDefinition(version); var groups = definition.Dirs.SelectNodes("group"); var sb = new StringBuilder(); foreach (XmlNode groupNode in groups) { sb.Append(outerSep); sb.Append(groupNode.Attributes["name"].Value); foreach (XmlNode dir in groupNode.ChildNodes) { sb.Append(innerSep); sb.Append(dir.Attributes["dir"].Value); } } return(sb.ToString()); }
public void SaveDirectionGroups(VariantVersion version, string groupData) { var definition = GetDefinition(version); var root = definition.Dirs; if (root == null) { root = definition.Dirs = definition.CreateElement("dirs"); } else { // clear existing direction groups var existingGroups = root.SelectNodes("group"); foreach (XmlNode group in existingGroups) { group.ParentNode.RemoveChild(group); } } var groups = groupData.Split(outerSep, StringSplitOptions.RemoveEmptyEntries); foreach (string group in groups) { var groupParts = group.Split(innerSep); var groupNode = definition.CreateElement("group"); groupNode.Attributes.Append(definition.CreateAttribute("name", groupParts[0])); for (int i = 1; i < groupParts.Length; i++) { var linkNode = definition.CreateElement("include"); linkNode.Attributes.Append(definition.CreateAttribute("dir", groupParts[i])); groupNode.AppendChild(linkNode); } root.AppendChild(groupNode); } definition.Dirs = root; version.LastModified = DateTime.Now; Entities.SaveChanges(); }
public bool SaveBoardData(VariantVersion version, string boardSVG, string cellLinks) { XmlDocument svgDoc = new XmlDocument(); try { svgDoc.LoadXml(boardSVG); } catch { return(false); } var definition = GetDefinition(version); var board = definition.CreateElement("board"); var viewBox = definition.CreateAttribute("viewBox"); viewBox.Value = svgDoc.DocumentElement.HasAttribute("viewBox") ? svgDoc.DocumentElement.Attributes["viewBox"].Value : definition.Board.Attributes["viewBox"].Value; board.Attributes.Append(viewBox); foreach (XmlNode node in svgDoc.DocumentElement.ChildNodes) { if (node.Name == "path") { SaveCellFromSVG(node, board); } else if (node.Name == "line") { SaveLineFromSVG(node, board); } } SaveLinkData(definition, board, cellLinks); definition.Board = board; version.LastModified = DateTime.Now; Entities.SaveChanges(); return(true); }
public string GetRelativeDirs(VariantVersion version) { StringBuilder sb = new StringBuilder(); var dirRoot = GetDefinition(version).Dirs; if (dirRoot == null) { return(string.Empty); } foreach (XmlNode relativeNode in dirRoot.SelectNodes("relative")) { var relDir = relativeNode.Attributes["name"].Value; foreach (XmlNode link in relativeNode.ChildNodes) { sb.AppendFormat(";{0}:{1}:{2}", link.Attributes["from"].Value, relDir, link.Attributes["to"].Value); } } return(sb.ToString()); }
public IEnumerable <string> ListRelativeDirections(VariantVersion version) { SortedSet <string> directions = new SortedSet <string>(); var dirRoot = GetDefinition(version).Dirs; if (dirRoot == null) { return(new string[0]); } foreach (XmlNode relativeNode in dirRoot.SelectNodes("relative")) { var dir = relativeNode.Attributes["name"].Value; if (!directions.Contains(dir)) { directions.Add(dir); } } return(directions); }
public ActionResult New([Bind(Include = "Name,NumPlayers,Description,HelpText")] VariantEditModel model) { if (!ModelState.IsValid) { return(RedirectToAction("New")); } UserService users = GetService <UserService>(); VariantService variants = GetService <VariantService>(); var user = users.GetByName(User.Identity.Name); var variant = new Variant(); variant.CreatedByID = user.ID; variant.Description = model.Description ?? string.Empty; variant.HelpText = DataService.StripTags(model.HelpText ?? string.Empty); variant.PlayerCount = (byte)model.NumPlayers; if (!ValidateName(model, variant)) { return(View(model)); } var version = new VariantVersion(); version.Number = 1; version.LastModified = DateTime.Now; version.Variant = variant; version.Definition = string.Empty; Entities().Variants.Add(variant); Entities().VariantVersions.Add(version); Entities().SaveChanges(); return(RedirectToAction("Shape", "Designer", new { version.ID })); }
public ActionResult Offline(string id, int?version) { VariantService variants = GetService <VariantService>(); VariantVersion versionToPlay = DeterminePlayVersion(id, version, variants); if (versionToPlay == null) { return(HttpNotFound("Cannot determine variant version to play")); } var model = new GamePlayModel(versionToPlay, GameMode.Offline); model.Players = new PlayerModel[versionToPlay.Variant.PlayerCount]; for (int i = 0; i < model.Players.Length; i++) { model.Players[i] = new PlayerModel() { IsLocal = true } } ; return(View("Play", model)); }
public VariantDefinition GetDefinition(VariantVersion version) { // at some point this should be made to cache definitions, but we have to make sure it updates the cache when they're modified return(new VariantDefinition(version)); }
public static string DescribeVersion(VariantVersion version) { return(string.Format("v{0} @ {1}", version.Number, version.LastModified.ToString("d"))); }
public bool IsAllowedToPlay(VariantVersion version, string userName) { return((version.Variant.PublicVersionID.HasValue && version.Variant.PublicVersionID == version.ID) || version.Variant.CreatedBy.Name == userName); }
private bool ValidateNewGame(GameMode modeSelect, int?variantSelect, int?aiSelect, string[] opponent, VariantService variants, out VariantVersion version, out List <User> opponentUsers, out AIDifficultyModel aiDifficulty) { opponentUsers = null; aiDifficulty = default(AIDifficultyModel); // is variant version ID valid? version = variantSelect.HasValue ? Entities().VariantVersions.Find(variantSelect.Value) : null; if (version == null) { ModelState.AddModelError("variantSelect", "Please select a variant."); return(false); } // can user access variant version? UserService users = GetService <UserService>(); if (!users.IsAllowedToPlay(version, User.Identity.Name)) { ModelState.AddModelError("variantSelect", "Cannot access selected variant version."); return(false); } // if game mode is public, is variant version public? if (modeSelect == GameMode.Public && (!version.Variant.PublicVersionID.HasValue || version.Variant.PublicVersionID != version.Variant.PublicVersionID)) { ModelState.AddModelError("variantSelect", "Public games cannot use a private variant."); return(false); } // if game mode is AI, is difficulty selection valid? aiDifficulty = aiSelect.HasValue ? variants.ListAiDifficulties().SingleOrDefault(ai => ai.ID == aiSelect.Value) : null; if (modeSelect == GameMode.AI && aiDifficulty == null) { ModelState.AddModelError("aiSelect", "Invalid AI difficulty."); return(false); } // if game mode is private, are all opponent fields filled in, valid users, not the current user, and not duplicated? if (modeSelect == GameMode.Private) { if (opponent.Length != version.Variant.PlayerCount - 1 || opponent.Count(o => string.IsNullOrWhiteSpace(o)) != 0) { ModelState.AddModelError("opponent", string.Format(version.Variant.Name + " requires {0} players, so you must specify {1} opponent{2}.", version.Variant.PlayerCount, version.Variant.PlayerCount - 1, version.Variant.PlayerCount == 2 ? string.Empty : "s")); return(false); } if (opponent.FirstOrDefault(o => string.Equals(o.Trim(), User.Identity.Name, StringComparison.InvariantCultureIgnoreCase)) != null) { ModelState.AddModelError("opponent", "You cannot enter your own name as an opponent."); return(false); } opponentUsers = new List <User>(opponent.Length); foreach (var o in opponent) { User u = users.GetByName(o.Trim()); if (u == null) { ModelState.AddModelError("opponent", "Not a valid user name: " + o); return(false); } if (opponentUsers.FirstOrDefault(x => string.Equals(x.Name, u.Name, StringComparison.InvariantCultureIgnoreCase)) != null) { ModelState.AddModelError("opponent", "You cannot enter the same opponent multiple times"); return(false); } opponentUsers.Add(u); } } return(true); }
public string CalculateGlobalDirectionDiagram(VariantVersion version) { var directions = new SortedList <string, GlobalDirInfo>(); var board = GetDefinition(version).Board; foreach (XmlNode fromCell in board.SelectNodes("cell")) { // read path attr for X & Y positions var fromCellPath = fromCell.Attributes["path"].Value.Substring(1).Split(space, 3); float fromCellX, fromCellY; if (!float.TryParse(fromCellPath[1], out fromCellY) || fromCellPath[0].Length < 2 || !float.TryParse(fromCellPath[0], out fromCellX)) { continue; } foreach (XmlNode link in fromCell.ChildNodes) { var dir = link.Attributes["dir"].Value; var toCellName = link.Attributes["to"].Value; var toCell = board.SelectSingleNode(string.Format("cell[@id='{0}']", toCellName)); if (toCell == null) { if (!directions.ContainsKey(dir)) { directions[dir] = new GlobalDirInfo(dir, 0); } continue; } // read path attr for X & Y positions var toCellPath = toCell.Attributes["path"].Value.Split(space, 3); float toCellX, toCellY; if (!float.TryParse(toCellPath[1], out toCellY) || !float.TryParse(toCellPath[0].Substring(1), out toCellX)) { if (!directions.ContainsKey(dir)) { directions[dir] = new GlobalDirInfo(dir, 0); } continue; } var dx = toCellX - fromCellX; var dy = toCellY - fromCellY; if (!directions.ContainsKey(dir)) { directions[dir] = new GlobalDirInfo(dir) { FirstDX = dx, FirstDY = dy } } ; var direction = directions[dir]; direction.Num++; direction.DX += dx; direction.DY += dy; } } var svgDoc = new XmlDocument(); svgDoc.AppendChild(svgDoc.CreateElement("svg")); // add a <defs> section containing an arrowhead marker var defs = svgDoc.CreateElement("defs"); defs.InnerXml = @"<marker id=""arrowhead"" viewbox=""0 0 10 10"" refX=""1"" refY=""5"" markerWidth=""6"" markerHeight=""6"" orient=""auto""><path d=""M 0 0 L 10 5 L 0 10 z"" /></marker> <marker id=""arrowhead_from"" viewbox=""0 0 10 10"" refX=""1"" refY=""5"" markerWidth=""6"" markerHeight=""6"" orient=""auto""><path d=""M 0 0 L 10 5 L 0 10 z"" /></marker> <marker id=""arrowhead_to"" viewbox=""0 0 10 10"" refX=""1"" refY=""5"" markerWidth=""6"" markerHeight=""6"" orient=""auto""><path d=""M 0 0 L 10 5 L 0 10 z"" /></marker>"; svgDoc.DocumentElement.AppendChild(defs); var attr = svgDoc.CreateAttribute("xmlns"); attr.Value = "http://www.w3.org/2000/svg"; svgDoc.DocumentElement.Attributes.Append(attr); attr = svgDoc.CreateAttribute("id"); attr.Value = "indicator"; svgDoc.DocumentElement.Attributes.Append(attr); attr = svgDoc.CreateAttribute("viewbox"); attr.Value = "-120 -120 240 240"; svgDoc.DocumentElement.Attributes.Append(attr); // the elements should be written out here sorted by their directions, such that they come out in a clockwise order (this isn't for the diagram itself, but for the edit groups) const float tolerance = 0.01f; foreach (var kvp in directions) { var dir = kvp.Value; if (dir.Num > 1) { dir.DX /= dir.Num; dir.DY /= dir.Num; } if (Math.Abs(dir.DX) < tolerance && Math.Abs(dir.DY) < tolerance) { dir.DX = dir.FirstDX; dir.DY = dir.FirstDY; } } foreach (var dir in directions.Values.OrderBy(dir => dir.Angle)) { Console.WriteLine("{0}, {1}", dir.Name, dir.Angle); var magnitude = (float)Math.Sqrt(dir.DX * dir.DX + dir.DY * dir.DY); dir.DX /= magnitude; dir.DY /= magnitude; var line = svgDoc.CreateElement("line"); svgDoc.DocumentElement.AppendChild(line); attr = svgDoc.CreateAttribute("x1"); attr.Value = (dir.DX * 10).ToString("0.#"); line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("y1"); attr.Value = (dir.DY * 10).ToString("0.#"); line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("x2"); attr.Value = (dir.DX * 100).ToString("0.#"); line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("y2"); attr.Value = (dir.DY * 100).ToString("0.#"); line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("class"); attr.Value = "marker"; line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("dir"); attr.Value = dir.Name; line.Attributes.Append(attr); attr = svgDoc.CreateAttribute("marker-end"); attr.Value = "url(#arrowhead)"; line.Attributes.Append(attr); } return(svgDoc.OuterXml); }
public void SaveRelativeDirs(VariantVersion version, string relData) { var definition = GetDefinition(version); var root = definition.Dirs; if (root == null) { root = definition.Dirs = definition.CreateElement("dirs"); } else { // clear existing relative directions var existingDirs = root.SelectNodes("relative"); foreach (XmlNode dir in existingDirs) { dir.ParentNode.RemoveChild(dir); } } var relativeDirData = new SortedList <string, List <Tuple <string, string> > >(); var relLink = relData.Split(outerSep, StringSplitOptions.RemoveEmptyEntries); foreach (string link in relLink) { var linkParts = link.Split(innerSep, 3); if (linkParts.Length != 3) { continue; } string from = linkParts[0]; string relDir = linkParts[1]; string to = linkParts[2]; List <Tuple <string, string> > linksForThisDir; if (!relativeDirData.TryGetValue(relDir, out linksForThisDir)) { linksForThisDir = new List <Tuple <string, string> >(); relativeDirData.Add(relDir, linksForThisDir); } linksForThisDir.Add(new Tuple <string, string>(from, to)); } foreach (var kvp in relativeDirData) { var relDirNode = definition.CreateElement("relative"); relDirNode.Attributes.Append(definition.CreateAttribute("name", kvp.Key)); foreach (var link in kvp.Value) { var linkNode = definition.CreateElement("link"); linkNode.Attributes.Append(definition.CreateAttribute("from", link.Item1)); linkNode.Attributes.Append(definition.CreateAttribute("to", link.Item2)); relDirNode.AppendChild(linkNode); } root.PrependChild(relDirNode); } definition.Dirs = root; version.LastModified = DateTime.Now; Entities.SaveChanges(); }
public XmlNode GetPieceDefinitionXML(VariantVersion version) { var definition = GetDefinition(version); return(definition.Pieces); }