Browse Source

init

master
Robin Thoni 7 years ago
commit
01faca2c36

+ 76
- 0
.gitignore View File

@@ -0,0 +1,76 @@
1
+*.swp
2
+*.*~
3
+project.lock.json
4
+.DS_Store
5
+*.pyc
6
+
7
+# Visual Studio Code
8
+.vscode
9
+
10
+# User-specific files
11
+*.suo
12
+*.user
13
+*.userosscache
14
+*.sln.docstates
15
+
16
+# Build results
17
+[Dd]ebug/
18
+[Dd]ebugPublic/
19
+[Rr]elease/
20
+[Rr]eleases/
21
+x64/
22
+x86/
23
+build/
24
+bld/
25
+[Bb]in/
26
+[Oo]bj/
27
+msbuild.log
28
+msbuild.err
29
+msbuild.wrn
30
+
31
+# Visual Studio 2015
32
+.vs/
33
+
34
+
35
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
36
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
37
+
38
+# User-specific stuff:
39
+.idea/**/workspace.xml
40
+.idea/**/tasks.xml
41
+
42
+# Sensitive or high-churn files:
43
+.idea/**/dataSources/
44
+.idea/**/dataSources.ids
45
+.idea/**/dataSources.xml
46
+.idea/**/dataSources.local.xml
47
+.idea/**/sqlDataSources.xml
48
+.idea/**/dynamic.xml
49
+.idea/**/uiDesigner.xml
50
+
51
+# Gradle:
52
+.idea/**/gradle.xml
53
+.idea/**/libraries
54
+
55
+# Mongo Explorer plugin:
56
+.idea/**/mongoSettings.xml
57
+
58
+## File-based project format:
59
+*.iws
60
+
61
+## Plugin-specific files:
62
+
63
+# IntelliJ
64
+/out/
65
+
66
+# mpeltonen/sbt-idea plugin
67
+.idea_modules/
68
+
69
+# JIRA plugin
70
+atlassian-ide-plugin.xml
71
+
72
+# Crashlytics plugin (for Android Studio and IntelliJ)
73
+com_crashlytics_export_strings.xml
74
+crashlytics.properties
75
+crashlytics-build.properties
76
+fabric.properties

+ 6
- 0
.idea/.idea.uqac-ia-sudoku-csp/.idea/contentModel.xml View File

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="RiderRiderContentModelStore">
4
+    <excludedPaths />
5
+  </component>
6
+</project>

+ 8
- 0
.idea/.idea.uqac-ia-sudoku-csp/.idea/modules.xml View File

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ProjectModuleManager">
4
+    <modules>
5
+      <module fileurl="file://$PROJECT_DIR$/.idea/.idea.uqac-ia-sudoku-csp/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.uqac-ia-sudoku-csp/riderModule.iml" />
6
+    </modules>
7
+  </component>
8
+</project>

+ 12
- 0
.idea/.idea.uqac-ia-sudoku-csp/riderModule.iml View File

@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<module type="RIDER_MODULE" version="4">
3
+  <component name="NewModuleRootManager">
4
+    <content url="file://$MODULE_DIR$/../..">
5
+      <sourceFolder url="file://$MODULE_DIR$/../../uqac-ia-sudoku-csp" isTestSource="false" />
6
+      <excludeFolder url="file://$MODULE_DIR$/../../packages" />
7
+      <excludeFolder url="file://$MODULE_DIR$/../../uqac-ia-sudoku-csp/bin" />
8
+      <excludeFolder url="file://$MODULE_DIR$/../../uqac-ia-sudoku-csp/obj" />
9
+    </content>
10
+    <orderEntry type="sourceFolder" forTests="false" />
11
+  </component>
12
+</module>

+ 9
- 0
sample/01.txt View File

@@ -0,0 +1,9 @@
1
+003020600
2
+900305001
3
+001806400
4
+008102900
5
+700000008
6
+006708200
7
+002609500
8
+800203009
9
+005010300

+ 9
- 0
sample/02.txt View File

@@ -0,0 +1,9 @@
1
+200080300
2
+060070084
3
+030500209
4
+000105408
5
+000000000
6
+402706000
7
+301007040
8
+720040060
9
+004010003

+ 9
- 0
sample/03.txt View File

@@ -0,0 +1,9 @@
1
+000000907
2
+000420180
3
+000705026
4
+100904000
5
+050000040
6
+000507009
7
+920108000
8
+034059000
9
+507000000

+ 22
- 0
uqac-ia-sudoku-csp.sln View File

@@ -0,0 +1,22 @@
1
+
2
+Microsoft Visual Studio Solution File, Format Version 12.00
3
+# Visual Studio 2013
4
+VisualStudioVersion = 12.0.0.0
5
+MinimumVisualStudioVersion = 10.0.0.1
6
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "uqac_ia_sudoku_csp", "uqac-ia-sudoku-csp/uqac-ia-sudoku-csp.xproj", "{77FF317D-6818-4E89-9981-919B301FBA76}"
7
+EndProject
8
+Global
9
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
10
+		Debug|Any CPU = Debug|Any CPU
11
+		Release|Any CPU = Release|Any CPU
12
+	EndGlobalSection
13
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
14
+		{77FF317D-6818-4E89-9981-919B301FBA76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15
+		{77FF317D-6818-4E89-9981-919B301FBA76}.Debug|Any CPU.Build.0 = Debug|Any CPU
16
+		{77FF317D-6818-4E89-9981-919B301FBA76}.Release|Any CPU.ActiveCfg = Release|Any CPU
17
+		{77FF317D-6818-4E89-9981-919B301FBA76}.Release|Any CPU.Build.0 = Release|Any CPU
18
+	EndGlobalSection
19
+	GlobalSection(SolutionProperties) = preSolution
20
+		HideSolutionNode = FALSE
21
+	EndGlobalSection
22
+EndGlobal

+ 113
- 0
uqac-ia-sudoku-csp/Board.cs View File

@@ -0,0 +1,113 @@
1
+using System;
2
+using System.IO;
3
+using System.Linq;
4
+
5
+namespace uqac_ia_sudoku_csp
6
+{
7
+    public class Board
8
+    {
9
+        public string Characters { get; }
10
+
11
+        public int Size => Game.Length;
12
+
13
+        protected int?[][] Game { get; set; }
14
+
15
+        public Board(string characters)
16
+        {
17
+            Characters = characters;
18
+            InitGame(characters.Length);
19
+            Init((x, y) => null);
20
+        }
21
+
22
+        public Board(string characters, Func<int, int, int?> cb)
23
+        {
24
+            Characters = characters;
25
+            InitGame(characters.Length);
26
+            Init(cb);
27
+        }
28
+
29
+        public Board(Board other)
30
+        {
31
+            Characters = other.Characters;
32
+            InitGame(other.Size);
33
+            Init(other.GetNumber);
34
+        }
35
+
36
+        public Board Clone()
37
+        {
38
+            return new Board(this);
39
+        }
40
+
41
+        protected void InitGame(int size)
42
+        {
43
+            Game = new int?[size][];
44
+            for (var y = 0; y < size; ++y)
45
+            {
46
+                Game[y] = new int?[size];
47
+            }
48
+        }
49
+
50
+        public void Init(Func<int, int, int?> cb)
51
+        {
52
+            for (var y = 0; y < Size; ++y)
53
+            {
54
+                for (var x = 0; x < Size; ++x)
55
+                {
56
+                    SetNumber(x, y, cb(x, y));
57
+                }
58
+            }
59
+        }
60
+
61
+        public char? GetCharacter(int? v)
62
+        {
63
+            return v == null ? null : (char?)Characters[v.Value];
64
+        }
65
+
66
+        public char? GetCharacter(int x, int y)
67
+        {
68
+            return GetCharacter(GetNumber(x, y));
69
+        }
70
+
71
+        public void SetCharacter(int x, int y, char? c)
72
+        {
73
+            SetNumber(x, y, c == null ? null : (char?)Characters.IndexOf(c.Value));
74
+        }
75
+
76
+        public int? GetNumber(int x, int y)
77
+        {
78
+            return Game[y][x];
79
+        }
80
+
81
+        public void SetNumber(int x, int y, int? value)
82
+        {
83
+            Game[y][x] = value;
84
+        }
85
+
86
+        public void ClearNumber(int x, int y)
87
+        {
88
+            SetNumber(x, y, null);
89
+        }
90
+
91
+        public bool IsComplete()
92
+        {
93
+            return !Game.Any(line => line.Any(cell => cell == null));
94
+        }
95
+
96
+        public void Print(TextWriter stream)
97
+        {
98
+            stream.WriteLine(Characters);
99
+            stream.WriteLine(new string('-', Size + 2));
100
+            foreach (var line in Game)
101
+            {
102
+                stream.Write('|');
103
+                foreach (var cell in line)
104
+                {
105
+                    var c = GetCharacter(cell);
106
+                    stream.Write(c ?? ' ');
107
+                }
108
+                stream.WriteLine('|');
109
+            }
110
+            stream.WriteLine(new string('-', Size + 2));
111
+        }
112
+    }
113
+}

+ 7
- 0
uqac-ia-sudoku-csp/Interfaces/IConstraint.cs View File

@@ -0,0 +1,7 @@
1
+namespace uqac_ia_sudoku_csp.Interfaces
2
+{
3
+    public interface IConstraint
4
+    {
5
+        bool Check(Board board, int x, int y);
6
+    }
7
+}

+ 7
- 0
uqac-ia-sudoku-csp/Interfaces/IGenerator.cs View File

@@ -0,0 +1,7 @@
1
+namespace uqac_ia_sudoku_csp.Interfaces
2
+{
3
+    public interface IGenerator
4
+    {
5
+        void Generate(Board board, object data);
6
+    }
7
+}

+ 7
- 0
uqac-ia-sudoku-csp/Interfaces/INextValueChooser.cs View File

@@ -0,0 +1,7 @@
1
+namespace uqac_ia_sudoku_csp.Interfaces
2
+{
3
+    public interface INextValueChooser
4
+    {
5
+        void SelectVariable(Board board, out int x, out int y);
6
+    }
7
+}

+ 7
- 0
uqac-ia-sudoku-csp/Interfaces/ISolver.cs View File

@@ -0,0 +1,7 @@
1
+namespace uqac_ia_sudoku_csp.Interfaces
2
+{
3
+    public interface ISolver
4
+    {
5
+        bool Resolve(Board board);
6
+    }
7
+}

+ 35
- 0
uqac-ia-sudoku-csp/Program.cs View File

@@ -0,0 +1,35 @@
1
+using System;
2
+using uqac_ia_sudoku_csp.Solver;
3
+using uqac_ia_sudoku_csp.Solver.Generators;
4
+
5
+namespace uqac_ia_sudoku_csp
6
+{
7
+    internal class Program
8
+    {
9
+        public static void Main(string[] args)
10
+        {
11
+            var board = new Board("123456789");
12
+
13
+            var generator = new FileGenerator();
14
+            generator.Generate(board, new FileGeneratorDbo
15
+            {
16
+                EmptyCharacters = "0 ",
17
+                FilePath = "../sample/03.txt"
18
+            });
19
+            board.Print(Console.Out);
20
+
21
+            var solver = new BacktrackSearch();
22
+            var resolved = solver.Resolve(board);
23
+
24
+            if (resolved)
25
+            {
26
+                Console.WriteLine("Resolved:");
27
+                board.Print(Console.Out);
28
+            }
29
+            else
30
+            {
31
+                Console.WriteLine("Not resolved");
32
+            }
33
+        }
34
+    }
35
+}

+ 26
- 0
uqac-ia-sudoku-csp/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,26 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+
9
+[assembly: AssemblyTitle("uqac_ia_sudoku_csp")]
10
+[assembly: AssemblyDescription("")]
11
+[assembly: AssemblyConfiguration("")]
12
+[assembly: AssemblyCompany("")]
13
+[assembly: AssemblyProduct("uqac_ia_sudoku_csp")]
14
+[assembly: AssemblyCopyright("Copyright ©  2017")]
15
+[assembly: AssemblyTrademark("")]
16
+[assembly: AssemblyCulture("")]
17
+
18
+// Setting ComVisible to false makes the types in this assembly not visible
19
+// to COM components.  If you need to access a type in this assembly from
20
+// COM, set the ComVisible attribute to true on that type.
21
+
22
+[assembly: ComVisible(false)]
23
+
24
+// The following GUID is for the ID of the typelib if this project is exposed to COM
25
+
26
+[assembly: Guid("77FF317D-6818-4E89-9981-919B301FBA76")]

+ 79
- 0
uqac-ia-sudoku-csp/Solver/BacktrackSearch.cs View File

@@ -0,0 +1,79 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using uqac_ia_sudoku_csp.Interfaces;
5
+using uqac_ia_sudoku_csp.Solver.Constraints;
6
+
7
+namespace uqac_ia_sudoku_csp.Solver
8
+{
9
+    public class BacktrackSearch : ISolver
10
+    {
11
+        protected IList<IConstraint> Constraints;
12
+
13
+        public BacktrackSearch()
14
+        {
15
+            Constraints = new List<IConstraint>
16
+            {
17
+                new LineContraint(),
18
+                new ColumnConstraint(),
19
+                new BlockConstraint()
20
+            };
21
+        }
22
+
23
+        public bool Resolve(Board board)
24
+        {
25
+            return RecursiveResolve(board);
26
+        }
27
+
28
+        protected bool RecursiveResolve(Board board)
29
+        {
30
+            if (board.IsComplete())
31
+            {
32
+                return true;
33
+            }
34
+            int x, y;
35
+            SelectVariable(board, out x, out y);
36
+            foreach (var value in GetDomainValues(board))
37
+            {
38
+                board.SetNumber(x, y, value);
39
+                if (IsConsistent(board, x, y))
40
+                {
41
+                    if (RecursiveResolve(board))
42
+                    {
43
+                        return true;
44
+                    }
45
+                }
46
+            }
47
+            board.ClearNumber(x, y);
48
+            return false;
49
+        }
50
+
51
+        protected void SelectVariable(Board board, out int x, out int y)
52
+        {
53
+            for (var xx = 0; xx < board.Size; ++xx)
54
+            {
55
+                for (var yy = 0; yy < board.Size; ++yy)
56
+                {
57
+                    if (board.GetNumber(xx, yy) == null)
58
+                    {
59
+                        x = xx;
60
+                        y = yy;
61
+                        return;
62
+                    }
63
+                }
64
+            }
65
+            x = -1;
66
+            y = -1;
67
+        }
68
+
69
+        protected IEnumerable<int> GetDomainValues(Board board)
70
+        {
71
+            return Enumerable.Range(0, board.Size);
72
+        }
73
+
74
+        protected bool IsConsistent(Board board, int x, int y)
75
+        {
76
+            return Constraints.All(constraint => constraint.Check(board, x, y));
77
+        }
78
+    }
79
+}

+ 27
- 0
uqac-ia-sudoku-csp/Solver/Constraints/BlockConstraint.cs View File

@@ -0,0 +1,27 @@
1
+using System;
2
+using uqac_ia_sudoku_csp.Interfaces;
3
+
4
+namespace uqac_ia_sudoku_csp.Solver.Constraints
5
+{
6
+    public class BlockConstraint : IConstraint
7
+    {
8
+        public bool Check(Board board, int x, int y)
9
+        {
10
+            var bs = Math.Sqrt(board.Size);
11
+            var sx = x / 3 * 3;
12
+            var sy = y / 3 * 3;
13
+            var cell = board.GetNumber(x, y).Value;
14
+            for (var xx = sx; xx < sx + bs; ++xx)
15
+            {
16
+                for (var yy = sy; yy < sy + bs; ++yy)
17
+                {
18
+                    if (cell == board.GetNumber(xx, yy) && (xx != x || yy != y))
19
+                    {
20
+                        return false;
21
+                    }
22
+                }
23
+            }
24
+            return true;
25
+        }
26
+    }
27
+}

+ 20
- 0
uqac-ia-sudoku-csp/Solver/Constraints/ColumnConstraint.cs View File

@@ -0,0 +1,20 @@
1
+using uqac_ia_sudoku_csp.Interfaces;
2
+
3
+namespace uqac_ia_sudoku_csp.Solver.Constraints
4
+{
5
+    public class ColumnConstraint : IConstraint
6
+    {
7
+        public bool Check(Board board, int x, int y)
8
+        {
9
+            var cell = board.GetNumber(x, y).Value;
10
+            for (var yy = 0; yy < board.Size; ++yy)
11
+            {
12
+                if (cell == board.GetNumber(x, yy) && yy != y)
13
+                {
14
+                    return false;
15
+                }
16
+            }
17
+            return true;
18
+        }
19
+    }
20
+}

+ 20
- 0
uqac-ia-sudoku-csp/Solver/Constraints/LineContraint.cs View File

@@ -0,0 +1,20 @@
1
+using uqac_ia_sudoku_csp.Interfaces;
2
+
3
+namespace uqac_ia_sudoku_csp.Solver.Constraints
4
+{
5
+    public class LineContraint : IConstraint
6
+    {
7
+        public bool Check(Board board, int x, int y)
8
+        {
9
+            var cell = board.GetNumber(x, y).Value;
10
+            for (var xx = 0; xx < board.Size; ++xx)
11
+            {
12
+                if (cell == board.GetNumber(xx, y) && xx != x)
13
+                {
14
+                    return false;
15
+                }
16
+            }
17
+            return true;
18
+        }
19
+    }
20
+}

+ 10
- 0
uqac-ia-sudoku-csp/Solver/Generator.cs View File

@@ -0,0 +1,10 @@
1
+namespace uqac_ia_sudoku_csp
2
+{
3
+    public class Generator
4
+    {
5
+        public void Generate(Board board, object data)
6
+        {
7
+//            board.SetNumber(0, 0, 0);
8
+        }
9
+    }
10
+}

+ 11
- 0
uqac-ia-sudoku-csp/Solver/Generators/EmptyGenerator.cs View File

@@ -0,0 +1,11 @@
1
+using uqac_ia_sudoku_csp.Interfaces;
2
+
3
+namespace uqac_ia_sudoku_csp.Solver.Generators
4
+{
5
+    public class EmptyGenerator : IGenerator
6
+    {
7
+        public void Generate(Board board, object data)
8
+        {
9
+        }
10
+    }
11
+}

+ 27
- 0
uqac-ia-sudoku-csp/Solver/Generators/FileGenerator.cs View File

@@ -0,0 +1,27 @@
1
+using System.IO;
2
+
3
+namespace uqac_ia_sudoku_csp.Solver.Generators
4
+{
5
+    public class FileGeneratorDbo
6
+    {
7
+        public string FilePath { get; set; }
8
+
9
+        public string EmptyCharacters { get; set; }
10
+    }
11
+
12
+    public class FileGenerator : TextReaderGenerator
13
+    {
14
+        public override void Generate(Board board, object data)
15
+        {
16
+            var dbo = data as FileGeneratorDbo;
17
+            using (var stream = File.OpenText(dbo.FilePath))
18
+            {
19
+                base.Generate(board, new TextReaderGeneratorDbo
20
+                {
21
+                    EmptyCharacters = dbo.EmptyCharacters,
22
+                    Reader = stream
23
+                });
24
+            }
25
+        }
26
+    }
27
+}

+ 16
- 0
uqac-ia-sudoku-csp/Solver/Generators/StdInGenerator.cs View File

@@ -0,0 +1,16 @@
1
+using System;
2
+
3
+namespace uqac_ia_sudoku_csp.Solver.Generators
4
+{
5
+    public class StdInGenerator : TextReaderGenerator
6
+    {
7
+        public override void Generate(Board board, object data)
8
+        {
9
+            base.Generate(board, new TextReaderGeneratorDbo
10
+            {
11
+                Reader = Console.In,
12
+                EmptyCharacters = data as string
13
+            });
14
+        }
15
+    }
16
+}

+ 39
- 0
uqac-ia-sudoku-csp/Solver/Generators/TextReaderGenerator.cs View File

@@ -0,0 +1,39 @@
1
+using System.IO;
2
+using uqac_ia_sudoku_csp.Interfaces;
3
+
4
+namespace uqac_ia_sudoku_csp.Solver.Generators
5
+{
6
+    public class TextReaderGeneratorDbo
7
+    {
8
+        public TextReader Reader { get; set; }
9
+
10
+        public string EmptyCharacters { get; set; }
11
+    }
12
+
13
+    public class TextReaderGenerator : IGenerator
14
+    {
15
+        public virtual void Generate(Board board, object data)
16
+        {
17
+            var dbo = data as TextReaderGeneratorDbo;
18
+            for (var y = 0; y < board.Size; ++y)
19
+            {
20
+                for (var x = 0; x < board.Size; ++x)
21
+                {
22
+                    string c;
23
+                    do
24
+                    {
25
+                        c = $"{(char)dbo.Reader.Read()}";
26
+                    } while (!dbo.EmptyCharacters.Contains(c) && !board.Characters.Contains(c));
27
+                    if (dbo.EmptyCharacters.Contains(c))
28
+                    {
29
+                        board.ClearNumber(x, y);
30
+                    }
31
+                    else if (board.Characters.Contains(c))
32
+                    {
33
+                        board.SetCharacter(x, y, c[0]);
34
+                    }
35
+                }
36
+            }
37
+        }
38
+    }
39
+}

+ 19
- 0
uqac-ia-sudoku-csp/project.json View File

@@ -0,0 +1,19 @@
1
+{
2
+  "version": "1.0.0-*",
3
+  "buildOptions": {
4
+    "debugType": "portable",
5
+    "emitEntryPoint": true
6
+  },
7
+  "dependencies": {},
8
+  "frameworks": {
9
+    "netcoreapp1.0": {
10
+      "dependencies": {
11
+        "Microsoft.NETCore.App": {
12
+          "type": "platform",
13
+          "version": "1.0.1"
14
+        }
15
+      },
16
+      "imports": "dnxcore50"
17
+    }
18
+  }
19
+}

+ 22
- 0
uqac-ia-sudoku-csp/uqac-ia-sudoku-csp.xproj View File

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <PropertyGroup>
4
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6
+  </PropertyGroup>
7
+
8
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''"  />
9
+  <PropertyGroup Label="Globals">
10
+    <ProjectGuid>{77FF317D-6818-4E89-9981-919B301FBA76}</ProjectGuid>
11
+    <ProjectTypeGuids>{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}</ProjectTypeGuids>
12
+    <RootNamespace>uqac_ia_sudoku_csp</RootNamespace>
13
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
14
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
15
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
16
+  </PropertyGroup>
17
+
18
+  <PropertyGroup>
19
+    <SchemaVersion>2.0</SchemaVersion>
20
+  </PropertyGroup>
21
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
22
+</Project>

Loading…
Cancel
Save