Skip to content
This repository has been archived by the owner on Mar 12, 2019. It is now read-only.

Commit

Permalink
Add off-game source code
Browse files Browse the repository at this point in the history
  • Loading branch information
extesy committed Jul 15, 2017
1 parent 6f6ecac commit 37a1379
Show file tree
Hide file tree
Showing 73 changed files with 6,072 additions and 677 deletions.
63 changes: 63 additions & 0 deletions .gitattributes
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
14 changes: 13 additions & 1 deletion .gitignore
Expand Up @@ -42,6 +42,7 @@ dlldata.c

# DNX
project.lock.json
project.fragment.lock.json
artifacts/

*_i.c
Expand Down Expand Up @@ -142,7 +143,7 @@ publish/
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
#*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
Expand Down Expand Up @@ -188,6 +189,7 @@ ClientBin/
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
Expand Down Expand Up @@ -250,3 +252,13 @@ paket-files/
# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Custom ignores
/lib
77 changes: 77 additions & 0 deletions DeckTracker.Common/DeckTracker.Common.csproj
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8854D93E-999F-4F17-A60E-8627BC9695E4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DeckTracker</RootNamespace>
<AssemblyName>DeckTracker.Common</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\DeckTracker\Properties\AssemblyCommonInfo.cs">
<Link>Properties\AssemblyCommonInfo.cs</Link>
</Compile>
<Compile Include="Domain\CardAction.cs" />
<Compile Include="Domain\CompressionFormat.cs" />
<Compile Include="Domain\DeckClassifier.cs" />
<Compile Include="Domain\Eternal\Attribute.cs" />
<Compile Include="Domain\Eternal\Extensions\Extensions.cs" />
<Compile Include="Domain\Eternal\GameMode.cs" />
<Compile Include="Domain\Eternal\League.cs" />
<Compile Include="Domain\Eternal\Rarity.cs" />
<Compile Include="Domain\Eternal\Class.cs" />
<Compile Include="Domain\Eternal\Type.cs" />
<Compile Include="Domain\GameType.cs" />
<Compile Include="Domain\MessageType.cs" />
<Compile Include="Domain\NotifyObservableCollection.cs" />
<Compile Include="Domain\ObservableDictionary.cs" />
<Compile Include="Domain\ObservableSortedList.cs" />
<Compile Include="Domain\PlayerSide.cs" />
<Compile Include="Domain\SerializationFormat.cs" />
<Compile Include="Domain\TheElderScrollsLegends\Attribute.cs" />
<Compile Include="Domain\TheElderScrollsLegends\Class.cs" />
<Compile Include="Domain\TheElderScrollsLegends\Extensions\Extensions.cs" />
<Compile Include="Domain\TheElderScrollsLegends\SpecialRarity.cs" />
<Compile Include="Domain\TheElderScrollsLegends\Rarity.cs" />
<Compile Include="Domain\TheElderScrollsLegends\Type.cs" />
<Compile Include="Domain\TheElderScrollsLegends\GameMode.cs" />
<Compile Include="LowLevel\TaskHelpers.cs" />
<Compile Include="LowLevel\Zstd\ArraySegmentPtr.cs" />
<Compile Include="LowLevel\Zstd\Compressor.cs" />
<Compile Include="LowLevel\Zstd\Decompressor.cs" />
<Compile Include="LowLevel\Zstd\ExternMethods.cs" />
<Compile Include="LowLevel\Zstd\ThrowHelper.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="decktypes.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
17 changes: 17 additions & 0 deletions DeckTracker.Common/Domain/CardAction.cs
@@ -0,0 +1,17 @@
namespace DeckTracker.Domain
{
public enum CardAction : byte
{
Draw = 1,
Mulligan = 2,
Discard = 3,
Play = 4,
Die = 5,
ReturnToHand = 6,
ReturnToDeck = 7,
Resurrect = 8,
Attack = 9,
Block = 10,
Prophecy = 11
}
}
8 changes: 8 additions & 0 deletions DeckTracker.Common/Domain/CompressionFormat.cs
@@ -0,0 +1,8 @@
namespace DeckTracker.Domain
{
public enum CompressionFormat : byte
{
NoCompression = 0,
Zstandard = 1
}
}
162 changes: 162 additions & 0 deletions DeckTracker.Common/Domain/DeckClassifier.cs
@@ -0,0 +1,162 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;

namespace DeckTracker.Domain
{
public static class DeckClassifier
{
public class DeckAttributes
{
public string GameType;
public IDictionary<string, int> Colors = new Dictionary<string, int>();
public IDictionary<string, int> Cards = new Dictionary<string, int>();
public IDictionary<string, int> Words = new Dictionary<string, int>();
}

public class DeckDefinition
{
public string Name;
public MethodInfo Script;
public DeckDefinition Parent;
public int Level;
public readonly List<DeckDefinition> Subtypes = new List<DeckDefinition>();
}

private static DeckDefinition rootDeckDefinition;
private static FieldInfo gameTypeField;
private static MethodInfo setColorsMethod;
private static MethodInfo setCardsMethod;
private static MethodInfo setWordsMethod;

public static void Initialize()
{
var codeProvider = new CSharpCodeProvider();
var compilerParameters = new CompilerParameters {
GenerateInMemory = true,
TreatWarningsAsErrors = false,
WarningLevel = 4,
ReferencedAssemblies = {"System.dll", "System.Core.dll"}
};
var code = new StringBuilder();
code.AppendLine(@"
using System.Collections.Generic;
using System.Linq;
public static class DeckClassifier {
public class DeckSet<T> : Dictionary<T, int> {
public DeckSet() {}
public DeckSet(IDictionary<T, int> source) : base(source) {}
public bool Contains(params T[] values)
{
return values.All(ContainsKey);
}
public bool ContainsAny(params T[] values)
{
return ContainsAny(1, values);
}
public bool ContainsAny(int minCount, params T[] values)
{
return values.Count(ContainsKey) >= minCount;
}
}
public static string GameType;
public static DeckSet<string> Colors = new DeckSet<string>();
public static DeckSet<string> Cards = new DeckSet<string>();
public static DeckSet<string> Words = new DeckSet<string>();
public static void SetColors(IDictionary<string, int> colors) { Colors = new DeckSet<string>(colors); }
public static void SetCards(IDictionary<string, int> cards) { Cards = new DeckSet<string>(cards); }
public static void SetWords(IDictionary<string, int> words) { Words = new DeckSet<string>(words); }
public static bool IsDeck0() { return true; }
");

var rootDeckDefinition = new DeckDefinition {Name = "All Games"};
var deckDefinitions = new List<DeckDefinition> {rootDeckDefinition};
var deckTypes = "";
if (File.Exists(@"..\decktypes.txt")) deckTypes = File.ReadAllText(@"..\decktypes.txt");
else if (File.Exists(@"decktypes.txt")) deckTypes = File.ReadAllText(@"decktypes.txt");
using (var reader = new StringReader(deckTypes)) {
var currentLevel = -1;
var lastDeckDefinition = rootDeckDefinition;
var levels = new Stack<DeckDefinition>();
string line;
while ((line = reader.ReadLine()) != null) {
var level = line.TakeWhile(c => c == '|').Count();
var parts = line.Substring(level).Split(new[] {'|'}, 2);
if (level < 0 || level > currentLevel + 1 || parts.Length != 2)
throw new Exception("Invalid tree structure for deck: " + line);
if (level == currentLevel + 1) {
levels.Push(lastDeckDefinition);
currentLevel++;
}
while (level < currentLevel) {
levels.Pop();
currentLevel--;
}
code.AppendLine($" public static bool IsDeck{deckDefinitions.Count}() {{ return {parts[1]}; }}");
var deckDefinition = new DeckDefinition {Name = parts[0], Parent = levels.Peek(), Level = currentLevel};
deckDefinitions.Add(deckDefinition);
levels.Peek().Subtypes.Add(deckDefinition);
lastDeckDefinition = deckDefinition;
}
}
code.AppendLine("}");

var results = codeProvider.CompileAssemblyFromSource(compilerParameters, code.ToString());
if (!results.Errors.HasErrors) {
var assembly = results.CompiledAssembly;
var type = assembly.GetType("DeckClassifier");
gameTypeField = type.GetField("GameType", BindingFlags.Public | BindingFlags.Static);
setColorsMethod = type.GetMethod("SetColors", BindingFlags.Public | BindingFlags.Static);
setCardsMethod = type.GetMethod("SetCards", BindingFlags.Public | BindingFlags.Static);
setWordsMethod = type.GetMethod("SetWords", BindingFlags.Public | BindingFlags.Static);
for (int i = 0; i < deckDefinitions.Count; i++)
deckDefinitions[i].Script = type.GetMethod($"IsDeck{i}", BindingFlags.Public | BindingFlags.Static);
} else {
var errors = new StringBuilder();
foreach (CompilerError error in results.Errors)
errors.AppendLine($"Line number {error.Line}, Error Number: {error.ErrorNumber}, Error: {error.ErrorText}");
throw new Exception($"Unable to parse deck types: {errors}");
}

DeckClassifier.rootDeckDefinition = rootDeckDefinition;
}

public static DeckDefinition ClassifyDeck(DeckAttributes deck)
{
if (rootDeckDefinition == null) return null;
var matches = new Dictionary<int, List<DeckDefinition>>();
lock (rootDeckDefinition)
ClassifyDeck(deck, matches, rootDeckDefinition, 0);
return matches.OrderBy(match => match.Key).Last(match => match.Value.Count == 1).Value[0];
}

private static void ClassifyDeck(DeckAttributes deck, IDictionary<int, List<DeckDefinition>> matches, DeckDefinition deckDefinition, int level)
{
gameTypeField.SetValue(null, deck.GameType);
if (deck.Colors != null)
setColorsMethod.Invoke(null, new object[] {deck.Colors});
if (deck.Cards != null)
setCardsMethod.Invoke(null, new object[] {deck.Cards});
if (deck.Words != null)
setWordsMethod.Invoke(null, new object[] {deck.Words});
if (!(bool)deckDefinition.Script.Invoke(null, null)) return;
if (!matches.ContainsKey(level))
matches[level] = new List<DeckDefinition>();
if (!deckDefinition.Name.StartsWith("$"))
matches[level].Add(deckDefinition);
foreach (var subtype in deckDefinition.Subtypes)
ClassifyDeck(deck, matches, subtype, level + 1);
}
}
}

0 comments on commit 37a1379

Please sign in to comment.