Skip to content

Commit 439c815

Browse files
author
Marcus Beranek
committed
Added blackboard pattern demo
1 parent 0ac8957 commit 439c815

19 files changed

+619
-0
lines changed

BlackBoardDemo/BlackBoardDemo.sln

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30804.86
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlackBoardDemo", "BlackBoardDemo\BlackBoardDemo.csproj", "{F2D444C7-69FF-46F3-BA5D-6A48558744E1}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlackBoardDemoTests", "BlackBoardDemoTests\BlackBoardDemoTests.csproj", "{1F99C870-7849-4758-A7D5-343B87302E43}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{F2D444C7-69FF-46F3-BA5D-6A48558744E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{F2D444C7-69FF-46F3-BA5D-6A48558744E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{F2D444C7-69FF-46F3-BA5D-6A48558744E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{F2D444C7-69FF-46F3-BA5D-6A48558744E1}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{1F99C870-7849-4758-A7D5-343B87302E43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{1F99C870-7849-4758-A7D5-343B87302E43}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{1F99C870-7849-4758-A7D5-343B87302E43}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{1F99C870-7849-4758-A7D5-343B87302E43}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {CC4CB7D3-E156-4044-B38E-77014119C7EA}
30+
EndGlobalSection
31+
EndGlobal
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace BlackBoardDemo
4+
{
5+
public class Analyzer
6+
{
7+
public virtual ProblemState Analyze(Problem problem)
8+
{ throw new NotImplementedException(); }
9+
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
3+
namespace BlackBoardDemo.Analyzers
4+
{
5+
public class SortAnalyser : Analyzer
6+
{
7+
public override ProblemState Analyze(Problem problem)
8+
{
9+
10+
var data = problem.Data as int[];
11+
12+
if (data == null)
13+
{
14+
return ProblemState.UnSolvable;
15+
}
16+
else if (data.Length == 0 || data.Length == 1)
17+
{
18+
return ProblemState.Solved;
19+
}
20+
else
21+
{
22+
for (var i = 0; i < data.Length - 1; i++)
23+
{
24+
if (data[i] > data[i + 1])
25+
{
26+
return ProblemState.NeedsSorting;
27+
}
28+
}
29+
30+
return ProblemState.Solved;
31+
}
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BlackBoardDemo
8+
{
9+
public class BlackBoard
10+
{
11+
public Problem InputProblem { get; set; }
12+
13+
public Problem CurrentSolution { get; set; }
14+
15+
public List<Problem> PartialSolutions { get; set; } = new List<Problem>();
16+
public Analyzer ProblemAnalyzer { get; set; }
17+
18+
public void Analyze()
19+
{
20+
if(CurrentSolution != null)
21+
{
22+
CurrentSolution.State = ProblemAnalyzer.Analyze(CurrentSolution);
23+
}
24+
25+
foreach (var solutionPart in PartialSolutions)
26+
{
27+
if(solutionPart.State == ProblemState.Solved)
28+
{
29+
solutionPart.State = ProblemAnalyzer.Analyze(solutionPart);
30+
}
31+
}
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
</PropertyGroup>
7+
8+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace BlackBoardDemo
5+
{
6+
public class Controller
7+
{
8+
private BlackBoard _blackBoard;
9+
private KnowledgeBase _knowlegdeBase;
10+
public Controller(BlackBoard board, KnowledgeBase kb)
11+
{
12+
_blackBoard = board;
13+
_knowlegdeBase = kb;
14+
}
15+
16+
public void Run()
17+
{
18+
if(!_blackBoard.PartialSolutions.Any())
19+
{
20+
_blackBoard.PartialSolutions.Insert(0,_blackBoard.InputProblem);
21+
}
22+
23+
while(_blackBoard.PartialSolutions.Any( p => p.State != ProblemState.Solved))
24+
{
25+
var p = _blackBoard.PartialSolutions.First(p => p.State != ProblemState.Solved);
26+
_blackBoard.PartialSolutions.Remove(p);
27+
28+
var solver = _knowlegdeBase.FindSolverFor(p);
29+
var solutionParts = solver.Solve(p);
30+
31+
_blackBoard.PartialSolutions.InsertRange(0,solutionParts);
32+
33+
_blackBoard.Analyze();
34+
}
35+
36+
var result = new Problem() { Data = new int[0], State = ProblemState.Solved};
37+
foreach(var part in _blackBoard.PartialSolutions)
38+
{
39+
var problem = new Problem()
40+
{
41+
Data = new Tuple<Problem, Problem>(result, part),
42+
State = ProblemState.NeedsIntegration
43+
};
44+
45+
var merger = _knowlegdeBase.FindSolverFor(problem);
46+
result = merger.Solve(problem).Single();
47+
}
48+
49+
_blackBoard.CurrentSolution = result;
50+
_blackBoard.Analyze();
51+
}
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Collections.Generic;
2+
3+
namespace BlackBoardDemo
4+
{
5+
public class EmptyProblemSolver : ProblemSolver
6+
{
7+
public EmptyProblemSolver()
8+
{
9+
10+
}
11+
12+
public override bool CanSolve(Problem problem)
13+
{
14+
return false;
15+
}
16+
17+
public override IEnumerable<Problem> Solve(Problem input)
18+
{
19+
return new[] { input };
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace BlackBoardDemo
6+
{
7+
public class KnowledgeBase
8+
{
9+
public List<ProblemSolver> ProblemSolvers { get; set; } = new List<ProblemSolver>();
10+
11+
public ProblemSolver FindSolverFor(Problem input)
12+
{
13+
ProblemSolver foundSolver = null;
14+
foreach (var solver in ProblemSolvers)
15+
{
16+
if (solver.CanSolve(input))
17+
{
18+
foundSolver = solver;
19+
}
20+
}
21+
22+
return foundSolver;
23+
}
24+
}
25+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace BlackBoardDemo
2+
{
3+
using Analyzers;
4+
using System;
5+
6+
public class MergeSort
7+
{
8+
public int[] Sort(int[] input)
9+
{
10+
var problem = new Problem();
11+
problem.State = ProblemState.NeedsSorting;
12+
problem.Data = input;
13+
14+
// Push problem to a blackboard:
15+
var blackBoard = new BlackBoard();
16+
blackBoard.InputProblem = problem;
17+
blackBoard.ProblemAnalyzer = new SortAnalyser();
18+
19+
// Set up a knoledgebase of all things, that we can do:
20+
var kb = new KnowledgeBase();
21+
kb.ProblemSolvers.Add(new Solvers.Splitter());
22+
kb.ProblemSolvers.Add(new Solvers.Merger());
23+
kb.ProblemSolvers.Add(new Solvers.Sorter());
24+
25+
// Add a controller to find a solution:
26+
var controller = new Controller(blackBoard, kb);
27+
controller.Run();
28+
29+
return blackBoard.CurrentSolution.Data as int[];
30+
}
31+
}
32+
}
33+
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace BlackBoardDemo
5+
{
6+
public class Problem
7+
{
8+
public ProblemState State { get; set; }
9+
10+
public object Data { get; set; }
11+
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace BlackBoardDemo
6+
{
7+
public class ProblemSolver
8+
{
9+
public static ProblemSolver Empty = new EmptyProblemSolver();
10+
public virtual bool CanSolve(Problem input)
11+
{
12+
throw new NotImplementedException();
13+
}
14+
15+
public virtual IEnumerable<Problem> Solve(Problem input)
16+
{
17+
throw new NotImplementedException();
18+
}
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace BlackBoardDemo
5+
{
6+
public enum ProblemState { Solved, NeedsSorting, NeedsIntegration, TooBig, UnSolvable }
7+
}
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
namespace BlackBoardDemo
2+
{
3+
using System;
4+
using Analyzers;
5+
6+
public class Program
7+
{
8+
static void Main(string[] args)
9+
{
10+
int length = 1000;
11+
12+
if(args.Length > 0)
13+
{
14+
int cmdArg;
15+
16+
if(int.TryParse(args[0], out cmdArg))
17+
{
18+
length = cmdArg;
19+
}
20+
}
21+
22+
Random rng = new Random((int)(DateTime.UtcNow.Ticks));
23+
var input = new int[length];
24+
for (int i = 0; i < length; i++)
25+
{
26+
input[i] = rng.Next();
27+
}
28+
29+
var mergesort = new MergeSort();
30+
var sorted = mergesort.Sort(input);
31+
32+
if (length <= 20)
33+
{
34+
Console.WriteLine("Input:");
35+
for(int i = 0; i < length; i++)
36+
{
37+
Console.WriteLine(input[i]);
38+
}
39+
40+
Console.WriteLine();
41+
Console.WriteLine("Sorted:");
42+
for (int i = 0; i < length; i++)
43+
{
44+
Console.WriteLine(sorted[i]);
45+
}
46+
}
47+
else
48+
{
49+
Console.WriteLine($"Sorted {length} items");
50+
}
51+
52+
Console.ReadLine();
53+
}
54+
}
55+
}
56+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"profiles": {
3+
"BlackBoardDemo": {
4+
"commandName": "Project",
5+
"commandLineArgs": "20"
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)