SlideShare a Scribd company logo
1 of 59
Download to read offline
PORTFOLIO THREE
Examples of work in later 201x’s
CHRIS WORLEDGE
27th August 2018
1
STRS Retrievals App [MVC 5 asp.net C# jQuery] Page 2
Performance of Parallel Processing Page 6
X-Ray Image Processing Page 12
Unit Tested Maths Functions Page 18
Maze Solving Application Page 21
Text Matching Page 36
FizzBuzz Test with Unit Tests Page 39
Fibonacci Sequence [plain and with yield return IEnumerable] Page 46
WebAPI2 With Dependency Injection Page 49
2
Purpose
The Transfers Application provides a streamlined means of recording, updating, and managing the
data associated with patient transfers conducted by the South Thames Retrieval Service. It also
provides an instant overview of current and previous activity, with the opportunity for drill down.
Data
The data used with the Transfers Application is stored in an MS SQL Server relational database. It
holds information on each transfer activity, and a table of outcomes, used to provide data to a drop-
down control on the Create and Edit pages. This ensures users select from approved outcomes.
The data associated with transfers is:
NHS Number Stored as a 12 character Unicode string [nchar(12)] as the ten digit number must be
split with two spaces.
Referral Date Autogenerated DateTime stamp to the nearest second, on initial submission of
information. [SmallDateTime]
Patient Name Character string
Age An integer representing age in whole years.
Age-Months An integer representing the number of months after the age years.
Date of Birth A date picker is provided which allows the year and month to be selected from drop-
downs, and the day from the range for that month.
Diagnosis Character string
Referring Hospital The start point for the transfer as a character string.
Last Contact Date The date of last contact with the patient. A date picker is provided which
allows the year and month to be selected from drop-downs, and the day from the range for that
month.
Last Contact Time The time of last contact with the patient. A time picker is provided with
separate controls for hour and minutes
The Last Contact Date and Last Contact Time are stored in a single SmallDateTime in the database.
Outcome Selected from a list, including destinations and remaining at DGH. Character String.
Date Closed The date the retrieval was closed. A date picker is provided which allows the year
and month to be selected from drop-downs, and the day from the range for that month.
Time Closed The time the retrieval was closed. A date picker is provided which allows the year
and month to be selected from drop-downs, and the day from the range for that month.
The Date Closed and Time Closed are stored in a single SmallDateTime in the database.
3
Pages
The home or Index page is decorated with both Evalina and GSTT logos, as well as a picture of a
retrieval ambulance used by the service. It provides access to Create a new record, as well as a listing
of existing records, split in tabs to provide all records, just open activity, and just closed activity.
The listings each provide access to Details and Edit pages.
The Create Page
This page allows a new record to be generated, with an auto generated date time stamp, NHS
Number (required) Patient Name (required) Date of Birth(date-picker, required) Age in Years and
Months are generated from the date of birth.
The input fields:
Setting up a ten year old:
If they are sixteen days short of the threshold:
4
But only fifteen days short is rounded up:
And in the middle of the year:
Following this the Diagnosis (required) will accept text and offer auto complete, and will be tested
against the auto-complete source table. After the referral area is selected from the drop-down, the
referral hospital Drop-Down is populated and displayed.
The Details Page
This page is designed to give a complete breakdown of the transfer record. It is anticipated this
would be used to provide clarification of details absent from the main listings pages
The Edit Page
This page displays an existing listing for edit. The validation rules match the Create page.
It is envisaged that this will be used to provide additional information such as contact date;
outcome; and date/time closed.
Validation
NHS Number The modulus eleven algorithm is used to validate the NHS number by calculating it’s
outcome from the first nine digits (after removing the spaces) and comparing it with the tenth. A
failure will result in a message asking the user to check the NHS Number as it is not valid. The
validation overlooks entries of ten nines as this is used where the real NHS Number is not known.
Referral Date As this is auto generated, it requires no validation. It is displayed on the Edit page,
but is not editable.
Patient Name Validation is limited to a string being required.
Age The Age field stores an integer which will have an initial population generated from the
D.O.B. This is editable, and a range will be required.
Date of Birth As this is generated from a date picker it does not need validating.
Diagnosis Tested against look-up table used to supply auto-complete feature.
Area Drop-Down list of areas.
5
Referring Hospital Drop-Down list based on area selected.
Last Contact Date This is populated using a date-picker, so it’s validation is limited to a high
level check that it has a time as well if it is not empty, and it falls between Referral Date and Closed
Date.
Last Contact Time This is populated using a time-picker, so it’s validation is limited to a high
level check that it has a date as well if it is not empty, and it falls between Referral Date and Closed
Date.
Outcome Populated from a drop-down so validation is limited to being required if the Date
Closed is set.
Date Closed This is populated using a date-picker, so it’s validation is limited to a high level check
that it has a time as well if it is not empty, and it falls after the Referral Date and the Last Contact
Date.
Time Closed This is populated using a time-picker, so it’s validation is limited to a high level check
that it has a date as well if it is not empty, and it falls after Referral Time and Last Contact Time.
Rationale
Minimal Database Table Count
The premise for this approach is that each retrieval will only be considered in isolation. This would
minimise requirement for relational organisation. It may be necessary to consider some re-
organisation of the data to allow more manipulation of records if the usage is expanded.
Transient Data
It is not usual for computer systems to store transient information as it quickly becomes invalid.
Usually only date of birth would be stored, and age calculated when required, to ensure it is current.
The storing of age values is considered appropriate to this particular case for two reasons:
1. Whilst the retrieval is open.
Retrievals are short lived activities, so it would be anticipated that an age calculated at the time of
referral will remain valid during the time the retrieval is open
2. Review of historic records.
When viewing closed retrievals some time later, the viewer will not require the age of the patient at
the time of viewing. The age which will be salient for them is the age at the time of the retrieval, so
the one stored will be appropriate then as well.
6
The system processes Widgets:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WidgetProcessor
{
class Widget
{
public int Id { get; set; }
public String Name { get; set; }
public Double Price { get; set; }
}
}
Within a BespokeDictionary:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WidgetProcessor
{
class BespokeDictionary
{
public ConcurrentDictionary<string, Widget> widgets { get; set; }
private const int length = 10;
public bool MakeWidgets(int size)
{
widgets = new ConcurrentDictionary<string, Widget>();
for (int i = 0; i < size; i++)
{
string key = "X" + i.ToString().PadLeft(length, '0');
widgets.TryAdd(key, new Widget() { Id = i, Name = RandomString(2),
Price = random.NextDouble() * 100 });
}
return true;
}
public int AddVat(Double rate)
{
Double multiplier = rate + 1;
int count = 0;
foreach (var item in widgets)
{
Widget newVal = new Widget() { Id = item.Value.Id, Name =
item.Value.Name, Price = item.Value.Price * multiplier };
7
if (widgets.TryUpdate(item.Key, newVal, item.Value))
count++;
}
return count;
}
public int ParralelForVat(Double rate)
{
int size = widgets.Count();
Parallel.For(0, size, _ => AddIndexedSingleVat(_, rate));
return size;
}
public void AddIndexedSingleVat(int x, Double rate)
{
bool changed = false;
Double multiplier = rate + 1;
string key = "X" + x.ToString().PadLeft(length, '0');
Widget Value;
if (widgets.TryGetValue(key, out Value))
{
Widget newVal = new Widget() { Id = Value.Id, Name = Value.Name, Price
= Value.Price * multiplier };
if (widgets.TryUpdate(key, newVal, Value))
changed = true;
}
}
public int ParralelForEachVat(Double rate)
{
Double multiplier = rate + 1;
int count = widgets.Count();
Parallel.ForEach<KeyValuePair<string, Widget>>(widgets, _ =>
AddSingleVat(_, rate));
return count;
}
public void AddSingleVat(KeyValuePair<string, Widget> pair, Double rate)
{
Double multiplier = rate + 1;
bool changed = false;
Widget newVal = new Widget() { Id = pair.Value.Id, Name = pair.Value.Name,
Price = pair.Value.Price * multiplier };
if (widgets.TryUpdate(pair.Key, newVal, pair.Value))
changed = true;
}
public void AddVatSpecific(Double rate)
{
int size = widgets.Count();
Double multiplier = rate + 1;
for (int i = 0; i < size; ++i)
{
string key = "X" + i.ToString().PadLeft(length, '0');
Widget val, newVal;
if (widgets.TryGetValue(key, out val))
{
newVal = new Widget() { Id = val.Id, Name = val.Name, Price =
val.Price * multiplier };
8
widgets.TryUpdate(key, val, newVal);
}
}
}
private Random random = new Random();
private string RandomString(int length)
{
const string chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
}
}
Tested with this Program:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WidgetProcessor
{
class Program
{
private const int length = 10;
private const int size = 30000000;
static void Main(string[] args)
{
Run(args);
Console.ReadLine();
}
static async void Run(string[] args)
{
BespokeDictionary dictionary = new BespokeDictionary();
DateTime StartTime;
Widget val, postVat, parval, parpostVat, postSingleVat, postForeachVat;
string key = "X0000000067";
Console.WriteLine("Single thread make widgets.");
StartTime = DateTime.Now;
bool done = await Task.Run(() => dictionary.MakeWidgets(size));
Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Widgets made.");
while (!dictionary.widgets.TryGetValue(key, out val))
{
Thread.Sleep(100);
}
if (dictionary.widgets.TryGetValue(key, out val))
Console.WriteLine("Key: " + key + " Price: " + val.Price);
9
Console.WriteLine();
Console.WriteLine("Single thread Add VAT.");
StartTime = DateTime.Now;
int count = await Task.Run(() => dictionary.AddVat(rate));
Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added
using dictionary.AddVat(). No of widgets: ", count);
dictionary.widgets.TryGetValue(key, out postVat);
while(postVat.Equals(val))
{
Thread.Sleep(100);
dictionary.widgets.TryGetValue(key, out postVat);
}
if (dictionary.widgets.TryGetValue(key, out postVat))
Console.WriteLine("Key: " + key + " Price: " + postVat.Price);
Console.WriteLine();
Console.WriteLine("Adding more vat using Parallel For on single
widgets.");
StartTime = DateTime.Now;
Parallel.For(0, size, _ => dictionary.AddIndexedSingleVat( _, rate));
Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Vat added using
Parallel For on single widgets dictionary.AddIndexedSingleVat().");
dictionary.widgets.TryGetValue(key, out postSingleVat);
while (postSingleVat.Equals(postVat))
{
Thread.Sleep(100);
dictionary.widgets.TryGetValue(key, out postSingleVat);
}
if (dictionary.widgets.TryGetValue(key, out postSingleVat))
Console.WriteLine("Key: " + key + " Price: " + postSingleVat.Price);
Console.WriteLine();
Console.WriteLine("Adding more vat using Parallel ForEach on single
widgets.");
StartTime = DateTime.Now;
Parallel.ForEach<KeyValuePair<string, Widget>>(dictionary.widgets, _ =>
dictionary.AddSingleVat(_, rate));
Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Vat added using
Parallel ForEach on single widgets dictionary.AddSingleVat().");
dictionary.widgets.TryGetValue(key, out postForeachVat);
while (postForeachVat.Equals(postSingleVat))
{
Thread.Sleep(100);
dictionary.widgets.TryGetValue(key, out postForeachVat);
}
if (dictionary.widgets.TryGetValue(key, out postForeachVat))
Console.WriteLine("Key: " + key + " Price: " +
postForeachVat.Price);
Console.WriteLine();
StartTime = DateTime.Now;
count = await Task.Run(() => dictionary.ParralelForVat(rate));
Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added
using dictionary.ParallelForVat(). No of widgets: ", count);
dictionary.widgets.TryGetValue(key, out parval);
while (parval.Equals(postForeachVat))
{
Thread.Sleep(100);
dictionary.widgets.TryGetValue(key, out parval);
10
}
if (dictionary.widgets.TryGetValue(key, out parval))
Console.WriteLine("Key: " + key + " Price: " + parval.Price);
Console.WriteLine();
StartTime = DateTime.Now;
count = await Task.Run(() => dictionary.ParralelForEachVat(rate));
Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added
using dictionary.ParallelForEachVat(). No of widgets: ", count);
dictionary.widgets.TryGetValue(key, out parpostVat);
while (parpostVat.Equals(parval))
{
Thread.Sleep(100);
dictionary.widgets.TryGetValue(key, out parpostVat);
}
if (dictionary.widgets.TryGetValue(key, out parpostVat))
Console.WriteLine("Key: " + key + " Price: " + parpostVat.Price);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Sorry to spoil your fun, but that's all.");
Console.ReadLine();
}
Giving this output:
Single thread make widgets.
00:01:44.6420432, Widgets made.
Key: X0000000067 Price: 26.1324811848497
Single thread make widgets.
00:01:44.2324568, Widgets made.
Key: X0000000067 Price: 8.84308694342295
Single thread Add VAT.
00:01:01.2588588, Vat added using dictionary.AddVat(). No of widgets: , 30000000
Key: X0000000067 Price: 10.6117043321075
Adding more vat using Parallel For on single widgets.
00:01:21.5208134, Vat added using Parallel For on single widgets dictionary.AddIndexedSingleVat().
11
Key: X0000000067 Price: 12.734045198529
Adding more vat using Parallel ForEach on single widgets.
00:01:14.3860227, Vat added using Parallel ForEach on single widgets dictionary.AddSingleVat().
Key: X0000000067 Price: 15.2808542382349
00:01:22.9244306, Vat added using dictionary.ParallelForVat(). No of widgets: , 30000000
Key: X0000000067 Price: 18.3370250858818
00:00:56.8089456, Vat added using dictionary.ParallelForEachVat(). No of widgets: , 30000000
Key: X0000000067 Price: 22.0044301030582
Sorry to spoil your fun, but that's all.
A small advantage in performance is shown using dictionary.ParallelForEachVat processing method
over straightforward single thread. This may be more apparent on a server with many cores.
12
Write a simple C# application to take two images and generate a third image which is the difference
of the two. Each resultant pixel grey level value will be calculated by subtracting the pixel value of
the second image from the corresponding pixel value of the first.
Requirements:
- The application is to run on a Windows 7 or 10 platform.
- Read the two image files in and write out the resultant values to a third file of the same format.
- Demonstrate the use of asynchronous programming in the solution.
- Provide the source code such that it can be rebuilt locally using Visual Studio 2015 or later.
Guidelines:
- A console application is acceptable.
- Raw image file format:
- Very simple format
- The file does not contain any header or footer data
- Only contains grey level information
- Each pixel is represented by an unsigned 16bit value representing a grey level, where a value of
0x0000 represents black
- Subtracting an image from itself will result in a black image where all pixels are set to zero.
- Two example raw image files are included for testing; each has 540 by 1200 pixels.
The Code:
using System;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace ImageSubtractor
{
class Program
{
const int imageSize = 648000;
13
private static Stopwatch watch1, watch2, watch3, watch4, watch5, watch6,
watch7, watch8, watch9, watch10;
[STAThread]
static void Main(string[] args)
{
string fileBase, fileSubtract, pathString = @"C:Subtractions";
Console.WriteLine("Please press enter and select file to subtract from");
Console.ReadLine();
OpenFileDialog fd = new OpenFileDialog();
fd.ShowDialog();
fileBase = fd.FileName;
watch1 = Stopwatch.StartNew();
var BaseArray = MakeArray(fileBase);
watch1.Stop();
Console.WriteLine("Time to Make Base Array = {0} ms",
watch1.ElapsedMilliseconds);
Console.WriteLine("");
Console.WriteLine("Please press enter and select file to subtract");
Console.ReadLine();
OpenFileDialog sd = new OpenFileDialog();
sd.ShowDialog();
fileSubtract = sd.FileName;
watch2 = Stopwatch.StartNew();
var SubtractArray = MakeArray(fileSubtract);
watch2.Stop();
Console.WriteLine("Time to Make Subtract Array = {0} ms",
watch2.ElapsedMilliseconds);
Console.WriteLine("");
Console.WriteLine("Base file location " + fileBase);
Console.WriteLine("");
Console.WriteLine("Subtract file location " + fileSubtract);
Console.WriteLine("");
watch3 = Stopwatch.StartNew();
var firstResult = SubtractArrays(BaseArray, SubtractArray);
watch3.Stop();
Console.WriteLine("Time to perform SubtractArrays = {0} ms",
watch3.ElapsedMilliseconds);
Console.WriteLine("");
watch4 = Stopwatch.StartNew();
var secondResult = SubtractFromBaseParallelFor(BaseArray, SubtractArray);
watch4.Stop();
Console.WriteLine("Time to perform SubtractFromBaseParallelFor = {0} ms",
watch4.ElapsedMilliseconds);
Console.WriteLine("A timing anomaly I wasn't able to resolve");
Console.WriteLine("");
watch5 = Stopwatch.StartNew();
var secondSubtractResult = SubtractSecondParallelFor(BaseArray,
SubtractArray);
watch5.Stop();
Console.WriteLine("Time to perform SubtractSecondParallelFor = {0} ms",
watch5.ElapsedMilliseconds);
Console.WriteLine("");
watch6 = Stopwatch.StartNew();
var fourthResult = SubtractThirdParallelFor(BaseArray, SubtractArray);
watch6.Stop();
Console.WriteLine("Time to perform SubtractThirdParallelFor = {0} ms",
watch6.ElapsedMilliseconds);
Console.WriteLine("");
watch7 = Stopwatch.StartNew();
var thirdResult = SubtractFromBaseUnsafe(BaseArray, SubtractArray);
14
watch7.Stop();
Console.WriteLine("Time to perform SubtractFromBaseUnsafe = {0} ms",
watch7.ElapsedMilliseconds);
Console.WriteLine("");
Console.WriteLine("");
System.IO.Directory.CreateDirectory(pathString);
Console.WriteLine("Created Directory");
Console.WriteLine("");
watch8 = Stopwatch.StartNew();
WriteShorts(firstResult, @"C:SubtractionsSubtractArraysResult.raw");
watch8.Stop();
Console.WriteLine("Time to save First Result = {0} ms",
watch8.ElapsedMilliseconds);
Console.WriteLine("First File Saved as {0}",
@"C:SubtractionsSubtractArraysResult.raw");
Console.WriteLine("");
watch9 = Stopwatch.StartNew();
WriteShorts(secondResult,
@"C:SubtractionsSubtractFromBaseParallelForResult.raw");
watch9.Stop();
Console.WriteLine("Time to save Second Result = {0} ms",
watch9.ElapsedMilliseconds);
Console.WriteLine("Second File Saved as {0}",
@"C:SubtractionsSubtractFromBaseParallelForResult.raw");
Console.WriteLine("");
watch10 = Stopwatch.StartNew();
WriteShorts(thirdResult, @"C:SubtractionsSubtractFromBaseUnsafe.raw");
watch10.Stop();
Console.WriteLine("Time to save Third Result = {0} ms",
watch10.ElapsedMilliseconds);
Console.WriteLine("Third File Saved as {0}",
@"C:SubtractionsSubtractFromBaseUnsafe.raw");
Console.WriteLine("");
Console.ReadLine();
}
private static UInt16[] MakeArray(String filename)
{
byte[] data;
int size;
//read the stream into a byte array first
using (FileStream stream = new FileStream(filename, FileMode.Open,
FileAccess.Read))
{
size = (int)stream.Length;
data = new byte[size];
stream.Read(data, 0, size);
}
// Convert the bytes into uint16's for the array
UInt16[] uintData = new UInt16[size / 2];
using (var memoryStream = new MemoryStream(data))
using (var reader = new BinaryReader(memoryStream))
for (int i = 0; i < size / 2; i++)
uintData[i] = (UInt16)reader.ReadUInt16();
return uintData;
}
private static UInt16[] SubtractArrays(UInt16[] Base, UInt16[] Subtract)
{
UInt16[] pixels = new UInt16[Base.Length];
15
for (int i = 0; i < Base.Length; i++)
{
int difference = Base[i] - Subtract[i];
if (difference >= 0)
pixels[i] = (UInt16)difference;
else
pixels[i] = 0;
}
return pixels;
}
private static UInt16[] SubtractFromBaseParallelFor(UInt16[] Base, UInt16[]
Subtract)
{
int blockSize = 540;
UInt16[] pixels = new UInt16[Base.Length];
//runs the for(i) loop j (length divide by blocksize) times
Parallel.For(0, (Base.Length / blockSize), (j) =>
{
for (int i = j * blockSize; i < (j + 1) * blockSize; i++)
{
int difference = Base[i] - Subtract[i];
pixels[i] = (ushort)Math.Max(difference, 0);
}
});
return pixels;
}
private static UInt16[] SubtractSecondParallelFor(UInt16[] Base, UInt16[]
Subtract)
{
int blockSize = 540;
UInt16[] pixels = new UInt16[Base.Length];
//runs the for(i) loop j (rounded length divide by blocksize) times
Parallel.For(0, (int)Math.Ceiling(Base.Length / (double)blockSize), (j) =>
{
for (int i = j * blockSize; i < (j + 1) * blockSize; i++)
{
if(Base[i]> Subtract[i])
pixels[i] = (UInt16)(Base[i] - Subtract[i]);
else
pixels[i] = 0;
}
});
return pixels;
}
private static UInt16[] SubtractThirdParallelFor(UInt16[] Base, UInt16[]
Subtract)
{
int blockSize = 540;
UInt16[] pixels = new UInt16[Base.Length];
//runs the for(i) loop j (rounded length divide by blocksize) times
Parallel.For(0, (Base.Length / blockSize), (j) =>
{
for (int i = j * blockSize; i < (j + 1) * blockSize; i++)
{
int difference = Base[i] - Subtract[i];
pixels[i] = (ushort)Math.Max(difference, 0);
16
}
});
return pixels;
}
private static UInt16[] SubtractFromBaseUnsafe(UInt16[] Base, UInt16[]
Subtract)
{
UInt16[] pixels = new UInt16[Base.Length];
Parallel.ForEach(Partitioner.Create(0, Base.Length), range =>
{
for (int i = range.Item1; i < range.Item2; ++i)
{
unsafe
{
var nonNegative = Base[i] > Subtract[i];
pixels[i] = (UInt16)((Base[i] - Subtract[i]) *
*((int*)(&nonNegative)));
}
}
});
return pixels;
}
private static void WriteShorts(UInt16[] values, string path)
{
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate,
FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
foreach (UInt16 value in values)
{
bw.Write(value);
}
}
}
}
}
}
The console:
Please press enter and select file to subtract from
Time to Make Base Array = 22 ms
Please press enter and select file to subtract
Time to Make Subtract Array = 27 ms
Base file location E:DocumentsDagesino800_540x1200.raw
17
Subtract file location E:DocumentsDagesino801_540x1200.raw
Time to perform SubtractArrays = 4 ms
Time to perform SubtractFromBaseParallelFor = 22 ms
A timing anomaly I wasn't able to resolve
Time to perform SubtractSecondParallelFor = 2 ms
Time to perform SubtractThirdParallelFor = 4 ms
Time to perform SubtractFromBaseUnsafe = 4 ms
Created Directory
Time to save First Result = 27 ms
First File Saved as C:SubtractionsSubtractArraysResult.raw
Time to save Second Result = 25 ms
Second File Saved as C:SubtractionsSubtractFromBaseParallelForResult.raw
Time to save Third Result = 26 ms
Third File Saved as C:SubtractionsSubtractFromBaseUnsafe.raw
18
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MathsExamples
{
public class Rooter
{
public double SquareRoot(double input)
{
if (input <= 0.0)
{
throw new ArgumentOutOfRangeException();
}
double result = input;
double previousResult = -input;
while (Math.Abs(previousResult - result) > result / 1000)
{
previousResult = result;
result = (result + input / result) / 2;
}
return result;
}
// Finds the integer square root of a positive number
public static double Isqrt(double num)
{
if (num <= 0.0)
{
throw new ArgumentOutOfRangeException();
} // Avoid zero divide
double n = (num / 2) + 1; // Initial estimate, never low
double n1 = (n + (num / n)) / 2;
while (n1 < n)
{
n = n1;
n1 = (n + (num / n)) / 2;
} // end while
return n;
} // end Isqrt()
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MathsExamples
{
public class Squarer
{
public double Square(double input)
19
{
return input * input;
}
}
}
using System;
using MathsExamples;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MathsUnitTests
{
[TestClass]
public class MathsTests
{
[TestMethod]
public void BasicRooterTest()
{
// Create an instance to test:
Rooter rooter = new Rooter();
// Define a test input and output value:
double expectedResult = 2.0;
double input = expectedResult * expectedResult;
// Run the method under test:
double actualResult = rooter.SquareRoot(input);
// Verify the result:
Assert.AreEqual(expectedResult, actualResult,
delta: expectedResult / 100);
}
[TestMethod]
public void RooterValueRange()
{
// Create an instance to test:
Rooter rooter = new Rooter();
// Try a range of values:
for (double expectedResult = 1e-8;
expectedResult < 1e+8;
expectedResult = expectedResult * 3.2)
{
RooterOneValue(rooter, expectedResult);
}
}
private void RooterOneValue(Rooter rooter, double expectedResult)
{
double input = expectedResult * expectedResult;
double actualResult = rooter.SquareRoot(input);
Assert.AreEqual(expectedResult, actualResult,
delta: expectedResult / 1000);
double Isqrt = Rooter.Isqrt(input);
Assert.AreEqual(expectedResult, Isqrt,
delta: expectedResult / 1000);
}
[TestMethod]
public void RooterTestNegativeInputx()
{
Rooter rooter = new Rooter();
try
{
rooter.SquareRoot(-10);
20
}
catch (ArgumentOutOfRangeException e)
{
return;
}
Assert.Fail();
}
[TestMethod]
public void SquarerTest()
{
//Create instance of Squarer
Squarer squarer = new Squarer();
var j = 1e-8;
for (double input = -1e+8; input < 1e+8; input += j)
{
j += 1e-8;
SquarerOneValue(squarer, input);
}
}
private void SquarerOneValue(Squarer squarer, double input)
{
double expectedResult = input * input;
double actualResult = squarer.Square(input);
Assert.AreEqual(expectedResult, actualResult,
delta: expectedResult / 1000);
}
}
}
21
Original Challenge:
Solving a maze
==============
The idea here is to write a program to solve simple mazes. The mazes are given in
a file and the program must read in the file, solve the maze and output the solution.
If no solution is possible the output should indicate this somehow. The program
should be written to the following specification:
- Arbitrary sized mazes should be handled
- Valid moves are N, S, E, W (not diagonally)
- All input will be clean, no validation is necessary
- Any suitable language can be used although one of Java, C#, Python is preferred
- The maze file format is described below with an example
- The program should be tested on the sample mazes provided
- Output should be written to the Standard Output/Console
================================================
== ALL the sample mazes DO have a solution! ==
================================================
The emphasis should be on code readability and simplicity. Runtime for all of the sample mazes
should be <30 seconds.
Please email the solution in source code form, with short instructions on how to run.
Good luck!
22
Maze file format
================
The input is a maze description file in plain text.
1 - denotes walls
0 - traversable passage way
INPUT:
<WIDTH> <HEIGHT><CR>
<START_X> <START_Y><CR> (x,y) location of the start. (0,0) is upper left and (width-
1,height-1) is lower right
<END_X> <END_Y><CR> (x,y) location of the end
<HEIGHT> rows where each row has <WIDTH> {0,1} integers space delimited
OUTPUT:
the maze with a path from start to end
walls marked by '#', passages marked by ' ', path marked by 'X', start/end marked by 'S'/'E'
Example file:
10 10
1 1
8 8
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 0 1 0 1 1 1 1 1 1
1 0 1 0 0 0 0 0 0 1
1 0 1 1 0 1 0 1 1 1
1 0 1 0 0 1 0 1 0 1
1 0 1 0 0 0 0 0 0 1
1 0 1 1 1 0 1 1 1 1
23
1 0 1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
OUTPUT:
##########
#SXX #
# #X######
# #XX #
# ##X# ###
# # X# # #
# # XX #
# ###X####
# # XXXE#
##########
The Demo:
24
23 21
1 1
21 19
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 1
1 0 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1
1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1
1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1
1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 1
1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1
1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1
1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Becomes:
#######################
#S# # # # #
#X# # # ####### # # # #
#X# # # # # # # #
#X# # ######### # # # #
25
#X# # #XXXXXXX# # # #
#X# # #X#####X# ##### #
#X# # #XXXXX#X# # # #
#X### ### #X#X# # # # #
#XXX # #X#X# # # # #
###X#######X#X# ### # #
# XXX#XXXXX#X# # # #
#####X#X#####X### #XXX#
# #XXX # XXX# #X#X#
# # ##### ### #X# #X#X#
# # # # #X #X#X#
# ##### # # ###X###X#X#
# # # # # #X#XXX#X#
# # # # ##### #X#X# #X#
# # # #XXX# #E#
#######################
The Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MazeSolvingApp
{
class Program
{
static void Main(string[] args)
{
SolveMaze solve = new SolveMaze();
solve.Run();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MazeSolvingApp
{
26
class Node
{
public neighbour location { get; set; }//the location of the node itself
public neighbour top { get; set; }//the location of the neighbouring cell
public neighbour bottom { get; set; }
public neighbour left { get; set; }
public neighbour right { get; set; }
public int Neighbours()
{
int count = 0;
if (top != null)
{
count += 1;
}
if (bottom != null)
{
count += 1;
}
if (left != null)
{
count += 1;
}
if (right != null)
{
count += 1;
}
return count;
}
}
class neighbour
{
public int row { get; set; }
public int column { get; set; }
}
}
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace MazeSolvingApp
{
class SolveMaze
{
private int Width { get; set; }
private int Height { get; set; }
private int StartX { get; set; }
private int StartY { get; set; }
private int EndX { get; set; }
private int EndY { get; set; }
private int position { get; set; }
private char[,] MazeArray { get; set; }
private char[,] SolvedMaze { get; set; }
27
private string outFile { get; set; }
private List<Node> nodeList { get; set; }
public void Run()
{
string FolderPath =
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Data");
Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().
Location), @"Solutions"));//somewhere to put the solutions
List<String> mazes = new List<string>(Directory.EnumerateFiles(FolderPath,
"*.txt", SearchOption.AllDirectories));
foreach (string maze in mazes)
{
string[] contents = File.ReadAllLines(maze);
position = maze.LastIndexOf("") + 1;
outFile = maze.Substring(0, position - 5) + "SolutionsSolved" +
maze.Substring(position, maze.Length - position);
int[] mazeFirst = getIntValues(contents[3]);
if (getDims(contents[0]))
if (getStart(contents[1]))
if (getEnd(contents[2]))
if (contents.Count() == Height + 3 && mazeFirst.Count() ==
Width)//check the maze matches the supplied dimensions
{
Console.WriteLine("Width = " + Width.ToString() + " Height =
" + Height.ToString() + " ");
Console.WriteLine("Start X = " + StartX.ToString() + " Start
Y = " + StartY.ToString() + " ");
Console.WriteLine("End X = " + EndX.ToString() + " End Y = "
+ EndY.ToString() + " ");
string[] mazeContents = new string[Height];
Array.Copy(contents, 3, mazeContents, 0, Height);//copies the
maze strings only
makeMazeArray(mazeContents);
CopyMaze();
nodeList = makeNodeList(mazeContents);
nodeList = RelateNodeList(nodeList);
nodeList = TrimNodeList(nodeList);
generateSolution();
}
else
{
Console.WriteLine("The file " + maze + " is not a valid maze
file ");
}
}
Console.ReadLine();
}
private List<Node> makeNodeList(string[] maze)
{
List<Node> NodeList = new List<Node>();
for (int i = 0; i < Height; i++)
{
28
char[] row = getCharValues(maze[i]);
for (int j = 0; j < Width; j++)
{
if (row[j] == '0')
{
Node node = new Node() { location = new neighbour() { row = i, column
= j } };
/*just a basic node with its location*/
NodeList.Add(node);
}
}
}
return NodeList;
}
private List<Node> RelateNodeList(List<Node> NodeList)
{
foreach (Node node in NodeList)
{
int X = node.location.column;
int Y = node.location.row;
neighbour top = new neighbour { column = X - 1, row = Y };
neighbour left = new neighbour { column = X, row = Y - 1 };
neighbour right = new neighbour { column = X, row = Y + 1 };
neighbour bottom = new neighbour { column = X + 1, row = Y };
/*this connects the nodes up to each other, establishing their
relationships*/
int indexTop = NodeList.FindIndex(f => f.location.row == top.row &&
f.location.column == top.column);
int indexLeft = NodeList.FindIndex(f => f.location.row == left.row &&
f.location.column == left.column);
bool indexRight = NodeList.Any(n => n.location.row == right.row &&
n.location.column == right.column);// NodeList.FindIndex(f => f.location == right);
int indexBottom = NodeList.FindIndex(f => f.location.row == bottom.row &&
f.location.column == bottom.column);
if (indexTop >= 0)
{
node.top = top;
}
if (indexLeft >= 0)
{
node.left = left;
}
if (indexRight)
{
node.right = right;
}
if (indexBottom >= 0)
{
node.bottom = bottom;
}
}
return NodeList;
}
private List<Node> TrimNodeList(List<Node> NodeList)
{
//This finds all the cells with one or no connected nodes. These will be the ends
of dead ends
List<Node> orphanedNodes = (from n in NodeList where n.Neighbours() <= 1 &&
!(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY &&
n.location.column == EndX) select n).ToList();
29
foreach (Node node in orphanedNodes)
{
if (node.Neighbours() > 0)
{
neighbour neybour = null;
Node attachedNode = null;
if (node.top != null)//we remove the connection from the adjacent node.
If this becomes the end of the dead end, it will go next loop around.
{
neybour = node.top;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.bottom = null;
}
if (node.left != null)
{
neybour = node.left;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.right = null;
}
if (node.right != null)
{
neybour = node.right;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.left = null;
}
if (node.bottom != null)
{
neybour = node.bottom;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.top = null;
}
}
NodeList.Remove(node);
}
if (NodeList.Any(n => n.Neighbours() <= 1 && !(n.location.row == StartY &&
n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX))) {
TrimNodeList(NodeList); }
return NodeList;// This should now only have nodes that connect start and end
}
private bool makeMazeArray(string[] maze)
{
MazeArray = new char[Width, Height];
for (int i = 0; i < Height; i++)
{
char[] row = getCharValues(maze[i]);
for (int j = 0; j < Width; j++)
{
MazeArray[j, i] = row[j];
}
}
return true;
}
private void generateSolution()
{
List<Node> path = shortestPath();
foreach (Node node in path)
{
30
SolvedMaze[node.location.column, node.location.row] = 'X';
//plot the shortest path on the solved maze array
}
makeOutputFile();// make the solution text file
}
private List<Node> shortestPath()
{
List<List<Node>> paths = new List<List<Node>>();
List<Node> path1 = plotForward();
paths.Add(path1);
/*This is just in case we get a shorter route by taking a different branch of
multiple paths
There are opportunities for providing multiple navigation methods and selecting
randomly,
running these multiple times and finding the shortest, but it wasn't necessary
here.
*/
List<Node> path2 = plotBackward();
paths.Add(path2);
List<Node> shortestPath = findShortest(paths);
return shortestPath;
}
private List<Node> plotForward()
{
List<Node> forwardListCopy = CopyList(nodeList);
List<Node> forwardList = new List<Node>();
Node currentNode = forwardListCopy.First(n => n.location.row == StartY &&
n.location.column == StartX);
Node previousNode = currentNode;
while (!(currentNode.location.row == EndY && currentNode.location.column ==
EndX))
{
forwardList.Add(currentNode);
neighbour next = findNeighbour(currentNode, previousNode);
previousNode = currentNode;
currentNode = forwardListCopy.First(n => n.location.row == next.row &&
n.location.column == next.column);
}
return forwardList;
}
private List<Node> plotBackward()
{
List<Node> backwardListCopy = CopyList(nodeList);
List<Node> backwardList = new List<Node>();
Node currentNode = backwardListCopy.First(n => n.location.row == EndY &&
n.location.column == EndX);
Node previousNode = currentNode;//this duplicates the first node position
while (!(currentNode.location.row == StartY && currentNode.location.column ==
StartX))
{
backwardList.Add(currentNode);//save the node to the path
neighbour next = findNeighbour(currentNode, previousNode);//find the next
node on the path
previousNode = currentNode;//this saves the node as previous, as we are about
to get the next one
currentNode = backwardListCopy.First(n => n.location.row == next.row &&
n.location.column == next.column);
}
return backwardList;
31
}
private neighbour findNeighbour(Node node, Node prev)
{
neighbour first = new neighbour() { row = -1, column = -1 };//see if the node has
a neighbour other than the previous node
if (node.location.row == prev.location.row && node.location.column ==
prev.location.column)//first instance
{
if (node.bottom != null)
{
first = node.bottom;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
else if (node.top != null)
{
first = node.top;
}
}
else if (node.bottom != null && (node.bottom.row == prev.location.row &&
node.bottom.column == prev.location.column))
{
/* each of these options indicates the direction of travel
if the movement was from the bottom, then target top first, and then left
and right.
Don't go backwards*/
if (node.top != null)
{
first = node.top;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
}
else if (node.left != null && (node.left.row == prev.location.row &&
node.left.column == prev.location.column))
{
if (node.right != null)
{
first = node.right;
}
else if (node.bottom != null)
{
first = node.bottom;
}
else if (node.top != null)
{
first = node.top;
}
32
}
else if (node.right != null && (node.right.row == prev.location.row &&
node.right.column == prev.location.column))
{
if (node.left != null)
{
first = node.left;
}
else if (node.bottom != null)
{
first = node.bottom;
}
else if (node.top != null)
{
first = node.top;
}
}
else if (node.top != null && (node.top.row == prev.location.row &&
node.top.column == prev.location.column))
{
if (node.bottom != null)
{
first = node.bottom;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
}
return first;
}
private List<Node> findShortest(List<List<Node>> lists)
{
int minLength = lists.Min(x => x.Count);
List<Node> shortest = lists.First(x => x.Count == minLength);
//We take the first example with the shortest count
return shortest;
}
private List<Node> CopyList(List<Node> list)
{
List<Node> copy = new List<Node>();
/*Copies each node in the list into a new list of nodes*/
foreach (Node node in list)
{
Node copyNode = new Node() { location = new neighbour() { row =
node.location.row, column = node.location.column } };
if (node.bottom != null)
{
copyNode.bottom = new neighbour() { row = node.bottom.row, column =
node.bottom.column };
}
if (node.left != null)
{
33
copyNode.left = new neighbour() { row = node.left.row, column =
node.left.column };
}
if (node.right != null)
{
copyNode.right = new neighbour() { row = node.right.row, column =
node.right.column };
}
if (node.top != null)
{
copyNode.top = new neighbour() { row = node.top.row, column =
node.top.column };
}
copy.Add(copyNode);
}
return copy;
}
private void CopyMaze()
{
//create a copy of the mazed to plot the solution on
SolvedMaze = new char[Width, Height];
Array.Copy(MazeArray, SolvedMaze, MazeArray.Length);//copies the original maze
}
private bool getDims(String dims)
{
//gets the width and height of the maze
int[] Dims = getIntValues(dims);
if (Dims.Count() == 2)
{
Width = Dims[0];
Height = Dims[1];
return true;
}
else return false;
}
private bool getStart(String start)
{
//gets the start location
int[] Start = getIntValues(start);
if (Start.Count() == 2)
{
StartX = Start[0];
StartY = Start[1];
return true;
}
else return false;
}
private bool getEnd(String end)
{
//gets the end location
int[] End = getIntValues(end);
if (End.Count() == 2)
{
EndX = End[0];
EndY = End[1];
return true;
34
}
else return false;
}
private int[] getIntValues(String param)
{
//splits a string of space separated ints into individual ints
return param.Split(new[] { ' ' }).Select(int.Parse).ToArray();
}
private char[] getCharValues(String param)
{
//splits space separated chars
return param.Split(new[] { ' ' }).Select(char.Parse).ToArray();
}
private void makeOutputFile()
{
char[,] output = new char[Width, Height];
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
char temp = SolvedMaze[j, i];
if (temp == '1')
{
output[j, i] = '#';
}
else if (temp == 'X')
{
output[j, i] = 'X';
}
}
}
output[StartX, StartY] = 'S';
output[EndX, EndY] = 'E';
StringBuilder outList = new StringBuilder();
for (int i = 0; i < Height; i++)
{
StringBuilder sb = new StringBuilder();
for (int j = 0; j < Width; j++)
{
sb.Append(output[j, i]);
}
outList.AppendLine(sb.ToString());
}
System.IO.File.WriteAllText(outFile, outList.ToString());
int fileStart = position + 5;
string filename = outFile.Substring(fileStart);
string time = DateTime.Now.ToLongTimeString();
Console.WriteLine("Output file " + filename + " at " + time);
return;
}
}
}
35
To see the app working, first open the solution in Visual Studio 2017.
Build the solution, then navigate to the bin/release folder :
Double click the Application file (without a file extension) and the console display will report on
progress. The solutions appear in a folder called Solutions.
36
INTRODUCTION
Spend as much time as required to solve this problem. No time limit is applied.
Write production quality code in your usual style, using C#. Do not use built-in language functionality
to directly solve the problem. So do not use the built-in pattern matching functions:
String::split(), String::indexOf(), String::lastIndexOf(), String::substring(), Regex.Match(), etc…
The solution should provide this functionality if applicable. You may use the String class to hold
information while your own algorithm does the matching. Do not copy an existing algorithm from the
Internet; you do not need to implement the fastest possible algorithm.
You may choose any means of accepting input and producing output, including the use of a test
harness. Note: String functions not related to matching can be used.
Please return the completed code in a zip file named CODE_TEST_<Candidate Name>.zip
REQUIREMENTS
Write an application that fulfils the following requirements:
1. Accepts two strings as input: one string is called "text" and the other is called "subtext" in this
problem statement,
2. Matches the subtext against the text, outputting the character positions of the beginning of each
match for the subtext within the text.
3. Allows multiple matches
4. Allows case insensitive matching
ACCEPTANCE CRITERIA
Input text: Polly put the kettle on, polly put the kettle on, polly put the kettle on we'll all have tea
Subtext:
Output:
Polly
1, 26, 51
Subtext:
Output:
polly
1, 26, 51
Subtext:
Output:
ll
3, 28, 53,
78, 82
Subtext:
Output:
Ll
3, 28, 53,
78, 82
Subtext:
Output:
X
<no
matches>
Subtext:
Output:
Polx
<no
matches>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICE_Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter the Text to find matches in: ");
37
String Text = Console.ReadLine();
Console.WriteLine("Please enter the SubText to match: ");
String SubText = Console.ReadLine();
String Response = MatchReport(Text, SubText);//ask the method for the
report on matches, as a string
Console.WriteLine(Response);//display the string in the console window
Console.WriteLine("Press Enter to close");
Console.ReadLine();
}
private static String MatchReport(String Text, String SubText)
{
if(Text.Length < 1)
{
return "there is no Text.";
}
if(SubText.Length < 1)
{
return "there is no SubText.";// just in case of "finger trouble"
}
if (Text.Length < SubText.Length)
{
return "The Text should be at least as long as the SubText";
}
bool match = false, saveIndex;
int k = 0;
String Matches = String.Empty;
String NoMatches = "<no matches>";
var textArray = Text.ToLower().ToCharArray();//no need to worry about case
now, and we can match seperate chars by index
var subtextArray = SubText.ToLower().ToCharArray();
for(int i = 0; i<textArray.Length - subtextArray.Length + 1; i++)
{
k = i + 1;// because the array index starts at zero and we need a
count starting at 1
saveIndex = true;
for(int j = 0; j<subtextArray.Length; j++)//check for matches in all
positions along the subText length
{
if(textArray[i + j] != subtextArray[j])
{
saveIndex = false;
break;
}
}
if (saveIndex)//if they all matched, save the index plus one value in
the report string
{
match = true;
if (Matches != String.Empty)
{
Matches += ", " + k.ToString();// subsequent positions have
the comma and space added
}
else { Matches += k.ToString(); }// first position on its own
}
}
if (match)
38
{
return Matches;// the counted positions of the matches
}
else { return NoMatches; }// a message we didn't find any
}
}
}
Console:
Please enter the Text to find matches in:
Polly put the kettle on, polly put the kettle on, polly put the kettle on we'll all have tea
Please enter the SubText to match:
Polly
1, 26, 51
Please enter the SubText to match:
polly
1, 26, 51
Press Enter to close
Please enter the SubText to match:
ll
3, 28, 53, 78, 82
Please enter the SubText to match:
Ll
3, 28, 53, 78, 82
Please enter the SubText to match:
X
<no matches>
Please enter the SubText to match:
Polx
<no matches>
Press Enter to close
39
“FizzBuzz” is an interview question asked during interviews to check logical skills of developers.
For Demonstration, we will print number input where it is not divisible by three or five. When a
number is multiple of three, print “Fizz” instead of a number on the console and if multiple of five
then print “Buzz” on the console. For numbers which are multiple of three as well five, print
“FizzBuzz” on the console.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FizzBuzz
{
public class Program
{
public static void Main(string[] args)
{
int max;
FizzyChecks fizz = new FizzyChecks();
Console.WriteLine("Please type the maximum number to test to.");
String input = Console.ReadLine();
if (int.TryParse(input, out max))
{
bool finished = fizz.FizzBuzz(max);
}
else
Console.WriteLine("Sorry, your input was not recognised");
Console.ReadLine();
}
}
public class FizzyChecks
{
public bool FizzBuzz(int max)
{
for (int i = 0; i <= max; i++)
{
Console.WriteLine(FizzCheck(i));
}
return true;
}
public String FizzCheck(int num)
{
String response = num.ToString();
if (num > 0)
{
if (DivisibleByThree(num))
{
if (DivisibleByFive(num))
{
response = "FizzBuzz";
40
return response;//no need to continue checking
}
else
{
response = "Fizz";
return response;
}
}
else if (DivisibleByFive(num))
{
response = "Buzz";
return response;
}
}
return response;
}
public bool DivisibleByThree(int num)
{
bool isIt = false;
if (num % 3 == 0)
isIt = true;
return isIt;
}
public bool DivisibleByFive(int num)
{
bool isIt = false;
if (num % 5 == 0)
isIt = true;
return isIt;
}
}
}
41
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FizzBuzz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FizzBuzz.Tests
{
[TestClass()]
public class ProgramTests
{
[TestMethod()]
public void FizzBuzzTest()
{
FizzyChecks checker = new FizzyChecks();
bool expected = true;
bool actual = checker.FizzBuzz(100001);
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void FizzCheckTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> threeList = new List<int>();
for (int i = 1; i < 100001; i++)
{
int j = 3 * i;// up to 300003
threeList.Add(j);
}
int[] threeArray = threeList.ToArray();
List<int> fiveList = new List<int>();
for (int i = 1; i < 10001; i++)
{
42
int j = 5 * i;// up to 50005
fiveList.Add(j);
}
int[] fiveArray = fiveList.ToArray();
String expected, actual;
for (int i = 1; i< 1000; i++)
{
actual = checker.FizzCheck(i);
if (threeArray.Contains(i))
{
if (fiveArray.Contains(i))
{
expected = "FizzBuzz";
}
else
{
expected = "Fizz";
}
}
else if(fiveArray.Contains(i))
{
expected = "Buzz";
}
else { expected = i.ToString(); }
Assert.AreEqual(expected, actual);
}
}
[TestMethod()]
public void DivisibleByThreeTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> threeList = new List<int>();
for(int i = 1; i < 100001; i++)
{
int j = 3 * i;
threeList.Add(j);
}
int[] threeArray = threeList.ToArray();
for(int k = 1; k < 10000; k++)
{
bool expected = false;
if (threeArray.Contains(k))
{
expected = true;
}
bool actual = checker.DivisibleByThree(k);
Assert.AreEqual(expected, actual);
}
}
[TestMethod()]
public void DivisibleByFiveTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> fiveList = new List<int>();
for (int i = 1; i < 10001; i++)
{
43
int j = 5 * i;
fiveList.Add(j);
}
int[] fiveArray = fiveList.ToArray();
for (int k = 1; k < 10000; k++)
{
bool expected = false;
if (fiveArray.Contains(k))
{
expected = true;
}
bool actual = checker.DivisibleByFive(k);
Assert.AreEqual(expected, actual);
}
}
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FizzBuzz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FizzBuzz.Tests
{
[TestClass()]
public class FizzyChecksTests
{
[TestMethod()]
public void FizzBuzzTest()
{
FizzyChecks checker = new FizzyChecks();
bool expected = true;
bool actual = checker.FizzBuzz(100001);
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void FizzCheckTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> threeList = new List<int>();
for (int i = 1; i < 10001; i++)
{
int j = 3 * i;
threeList.Add(j);
}
int[] threeArray = threeList.ToArray();
List<int> fiveList = new List<int>();
for (int i = 1; i < 10001; i++)
{
int j = 5 * i;
fiveList.Add(j);
}
int[] fiveArray = fiveList.ToArray();
String outcome = String.Empty;
for (int k = 1; k < 1000; k++)
{
44
if (threeArray.Contains(k) && fiveArray.Contains(k))
{
outcome = "FizzBuzz";
}
else if (threeArray.Contains(k)) { if (fiveArray.Contains(k)) {
outcome = "FizzBuzz"; } else { outcome = "Fizz"; } }
else if(fiveArray.Contains(k)) { outcome = "Buzz"; }
else { outcome = k.ToString(); }
String test = checker.FizzCheck(k);
Assert.AreEqual(outcome, test);
}
}
[TestMethod()]
public void DivisibleByThreeTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> threeList = new List<int>();
for (int i = 1; i < 10001; i++)
{
int j = 3 * i;
threeList.Add(j);
}
int[] threeArray = threeList.ToArray();
for (int k = 1; k < 30000; k++)
{
bool expected = false;
if (threeArray.Contains(k))
{
expected = true;
}
bool actual = checker.DivisibleByThree(k);
Assert.AreEqual(expected, actual);
}
}
[TestMethod()]
public void DivisibleByFiveTest()
{
FizzyChecks checker = new FizzyChecks();
List<int> fiveList = new List<int>();
for (int i = 1; i < 10001; i++)
{
int j = 5 * i;
fiveList.Add(j);
}
int[] fiveArray = fiveList.ToArray();
for (int k = 1; k < 50000; k++)
{
bool expected = false;
if (fiveArray.Contains(k))
{
expected = true;
}
bool actual = checker.DivisibleByFive(k);
Assert.AreEqual(expected, actual);
}
}
}
}
45
Console:
46
I hold my hands up! When I wrote this, I couldn’t spell Fibonacci.
The first program sequence calls the Fibinachi(i) method for each value from 1 to 25 and
displays the single result. The second sequence calls the yield return IEnumerable
method on the number 25 and then prints out the values in the IEnumerable in turn.
We have overlooked the value for zero, as it is zero.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Fibinachi
{
class Program
{
static int x = 0;
static void Main(string[] args)
{
for (int i = 1; i < 26; i++)
{
Console.WriteLine(" fib of " + i + ": " + Fibinachi(i));
Console.WriteLine("");
}
int index = 1;
foreach (int j in FibinachEnumerable(25))
{
Console.WriteLine(" fib of " + index + ": " + j);
Console.WriteLine("");
index++;
}
Console.ReadLine();
}
public static int Fibinachi(int n)
{
if (n == 1 || n == 2)
return 1;
return Fibinachi(n - 1) + Fibinachi(n - 2);
}
public static IEnumerable<int> FibinachEnumerable(int n)
{
for (int i = 1; i <= n; i++)
{
if (i == 1 || i == 2)
{
x = 1;
}
else
{
x = Fibinachi(i - 1) + Fibinachi(i - 2);
}
yield return x;
47
}
}
}
}
48
49
The requirement is to take a price in pounds, euros, or dollars and retun an object with the relevant
tax, duty, markup and total. Duty varies depending on the currency.
50
51
Services:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataAccess;
namespace cServices
{
public class Pricer
{
public String Cost { get; set; }
public String Duty { get; set; }
public String Markup { get; set; }
public String Tax { get; set; }
public String Total { get; set; }
private volatile Type _dependency;
public Pricer(string cost)
{
_dependency = typeof(System.Data.Entity.SqlServer.SqlProviderServices);
APIsourcesEntities db = new APIsourcesEntities();
var currencies = db.Currencies.Select(c => c.Currency1).ToList() ;
String Currency = cost[0].ToString();
String Value = cost.Substring(1, cost.Length - 1);
if(currencies.Contains(Currency)){
double temp;
if(Double.TryParse(Value, out temp))
{
double Costnum = temp;
double Dutynum = temp * db.Duties.Where(d =>
d.Currency.Equals(Currency)).Select(d => d.Duty1).FirstOrDefault();
double Markupnum = temp * db.TaxMarkups.Where(t => t.Id ==
1).Select(t => t.Markup).FirstOrDefault();
double Taxnum = temp * db.TaxMarkups.Where(t => t.Id ==
1).Select(t => t.Tax).FirstOrDefault();
double Totalnum = Costnum + Dutynum + Markupnum + Taxnum;
Total = Currency + roundPrice(Totalnum);
Tax = Currency + roundPrice(Taxnum);
Markup = Currency + roundPrice(Markupnum);
Duty = Currency + roundPrice(Dutynum);
Cost = Currency + roundPrice(Costnum);
}
}
}
private String roundPrice(Double value)
{
return Math.Round(value, 2).ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
52
namespace cServices
{
public class APIServices : IAPIServices
{
public Pricer GetPrices(string price)
{
if (!String.IsNullOrEmpty(price)) {
return new Pricer(price);
} else return new Pricer("£0");
}
}
}
namespace cServices
{
public interface IAPIServices
{
Pricer GetPrices(string price);
}
}
53
API:
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using System.Linq;
using System.Web;
using Unity;
using Unity.Exceptions;
namespace API
{
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
container.Dispose();
54
}
}
}
using cServices;
using System.Web.Http;
using Unity;
using Unity.Lifetime;
namespace API
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IAPIServices, APIServices>(new
HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
55
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using cServices;
namespace API.Controllers
{
public class ValuesController : ApiController
{
private IAPIServices servint;
public ValuesController(IAPIServices _servint)
{
servint = _servint;
}
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/price
/*[api/values/?Price=%C2%A310]
[/api/values/?Price=£10 ] */
public Pricer GetPrice([FromUri]String Price)
{
return servint.GetPrices(Price);
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
}
56
57
58

More Related Content

Similar to PORTFOLIO THREE PROJECTS AND TECHNOLOGIES

Blood bank Management System Salesforce
Blood bank Management System SalesforceBlood bank Management System Salesforce
Blood bank Management System Salesforcesonalighai
 
IS320 Database Applications.docx
IS320 Database Applications.docxIS320 Database Applications.docx
IS320 Database Applications.docxstirlingvwriters
 
Financials Cloud and Planning and Budgeting Cloud Service White Paper
Financials Cloud and Planning and Budgeting Cloud Service White PaperFinancials Cloud and Planning and Budgeting Cloud Service White Paper
Financials Cloud and Planning and Budgeting Cloud Service White PaperMatthew Skurdahl
 
Top 10 excel analytic tests to minimize fraud and process risks
Top 10 excel analytic tests to minimize fraud and process risksTop 10 excel analytic tests to minimize fraud and process risks
Top 10 excel analytic tests to minimize fraud and process risksJim Kaplan CIA CFE
 
Burger King Simulation
Burger King SimulationBurger King Simulation
Burger King SimulationRohit Jain
 
AGA 2015 Conference - Data Analytics - Amtrak OIG v3
AGA 2015 Conference - Data Analytics - Amtrak OIG v3AGA 2015 Conference - Data Analytics - Amtrak OIG v3
AGA 2015 Conference - Data Analytics - Amtrak OIG v3Vijay Chheda
 
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docx
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docxOPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docx
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docxLacieKlineeb
 
DSAA204 Data Structure And Algorithms.docx
DSAA204 Data Structure And Algorithms.docxDSAA204 Data Structure And Algorithms.docx
DSAA204 Data Structure And Algorithms.docxwrite31
 
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESS
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESSANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESS
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESSJessica Henderson
 
Capstone New Century Wellness Group Task Financial.pdf
Capstone New Century Wellness Group Task Financial.pdfCapstone New Century Wellness Group Task Financial.pdf
Capstone New Century Wellness Group Task Financial.pdfstudywriters
 
[Database assignment is1060]UOL Student Number 090404702.docx
[Database assignment is1060]UOL Student Number 090404702.docx[Database assignment is1060]UOL Student Number 090404702.docx
[Database assignment is1060]UOL Student Number 090404702.docxdanielfoster65629
 
Reduction in customer complaints - Mortgage Industry
Reduction in customer complaints - Mortgage IndustryReduction in customer complaints - Mortgage Industry
Reduction in customer complaints - Mortgage IndustryPranov Mishra
 
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataEvaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataAM Publications
 
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataEvaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataAM Publications
 
Performance Tuning for Visualforce and Apex
Performance Tuning for Visualforce and ApexPerformance Tuning for Visualforce and Apex
Performance Tuning for Visualforce and ApexSalesforce Developers
 
A Trinity Construction for Web Extraction Using Efficient Algorithm
A Trinity Construction for Web Extraction Using Efficient AlgorithmA Trinity Construction for Web Extraction Using Efficient Algorithm
A Trinity Construction for Web Extraction Using Efficient AlgorithmIOSR Journals
 
Hospital.pdf
Hospital.pdfHospital.pdf
Hospital.pdfredagad2
 
Implementation of Banker’s Algorithm Using Dynamic Modified Approach
Implementation of Banker’s Algorithm Using Dynamic Modified ApproachImplementation of Banker’s Algorithm Using Dynamic Modified Approach
Implementation of Banker’s Algorithm Using Dynamic Modified Approachrahulmonikasharma
 

Similar to PORTFOLIO THREE PROJECTS AND TECHNOLOGIES (20)

Blood bank Management System Salesforce
Blood bank Management System SalesforceBlood bank Management System Salesforce
Blood bank Management System Salesforce
 
IS320 Database Applications.docx
IS320 Database Applications.docxIS320 Database Applications.docx
IS320 Database Applications.docx
 
Financials Cloud and Planning and Budgeting Cloud Service White Paper
Financials Cloud and Planning and Budgeting Cloud Service White PaperFinancials Cloud and Planning and Budgeting Cloud Service White Paper
Financials Cloud and Planning and Budgeting Cloud Service White Paper
 
Top 10 excel analytic tests to minimize fraud and process risks
Top 10 excel analytic tests to minimize fraud and process risksTop 10 excel analytic tests to minimize fraud and process risks
Top 10 excel analytic tests to minimize fraud and process risks
 
Burger King Simulation
Burger King SimulationBurger King Simulation
Burger King Simulation
 
AGA 2015 Conference - Data Analytics - Amtrak OIG v3
AGA 2015 Conference - Data Analytics - Amtrak OIG v3AGA 2015 Conference - Data Analytics - Amtrak OIG v3
AGA 2015 Conference - Data Analytics - Amtrak OIG v3
 
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docx
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docxOPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docx
OPS574 v1Process Improvement FlowchartOPS574 v1Page 2 of 2.docx
 
DSAA204 Data Structure And Algorithms.docx
DSAA204 Data Structure And Algorithms.docxDSAA204 Data Structure And Algorithms.docx
DSAA204 Data Structure And Algorithms.docx
 
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESS
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESSANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESS
ANALYSIS OF PATIENT WAITING TIME FOR HOSPITAL ADMISSION AND DISCHARGE PROCESS
 
Capstone New Century Wellness Group Task Financial.pdf
Capstone New Century Wellness Group Task Financial.pdfCapstone New Century Wellness Group Task Financial.pdf
Capstone New Century Wellness Group Task Financial.pdf
 
[Database assignment is1060]UOL Student Number 090404702.docx
[Database assignment is1060]UOL Student Number 090404702.docx[Database assignment is1060]UOL Student Number 090404702.docx
[Database assignment is1060]UOL Student Number 090404702.docx
 
Reduction in customer complaints - Mortgage Industry
Reduction in customer complaints - Mortgage IndustryReduction in customer complaints - Mortgage Industry
Reduction in customer complaints - Mortgage Industry
 
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataEvaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
 
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific DataEvaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
Evaluation Mechanism for Similarity-Based Ranked Search Over Scientific Data
 
Performance Tuning for Visualforce and Apex
Performance Tuning for Visualforce and ApexPerformance Tuning for Visualforce and Apex
Performance Tuning for Visualforce and Apex
 
Flowchart.pptx
Flowchart.pptxFlowchart.pptx
Flowchart.pptx
 
H017124652
H017124652H017124652
H017124652
 
A Trinity Construction for Web Extraction Using Efficient Algorithm
A Trinity Construction for Web Extraction Using Efficient AlgorithmA Trinity Construction for Web Extraction Using Efficient Algorithm
A Trinity Construction for Web Extraction Using Efficient Algorithm
 
Hospital.pdf
Hospital.pdfHospital.pdf
Hospital.pdf
 
Implementation of Banker’s Algorithm Using Dynamic Modified Approach
Implementation of Banker’s Algorithm Using Dynamic Modified ApproachImplementation of Banker’s Algorithm Using Dynamic Modified Approach
Implementation of Banker’s Algorithm Using Dynamic Modified Approach
 

Recently uploaded

React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxnada99848
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 

Recently uploaded (20)

React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptx
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 

PORTFOLIO THREE PROJECTS AND TECHNOLOGIES

  • 1. PORTFOLIO THREE Examples of work in later 201x’s CHRIS WORLEDGE 27th August 2018
  • 2. 1 STRS Retrievals App [MVC 5 asp.net C# jQuery] Page 2 Performance of Parallel Processing Page 6 X-Ray Image Processing Page 12 Unit Tested Maths Functions Page 18 Maze Solving Application Page 21 Text Matching Page 36 FizzBuzz Test with Unit Tests Page 39 Fibonacci Sequence [plain and with yield return IEnumerable] Page 46 WebAPI2 With Dependency Injection Page 49
  • 3. 2 Purpose The Transfers Application provides a streamlined means of recording, updating, and managing the data associated with patient transfers conducted by the South Thames Retrieval Service. It also provides an instant overview of current and previous activity, with the opportunity for drill down. Data The data used with the Transfers Application is stored in an MS SQL Server relational database. It holds information on each transfer activity, and a table of outcomes, used to provide data to a drop- down control on the Create and Edit pages. This ensures users select from approved outcomes. The data associated with transfers is: NHS Number Stored as a 12 character Unicode string [nchar(12)] as the ten digit number must be split with two spaces. Referral Date Autogenerated DateTime stamp to the nearest second, on initial submission of information. [SmallDateTime] Patient Name Character string Age An integer representing age in whole years. Age-Months An integer representing the number of months after the age years. Date of Birth A date picker is provided which allows the year and month to be selected from drop- downs, and the day from the range for that month. Diagnosis Character string Referring Hospital The start point for the transfer as a character string. Last Contact Date The date of last contact with the patient. A date picker is provided which allows the year and month to be selected from drop-downs, and the day from the range for that month. Last Contact Time The time of last contact with the patient. A time picker is provided with separate controls for hour and minutes The Last Contact Date and Last Contact Time are stored in a single SmallDateTime in the database. Outcome Selected from a list, including destinations and remaining at DGH. Character String. Date Closed The date the retrieval was closed. A date picker is provided which allows the year and month to be selected from drop-downs, and the day from the range for that month. Time Closed The time the retrieval was closed. A date picker is provided which allows the year and month to be selected from drop-downs, and the day from the range for that month. The Date Closed and Time Closed are stored in a single SmallDateTime in the database.
  • 4. 3 Pages The home or Index page is decorated with both Evalina and GSTT logos, as well as a picture of a retrieval ambulance used by the service. It provides access to Create a new record, as well as a listing of existing records, split in tabs to provide all records, just open activity, and just closed activity. The listings each provide access to Details and Edit pages. The Create Page This page allows a new record to be generated, with an auto generated date time stamp, NHS Number (required) Patient Name (required) Date of Birth(date-picker, required) Age in Years and Months are generated from the date of birth. The input fields: Setting up a ten year old: If they are sixteen days short of the threshold:
  • 5. 4 But only fifteen days short is rounded up: And in the middle of the year: Following this the Diagnosis (required) will accept text and offer auto complete, and will be tested against the auto-complete source table. After the referral area is selected from the drop-down, the referral hospital Drop-Down is populated and displayed. The Details Page This page is designed to give a complete breakdown of the transfer record. It is anticipated this would be used to provide clarification of details absent from the main listings pages The Edit Page This page displays an existing listing for edit. The validation rules match the Create page. It is envisaged that this will be used to provide additional information such as contact date; outcome; and date/time closed. Validation NHS Number The modulus eleven algorithm is used to validate the NHS number by calculating it’s outcome from the first nine digits (after removing the spaces) and comparing it with the tenth. A failure will result in a message asking the user to check the NHS Number as it is not valid. The validation overlooks entries of ten nines as this is used where the real NHS Number is not known. Referral Date As this is auto generated, it requires no validation. It is displayed on the Edit page, but is not editable. Patient Name Validation is limited to a string being required. Age The Age field stores an integer which will have an initial population generated from the D.O.B. This is editable, and a range will be required. Date of Birth As this is generated from a date picker it does not need validating. Diagnosis Tested against look-up table used to supply auto-complete feature. Area Drop-Down list of areas.
  • 6. 5 Referring Hospital Drop-Down list based on area selected. Last Contact Date This is populated using a date-picker, so it’s validation is limited to a high level check that it has a time as well if it is not empty, and it falls between Referral Date and Closed Date. Last Contact Time This is populated using a time-picker, so it’s validation is limited to a high level check that it has a date as well if it is not empty, and it falls between Referral Date and Closed Date. Outcome Populated from a drop-down so validation is limited to being required if the Date Closed is set. Date Closed This is populated using a date-picker, so it’s validation is limited to a high level check that it has a time as well if it is not empty, and it falls after the Referral Date and the Last Contact Date. Time Closed This is populated using a time-picker, so it’s validation is limited to a high level check that it has a date as well if it is not empty, and it falls after Referral Time and Last Contact Time. Rationale Minimal Database Table Count The premise for this approach is that each retrieval will only be considered in isolation. This would minimise requirement for relational organisation. It may be necessary to consider some re- organisation of the data to allow more manipulation of records if the usage is expanded. Transient Data It is not usual for computer systems to store transient information as it quickly becomes invalid. Usually only date of birth would be stored, and age calculated when required, to ensure it is current. The storing of age values is considered appropriate to this particular case for two reasons: 1. Whilst the retrieval is open. Retrievals are short lived activities, so it would be anticipated that an age calculated at the time of referral will remain valid during the time the retrieval is open 2. Review of historic records. When viewing closed retrievals some time later, the viewer will not require the age of the patient at the time of viewing. The age which will be salient for them is the age at the time of the retrieval, so the one stored will be appropriate then as well.
  • 7. 6 The system processes Widgets: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WidgetProcessor { class Widget { public int Id { get; set; } public String Name { get; set; } public Double Price { get; set; } } } Within a BespokeDictionary: using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WidgetProcessor { class BespokeDictionary { public ConcurrentDictionary<string, Widget> widgets { get; set; } private const int length = 10; public bool MakeWidgets(int size) { widgets = new ConcurrentDictionary<string, Widget>(); for (int i = 0; i < size; i++) { string key = "X" + i.ToString().PadLeft(length, '0'); widgets.TryAdd(key, new Widget() { Id = i, Name = RandomString(2), Price = random.NextDouble() * 100 }); } return true; } public int AddVat(Double rate) { Double multiplier = rate + 1; int count = 0; foreach (var item in widgets) { Widget newVal = new Widget() { Id = item.Value.Id, Name = item.Value.Name, Price = item.Value.Price * multiplier };
  • 8. 7 if (widgets.TryUpdate(item.Key, newVal, item.Value)) count++; } return count; } public int ParralelForVat(Double rate) { int size = widgets.Count(); Parallel.For(0, size, _ => AddIndexedSingleVat(_, rate)); return size; } public void AddIndexedSingleVat(int x, Double rate) { bool changed = false; Double multiplier = rate + 1; string key = "X" + x.ToString().PadLeft(length, '0'); Widget Value; if (widgets.TryGetValue(key, out Value)) { Widget newVal = new Widget() { Id = Value.Id, Name = Value.Name, Price = Value.Price * multiplier }; if (widgets.TryUpdate(key, newVal, Value)) changed = true; } } public int ParralelForEachVat(Double rate) { Double multiplier = rate + 1; int count = widgets.Count(); Parallel.ForEach<KeyValuePair<string, Widget>>(widgets, _ => AddSingleVat(_, rate)); return count; } public void AddSingleVat(KeyValuePair<string, Widget> pair, Double rate) { Double multiplier = rate + 1; bool changed = false; Widget newVal = new Widget() { Id = pair.Value.Id, Name = pair.Value.Name, Price = pair.Value.Price * multiplier }; if (widgets.TryUpdate(pair.Key, newVal, pair.Value)) changed = true; } public void AddVatSpecific(Double rate) { int size = widgets.Count(); Double multiplier = rate + 1; for (int i = 0; i < size; ++i) { string key = "X" + i.ToString().PadLeft(length, '0'); Widget val, newVal; if (widgets.TryGetValue(key, out val)) { newVal = new Widget() { Id = val.Id, Name = val.Name, Price = val.Price * multiplier };
  • 9. 8 widgets.TryUpdate(key, val, newVal); } } } private Random random = new Random(); private string RandomString(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } } } Tested with this Program: using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace WidgetProcessor { class Program { private const int length = 10; private const int size = 30000000; static void Main(string[] args) { Run(args); Console.ReadLine(); } static async void Run(string[] args) { BespokeDictionary dictionary = new BespokeDictionary(); DateTime StartTime; Widget val, postVat, parval, parpostVat, postSingleVat, postForeachVat; string key = "X0000000067"; Console.WriteLine("Single thread make widgets."); StartTime = DateTime.Now; bool done = await Task.Run(() => dictionary.MakeWidgets(size)); Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Widgets made."); while (!dictionary.widgets.TryGetValue(key, out val)) { Thread.Sleep(100); } if (dictionary.widgets.TryGetValue(key, out val)) Console.WriteLine("Key: " + key + " Price: " + val.Price);
  • 10. 9 Console.WriteLine(); Console.WriteLine("Single thread Add VAT."); StartTime = DateTime.Now; int count = await Task.Run(() => dictionary.AddVat(rate)); Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added using dictionary.AddVat(). No of widgets: ", count); dictionary.widgets.TryGetValue(key, out postVat); while(postVat.Equals(val)) { Thread.Sleep(100); dictionary.widgets.TryGetValue(key, out postVat); } if (dictionary.widgets.TryGetValue(key, out postVat)) Console.WriteLine("Key: " + key + " Price: " + postVat.Price); Console.WriteLine(); Console.WriteLine("Adding more vat using Parallel For on single widgets."); StartTime = DateTime.Now; Parallel.For(0, size, _ => dictionary.AddIndexedSingleVat( _, rate)); Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Vat added using Parallel For on single widgets dictionary.AddIndexedSingleVat()."); dictionary.widgets.TryGetValue(key, out postSingleVat); while (postSingleVat.Equals(postVat)) { Thread.Sleep(100); dictionary.widgets.TryGetValue(key, out postSingleVat); } if (dictionary.widgets.TryGetValue(key, out postSingleVat)) Console.WriteLine("Key: " + key + " Price: " + postSingleVat.Price); Console.WriteLine(); Console.WriteLine("Adding more vat using Parallel ForEach on single widgets."); StartTime = DateTime.Now; Parallel.ForEach<KeyValuePair<string, Widget>>(dictionary.widgets, _ => dictionary.AddSingleVat(_, rate)); Console.WriteLine("{0}, {1}", DateTime.Now - StartTime, "Vat added using Parallel ForEach on single widgets dictionary.AddSingleVat()."); dictionary.widgets.TryGetValue(key, out postForeachVat); while (postForeachVat.Equals(postSingleVat)) { Thread.Sleep(100); dictionary.widgets.TryGetValue(key, out postForeachVat); } if (dictionary.widgets.TryGetValue(key, out postForeachVat)) Console.WriteLine("Key: " + key + " Price: " + postForeachVat.Price); Console.WriteLine(); StartTime = DateTime.Now; count = await Task.Run(() => dictionary.ParralelForVat(rate)); Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added using dictionary.ParallelForVat(). No of widgets: ", count); dictionary.widgets.TryGetValue(key, out parval); while (parval.Equals(postForeachVat)) { Thread.Sleep(100); dictionary.widgets.TryGetValue(key, out parval);
  • 11. 10 } if (dictionary.widgets.TryGetValue(key, out parval)) Console.WriteLine("Key: " + key + " Price: " + parval.Price); Console.WriteLine(); StartTime = DateTime.Now; count = await Task.Run(() => dictionary.ParralelForEachVat(rate)); Console.WriteLine("{0}, {1}, {2}", DateTime.Now - StartTime, "Vat added using dictionary.ParallelForEachVat(). No of widgets: ", count); dictionary.widgets.TryGetValue(key, out parpostVat); while (parpostVat.Equals(parval)) { Thread.Sleep(100); dictionary.widgets.TryGetValue(key, out parpostVat); } if (dictionary.widgets.TryGetValue(key, out parpostVat)) Console.WriteLine("Key: " + key + " Price: " + parpostVat.Price); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Sorry to spoil your fun, but that's all."); Console.ReadLine(); } Giving this output: Single thread make widgets. 00:01:44.6420432, Widgets made. Key: X0000000067 Price: 26.1324811848497 Single thread make widgets. 00:01:44.2324568, Widgets made. Key: X0000000067 Price: 8.84308694342295 Single thread Add VAT. 00:01:01.2588588, Vat added using dictionary.AddVat(). No of widgets: , 30000000 Key: X0000000067 Price: 10.6117043321075 Adding more vat using Parallel For on single widgets. 00:01:21.5208134, Vat added using Parallel For on single widgets dictionary.AddIndexedSingleVat().
  • 12. 11 Key: X0000000067 Price: 12.734045198529 Adding more vat using Parallel ForEach on single widgets. 00:01:14.3860227, Vat added using Parallel ForEach on single widgets dictionary.AddSingleVat(). Key: X0000000067 Price: 15.2808542382349 00:01:22.9244306, Vat added using dictionary.ParallelForVat(). No of widgets: , 30000000 Key: X0000000067 Price: 18.3370250858818 00:00:56.8089456, Vat added using dictionary.ParallelForEachVat(). No of widgets: , 30000000 Key: X0000000067 Price: 22.0044301030582 Sorry to spoil your fun, but that's all. A small advantage in performance is shown using dictionary.ParallelForEachVat processing method over straightforward single thread. This may be more apparent on a server with many cores.
  • 13. 12 Write a simple C# application to take two images and generate a third image which is the difference of the two. Each resultant pixel grey level value will be calculated by subtracting the pixel value of the second image from the corresponding pixel value of the first. Requirements: - The application is to run on a Windows 7 or 10 platform. - Read the two image files in and write out the resultant values to a third file of the same format. - Demonstrate the use of asynchronous programming in the solution. - Provide the source code such that it can be rebuilt locally using Visual Studio 2015 or later. Guidelines: - A console application is acceptable. - Raw image file format: - Very simple format - The file does not contain any header or footer data - Only contains grey level information - Each pixel is represented by an unsigned 16bit value representing a grey level, where a value of 0x0000 represents black - Subtracting an image from itself will result in a black image where all pixels are set to zero. - Two example raw image files are included for testing; each has 540 by 1200 pixels. The Code: using System; using System.Windows.Forms; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections.Concurrent; using System.Diagnostics; namespace ImageSubtractor { class Program { const int imageSize = 648000;
  • 14. 13 private static Stopwatch watch1, watch2, watch3, watch4, watch5, watch6, watch7, watch8, watch9, watch10; [STAThread] static void Main(string[] args) { string fileBase, fileSubtract, pathString = @"C:Subtractions"; Console.WriteLine("Please press enter and select file to subtract from"); Console.ReadLine(); OpenFileDialog fd = new OpenFileDialog(); fd.ShowDialog(); fileBase = fd.FileName; watch1 = Stopwatch.StartNew(); var BaseArray = MakeArray(fileBase); watch1.Stop(); Console.WriteLine("Time to Make Base Array = {0} ms", watch1.ElapsedMilliseconds); Console.WriteLine(""); Console.WriteLine("Please press enter and select file to subtract"); Console.ReadLine(); OpenFileDialog sd = new OpenFileDialog(); sd.ShowDialog(); fileSubtract = sd.FileName; watch2 = Stopwatch.StartNew(); var SubtractArray = MakeArray(fileSubtract); watch2.Stop(); Console.WriteLine("Time to Make Subtract Array = {0} ms", watch2.ElapsedMilliseconds); Console.WriteLine(""); Console.WriteLine("Base file location " + fileBase); Console.WriteLine(""); Console.WriteLine("Subtract file location " + fileSubtract); Console.WriteLine(""); watch3 = Stopwatch.StartNew(); var firstResult = SubtractArrays(BaseArray, SubtractArray); watch3.Stop(); Console.WriteLine("Time to perform SubtractArrays = {0} ms", watch3.ElapsedMilliseconds); Console.WriteLine(""); watch4 = Stopwatch.StartNew(); var secondResult = SubtractFromBaseParallelFor(BaseArray, SubtractArray); watch4.Stop(); Console.WriteLine("Time to perform SubtractFromBaseParallelFor = {0} ms", watch4.ElapsedMilliseconds); Console.WriteLine("A timing anomaly I wasn't able to resolve"); Console.WriteLine(""); watch5 = Stopwatch.StartNew(); var secondSubtractResult = SubtractSecondParallelFor(BaseArray, SubtractArray); watch5.Stop(); Console.WriteLine("Time to perform SubtractSecondParallelFor = {0} ms", watch5.ElapsedMilliseconds); Console.WriteLine(""); watch6 = Stopwatch.StartNew(); var fourthResult = SubtractThirdParallelFor(BaseArray, SubtractArray); watch6.Stop(); Console.WriteLine("Time to perform SubtractThirdParallelFor = {0} ms", watch6.ElapsedMilliseconds); Console.WriteLine(""); watch7 = Stopwatch.StartNew(); var thirdResult = SubtractFromBaseUnsafe(BaseArray, SubtractArray);
  • 15. 14 watch7.Stop(); Console.WriteLine("Time to perform SubtractFromBaseUnsafe = {0} ms", watch7.ElapsedMilliseconds); Console.WriteLine(""); Console.WriteLine(""); System.IO.Directory.CreateDirectory(pathString); Console.WriteLine("Created Directory"); Console.WriteLine(""); watch8 = Stopwatch.StartNew(); WriteShorts(firstResult, @"C:SubtractionsSubtractArraysResult.raw"); watch8.Stop(); Console.WriteLine("Time to save First Result = {0} ms", watch8.ElapsedMilliseconds); Console.WriteLine("First File Saved as {0}", @"C:SubtractionsSubtractArraysResult.raw"); Console.WriteLine(""); watch9 = Stopwatch.StartNew(); WriteShorts(secondResult, @"C:SubtractionsSubtractFromBaseParallelForResult.raw"); watch9.Stop(); Console.WriteLine("Time to save Second Result = {0} ms", watch9.ElapsedMilliseconds); Console.WriteLine("Second File Saved as {0}", @"C:SubtractionsSubtractFromBaseParallelForResult.raw"); Console.WriteLine(""); watch10 = Stopwatch.StartNew(); WriteShorts(thirdResult, @"C:SubtractionsSubtractFromBaseUnsafe.raw"); watch10.Stop(); Console.WriteLine("Time to save Third Result = {0} ms", watch10.ElapsedMilliseconds); Console.WriteLine("Third File Saved as {0}", @"C:SubtractionsSubtractFromBaseUnsafe.raw"); Console.WriteLine(""); Console.ReadLine(); } private static UInt16[] MakeArray(String filename) { byte[] data; int size; //read the stream into a byte array first using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { size = (int)stream.Length; data = new byte[size]; stream.Read(data, 0, size); } // Convert the bytes into uint16's for the array UInt16[] uintData = new UInt16[size / 2]; using (var memoryStream = new MemoryStream(data)) using (var reader = new BinaryReader(memoryStream)) for (int i = 0; i < size / 2; i++) uintData[i] = (UInt16)reader.ReadUInt16(); return uintData; } private static UInt16[] SubtractArrays(UInt16[] Base, UInt16[] Subtract) { UInt16[] pixels = new UInt16[Base.Length];
  • 16. 15 for (int i = 0; i < Base.Length; i++) { int difference = Base[i] - Subtract[i]; if (difference >= 0) pixels[i] = (UInt16)difference; else pixels[i] = 0; } return pixels; } private static UInt16[] SubtractFromBaseParallelFor(UInt16[] Base, UInt16[] Subtract) { int blockSize = 540; UInt16[] pixels = new UInt16[Base.Length]; //runs the for(i) loop j (length divide by blocksize) times Parallel.For(0, (Base.Length / blockSize), (j) => { for (int i = j * blockSize; i < (j + 1) * blockSize; i++) { int difference = Base[i] - Subtract[i]; pixels[i] = (ushort)Math.Max(difference, 0); } }); return pixels; } private static UInt16[] SubtractSecondParallelFor(UInt16[] Base, UInt16[] Subtract) { int blockSize = 540; UInt16[] pixels = new UInt16[Base.Length]; //runs the for(i) loop j (rounded length divide by blocksize) times Parallel.For(0, (int)Math.Ceiling(Base.Length / (double)blockSize), (j) => { for (int i = j * blockSize; i < (j + 1) * blockSize; i++) { if(Base[i]> Subtract[i]) pixels[i] = (UInt16)(Base[i] - Subtract[i]); else pixels[i] = 0; } }); return pixels; } private static UInt16[] SubtractThirdParallelFor(UInt16[] Base, UInt16[] Subtract) { int blockSize = 540; UInt16[] pixels = new UInt16[Base.Length]; //runs the for(i) loop j (rounded length divide by blocksize) times Parallel.For(0, (Base.Length / blockSize), (j) => { for (int i = j * blockSize; i < (j + 1) * blockSize; i++) { int difference = Base[i] - Subtract[i]; pixels[i] = (ushort)Math.Max(difference, 0);
  • 17. 16 } }); return pixels; } private static UInt16[] SubtractFromBaseUnsafe(UInt16[] Base, UInt16[] Subtract) { UInt16[] pixels = new UInt16[Base.Length]; Parallel.ForEach(Partitioner.Create(0, Base.Length), range => { for (int i = range.Item1; i < range.Item2; ++i) { unsafe { var nonNegative = Base[i] > Subtract[i]; pixels[i] = (UInt16)((Base[i] - Subtract[i]) * *((int*)(&nonNegative))); } } }); return pixels; } private static void WriteShorts(UInt16[] values, string path) { using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) { using (BinaryWriter bw = new BinaryWriter(fs)) { foreach (UInt16 value in values) { bw.Write(value); } } } } } } The console: Please press enter and select file to subtract from Time to Make Base Array = 22 ms Please press enter and select file to subtract Time to Make Subtract Array = 27 ms Base file location E:DocumentsDagesino800_540x1200.raw
  • 18. 17 Subtract file location E:DocumentsDagesino801_540x1200.raw Time to perform SubtractArrays = 4 ms Time to perform SubtractFromBaseParallelFor = 22 ms A timing anomaly I wasn't able to resolve Time to perform SubtractSecondParallelFor = 2 ms Time to perform SubtractThirdParallelFor = 4 ms Time to perform SubtractFromBaseUnsafe = 4 ms Created Directory Time to save First Result = 27 ms First File Saved as C:SubtractionsSubtractArraysResult.raw Time to save Second Result = 25 ms Second File Saved as C:SubtractionsSubtractFromBaseParallelForResult.raw Time to save Third Result = 26 ms Third File Saved as C:SubtractionsSubtractFromBaseUnsafe.raw
  • 19. 18 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MathsExamples { public class Rooter { public double SquareRoot(double input) { if (input <= 0.0) { throw new ArgumentOutOfRangeException(); } double result = input; double previousResult = -input; while (Math.Abs(previousResult - result) > result / 1000) { previousResult = result; result = (result + input / result) / 2; } return result; } // Finds the integer square root of a positive number public static double Isqrt(double num) { if (num <= 0.0) { throw new ArgumentOutOfRangeException(); } // Avoid zero divide double n = (num / 2) + 1; // Initial estimate, never low double n1 = (n + (num / n)) / 2; while (n1 < n) { n = n1; n1 = (n + (num / n)) / 2; } // end while return n; } // end Isqrt() } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MathsExamples { public class Squarer { public double Square(double input)
  • 20. 19 { return input * input; } } } using System; using MathsExamples; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace MathsUnitTests { [TestClass] public class MathsTests { [TestMethod] public void BasicRooterTest() { // Create an instance to test: Rooter rooter = new Rooter(); // Define a test input and output value: double expectedResult = 2.0; double input = expectedResult * expectedResult; // Run the method under test: double actualResult = rooter.SquareRoot(input); // Verify the result: Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 100); } [TestMethod] public void RooterValueRange() { // Create an instance to test: Rooter rooter = new Rooter(); // Try a range of values: for (double expectedResult = 1e-8; expectedResult < 1e+8; expectedResult = expectedResult * 3.2) { RooterOneValue(rooter, expectedResult); } } private void RooterOneValue(Rooter rooter, double expectedResult) { double input = expectedResult * expectedResult; double actualResult = rooter.SquareRoot(input); Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 1000); double Isqrt = Rooter.Isqrt(input); Assert.AreEqual(expectedResult, Isqrt, delta: expectedResult / 1000); } [TestMethod] public void RooterTestNegativeInputx() { Rooter rooter = new Rooter(); try { rooter.SquareRoot(-10);
  • 21. 20 } catch (ArgumentOutOfRangeException e) { return; } Assert.Fail(); } [TestMethod] public void SquarerTest() { //Create instance of Squarer Squarer squarer = new Squarer(); var j = 1e-8; for (double input = -1e+8; input < 1e+8; input += j) { j += 1e-8; SquarerOneValue(squarer, input); } } private void SquarerOneValue(Squarer squarer, double input) { double expectedResult = input * input; double actualResult = squarer.Square(input); Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 1000); } } }
  • 22. 21 Original Challenge: Solving a maze ============== The idea here is to write a program to solve simple mazes. The mazes are given in a file and the program must read in the file, solve the maze and output the solution. If no solution is possible the output should indicate this somehow. The program should be written to the following specification: - Arbitrary sized mazes should be handled - Valid moves are N, S, E, W (not diagonally) - All input will be clean, no validation is necessary - Any suitable language can be used although one of Java, C#, Python is preferred - The maze file format is described below with an example - The program should be tested on the sample mazes provided - Output should be written to the Standard Output/Console ================================================ == ALL the sample mazes DO have a solution! == ================================================ The emphasis should be on code readability and simplicity. Runtime for all of the sample mazes should be <30 seconds. Please email the solution in source code form, with short instructions on how to run. Good luck!
  • 23. 22 Maze file format ================ The input is a maze description file in plain text. 1 - denotes walls 0 - traversable passage way INPUT: <WIDTH> <HEIGHT><CR> <START_X> <START_Y><CR> (x,y) location of the start. (0,0) is upper left and (width- 1,height-1) is lower right <END_X> <END_Y><CR> (x,y) location of the end <HEIGHT> rows where each row has <WIDTH> {0,1} integers space delimited OUTPUT: the maze with a path from start to end walls marked by '#', passages marked by ' ', path marked by 'X', start/end marked by 'S'/'E' Example file: 10 10 1 1 8 8 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 0 1 1 1 1 1 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 0 1 1 1 1
  • 24. 23 1 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 OUTPUT: ########## #SXX # # #X###### # #XX # # ##X# ### # # X# # # # # XX # # ###X#### # # XXXE# ########## The Demo:
  • 25. 24 23 21 1 1 21 19 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 1 1 0 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 1 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 1 1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Becomes: ####################### #S# # # # # #X# # # ####### # # # # #X# # # # # # # # #X# # ######### # # # #
  • 26. 25 #X# # #XXXXXXX# # # # #X# # #X#####X# ##### # #X# # #XXXXX#X# # # # #X### ### #X#X# # # # # #XXX # #X#X# # # # # ###X#######X#X# ### # # # XXX#XXXXX#X# # # # #####X#X#####X### #XXX# # #XXX # XXX# #X#X# # # ##### ### #X# #X#X# # # # # #X #X#X# # ##### # # ###X###X#X# # # # # # #X#XXX#X# # # # # ##### #X#X# #X# # # # #XXX# #E# ####################### The Code: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MazeSolvingApp { class Program { static void Main(string[] args) { SolveMaze solve = new SolveMaze(); solve.Run(); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MazeSolvingApp {
  • 27. 26 class Node { public neighbour location { get; set; }//the location of the node itself public neighbour top { get; set; }//the location of the neighbouring cell public neighbour bottom { get; set; } public neighbour left { get; set; } public neighbour right { get; set; } public int Neighbours() { int count = 0; if (top != null) { count += 1; } if (bottom != null) { count += 1; } if (left != null) { count += 1; } if (right != null) { count += 1; } return count; } } class neighbour { public int row { get; set; } public int column { get; set; } } } using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; namespace MazeSolvingApp { class SolveMaze { private int Width { get; set; } private int Height { get; set; } private int StartX { get; set; } private int StartY { get; set; } private int EndX { get; set; } private int EndY { get; set; } private int position { get; set; } private char[,] MazeArray { get; set; } private char[,] SolvedMaze { get; set; }
  • 28. 27 private string outFile { get; set; } private List<Node> nodeList { get; set; } public void Run() { string FolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Data"); Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly(). Location), @"Solutions"));//somewhere to put the solutions List<String> mazes = new List<string>(Directory.EnumerateFiles(FolderPath, "*.txt", SearchOption.AllDirectories)); foreach (string maze in mazes) { string[] contents = File.ReadAllLines(maze); position = maze.LastIndexOf("") + 1; outFile = maze.Substring(0, position - 5) + "SolutionsSolved" + maze.Substring(position, maze.Length - position); int[] mazeFirst = getIntValues(contents[3]); if (getDims(contents[0])) if (getStart(contents[1])) if (getEnd(contents[2])) if (contents.Count() == Height + 3 && mazeFirst.Count() == Width)//check the maze matches the supplied dimensions { Console.WriteLine("Width = " + Width.ToString() + " Height = " + Height.ToString() + " "); Console.WriteLine("Start X = " + StartX.ToString() + " Start Y = " + StartY.ToString() + " "); Console.WriteLine("End X = " + EndX.ToString() + " End Y = " + EndY.ToString() + " "); string[] mazeContents = new string[Height]; Array.Copy(contents, 3, mazeContents, 0, Height);//copies the maze strings only makeMazeArray(mazeContents); CopyMaze(); nodeList = makeNodeList(mazeContents); nodeList = RelateNodeList(nodeList); nodeList = TrimNodeList(nodeList); generateSolution(); } else { Console.WriteLine("The file " + maze + " is not a valid maze file "); } } Console.ReadLine(); } private List<Node> makeNodeList(string[] maze) { List<Node> NodeList = new List<Node>(); for (int i = 0; i < Height; i++) {
  • 29. 28 char[] row = getCharValues(maze[i]); for (int j = 0; j < Width; j++) { if (row[j] == '0') { Node node = new Node() { location = new neighbour() { row = i, column = j } }; /*just a basic node with its location*/ NodeList.Add(node); } } } return NodeList; } private List<Node> RelateNodeList(List<Node> NodeList) { foreach (Node node in NodeList) { int X = node.location.column; int Y = node.location.row; neighbour top = new neighbour { column = X - 1, row = Y }; neighbour left = new neighbour { column = X, row = Y - 1 }; neighbour right = new neighbour { column = X, row = Y + 1 }; neighbour bottom = new neighbour { column = X + 1, row = Y }; /*this connects the nodes up to each other, establishing their relationships*/ int indexTop = NodeList.FindIndex(f => f.location.row == top.row && f.location.column == top.column); int indexLeft = NodeList.FindIndex(f => f.location.row == left.row && f.location.column == left.column); bool indexRight = NodeList.Any(n => n.location.row == right.row && n.location.column == right.column);// NodeList.FindIndex(f => f.location == right); int indexBottom = NodeList.FindIndex(f => f.location.row == bottom.row && f.location.column == bottom.column); if (indexTop >= 0) { node.top = top; } if (indexLeft >= 0) { node.left = left; } if (indexRight) { node.right = right; } if (indexBottom >= 0) { node.bottom = bottom; } } return NodeList; } private List<Node> TrimNodeList(List<Node> NodeList) { //This finds all the cells with one or no connected nodes. These will be the ends of dead ends List<Node> orphanedNodes = (from n in NodeList where n.Neighbours() <= 1 && !(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX) select n).ToList();
  • 30. 29 foreach (Node node in orphanedNodes) { if (node.Neighbours() > 0) { neighbour neybour = null; Node attachedNode = null; if (node.top != null)//we remove the connection from the adjacent node. If this becomes the end of the dead end, it will go next loop around. { neybour = node.top; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.bottom = null; } if (node.left != null) { neybour = node.left; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.right = null; } if (node.right != null) { neybour = node.right; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.left = null; } if (node.bottom != null) { neybour = node.bottom; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.top = null; } } NodeList.Remove(node); } if (NodeList.Any(n => n.Neighbours() <= 1 && !(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX))) { TrimNodeList(NodeList); } return NodeList;// This should now only have nodes that connect start and end } private bool makeMazeArray(string[] maze) { MazeArray = new char[Width, Height]; for (int i = 0; i < Height; i++) { char[] row = getCharValues(maze[i]); for (int j = 0; j < Width; j++) { MazeArray[j, i] = row[j]; } } return true; } private void generateSolution() { List<Node> path = shortestPath(); foreach (Node node in path) {
  • 31. 30 SolvedMaze[node.location.column, node.location.row] = 'X'; //plot the shortest path on the solved maze array } makeOutputFile();// make the solution text file } private List<Node> shortestPath() { List<List<Node>> paths = new List<List<Node>>(); List<Node> path1 = plotForward(); paths.Add(path1); /*This is just in case we get a shorter route by taking a different branch of multiple paths There are opportunities for providing multiple navigation methods and selecting randomly, running these multiple times and finding the shortest, but it wasn't necessary here. */ List<Node> path2 = plotBackward(); paths.Add(path2); List<Node> shortestPath = findShortest(paths); return shortestPath; } private List<Node> plotForward() { List<Node> forwardListCopy = CopyList(nodeList); List<Node> forwardList = new List<Node>(); Node currentNode = forwardListCopy.First(n => n.location.row == StartY && n.location.column == StartX); Node previousNode = currentNode; while (!(currentNode.location.row == EndY && currentNode.location.column == EndX)) { forwardList.Add(currentNode); neighbour next = findNeighbour(currentNode, previousNode); previousNode = currentNode; currentNode = forwardListCopy.First(n => n.location.row == next.row && n.location.column == next.column); } return forwardList; } private List<Node> plotBackward() { List<Node> backwardListCopy = CopyList(nodeList); List<Node> backwardList = new List<Node>(); Node currentNode = backwardListCopy.First(n => n.location.row == EndY && n.location.column == EndX); Node previousNode = currentNode;//this duplicates the first node position while (!(currentNode.location.row == StartY && currentNode.location.column == StartX)) { backwardList.Add(currentNode);//save the node to the path neighbour next = findNeighbour(currentNode, previousNode);//find the next node on the path previousNode = currentNode;//this saves the node as previous, as we are about to get the next one currentNode = backwardListCopy.First(n => n.location.row == next.row && n.location.column == next.column); } return backwardList;
  • 32. 31 } private neighbour findNeighbour(Node node, Node prev) { neighbour first = new neighbour() { row = -1, column = -1 };//see if the node has a neighbour other than the previous node if (node.location.row == prev.location.row && node.location.column == prev.location.column)//first instance { if (node.bottom != null) { first = node.bottom; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } else if (node.top != null) { first = node.top; } } else if (node.bottom != null && (node.bottom.row == prev.location.row && node.bottom.column == prev.location.column)) { /* each of these options indicates the direction of travel if the movement was from the bottom, then target top first, and then left and right. Don't go backwards*/ if (node.top != null) { first = node.top; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } } else if (node.left != null && (node.left.row == prev.location.row && node.left.column == prev.location.column)) { if (node.right != null) { first = node.right; } else if (node.bottom != null) { first = node.bottom; } else if (node.top != null) { first = node.top; }
  • 33. 32 } else if (node.right != null && (node.right.row == prev.location.row && node.right.column == prev.location.column)) { if (node.left != null) { first = node.left; } else if (node.bottom != null) { first = node.bottom; } else if (node.top != null) { first = node.top; } } else if (node.top != null && (node.top.row == prev.location.row && node.top.column == prev.location.column)) { if (node.bottom != null) { first = node.bottom; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } } return first; } private List<Node> findShortest(List<List<Node>> lists) { int minLength = lists.Min(x => x.Count); List<Node> shortest = lists.First(x => x.Count == minLength); //We take the first example with the shortest count return shortest; } private List<Node> CopyList(List<Node> list) { List<Node> copy = new List<Node>(); /*Copies each node in the list into a new list of nodes*/ foreach (Node node in list) { Node copyNode = new Node() { location = new neighbour() { row = node.location.row, column = node.location.column } }; if (node.bottom != null) { copyNode.bottom = new neighbour() { row = node.bottom.row, column = node.bottom.column }; } if (node.left != null) {
  • 34. 33 copyNode.left = new neighbour() { row = node.left.row, column = node.left.column }; } if (node.right != null) { copyNode.right = new neighbour() { row = node.right.row, column = node.right.column }; } if (node.top != null) { copyNode.top = new neighbour() { row = node.top.row, column = node.top.column }; } copy.Add(copyNode); } return copy; } private void CopyMaze() { //create a copy of the mazed to plot the solution on SolvedMaze = new char[Width, Height]; Array.Copy(MazeArray, SolvedMaze, MazeArray.Length);//copies the original maze } private bool getDims(String dims) { //gets the width and height of the maze int[] Dims = getIntValues(dims); if (Dims.Count() == 2) { Width = Dims[0]; Height = Dims[1]; return true; } else return false; } private bool getStart(String start) { //gets the start location int[] Start = getIntValues(start); if (Start.Count() == 2) { StartX = Start[0]; StartY = Start[1]; return true; } else return false; } private bool getEnd(String end) { //gets the end location int[] End = getIntValues(end); if (End.Count() == 2) { EndX = End[0]; EndY = End[1]; return true;
  • 35. 34 } else return false; } private int[] getIntValues(String param) { //splits a string of space separated ints into individual ints return param.Split(new[] { ' ' }).Select(int.Parse).ToArray(); } private char[] getCharValues(String param) { //splits space separated chars return param.Split(new[] { ' ' }).Select(char.Parse).ToArray(); } private void makeOutputFile() { char[,] output = new char[Width, Height]; for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { char temp = SolvedMaze[j, i]; if (temp == '1') { output[j, i] = '#'; } else if (temp == 'X') { output[j, i] = 'X'; } } } output[StartX, StartY] = 'S'; output[EndX, EndY] = 'E'; StringBuilder outList = new StringBuilder(); for (int i = 0; i < Height; i++) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < Width; j++) { sb.Append(output[j, i]); } outList.AppendLine(sb.ToString()); } System.IO.File.WriteAllText(outFile, outList.ToString()); int fileStart = position + 5; string filename = outFile.Substring(fileStart); string time = DateTime.Now.ToLongTimeString(); Console.WriteLine("Output file " + filename + " at " + time); return; } } }
  • 36. 35 To see the app working, first open the solution in Visual Studio 2017. Build the solution, then navigate to the bin/release folder : Double click the Application file (without a file extension) and the console display will report on progress. The solutions appear in a folder called Solutions.
  • 37. 36 INTRODUCTION Spend as much time as required to solve this problem. No time limit is applied. Write production quality code in your usual style, using C#. Do not use built-in language functionality to directly solve the problem. So do not use the built-in pattern matching functions: String::split(), String::indexOf(), String::lastIndexOf(), String::substring(), Regex.Match(), etc… The solution should provide this functionality if applicable. You may use the String class to hold information while your own algorithm does the matching. Do not copy an existing algorithm from the Internet; you do not need to implement the fastest possible algorithm. You may choose any means of accepting input and producing output, including the use of a test harness. Note: String functions not related to matching can be used. Please return the completed code in a zip file named CODE_TEST_<Candidate Name>.zip REQUIREMENTS Write an application that fulfils the following requirements: 1. Accepts two strings as input: one string is called "text" and the other is called "subtext" in this problem statement, 2. Matches the subtext against the text, outputting the character positions of the beginning of each match for the subtext within the text. 3. Allows multiple matches 4. Allows case insensitive matching ACCEPTANCE CRITERIA Input text: Polly put the kettle on, polly put the kettle on, polly put the kettle on we'll all have tea Subtext: Output: Polly 1, 26, 51 Subtext: Output: polly 1, 26, 51 Subtext: Output: ll 3, 28, 53, 78, 82 Subtext: Output: Ll 3, 28, 53, 78, 82 Subtext: Output: X <no matches> Subtext: Output: Polx <no matches> using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ICE_Demo { class Program { static void Main(string[] args) { Console.WriteLine("Please enter the Text to find matches in: ");
  • 38. 37 String Text = Console.ReadLine(); Console.WriteLine("Please enter the SubText to match: "); String SubText = Console.ReadLine(); String Response = MatchReport(Text, SubText);//ask the method for the report on matches, as a string Console.WriteLine(Response);//display the string in the console window Console.WriteLine("Press Enter to close"); Console.ReadLine(); } private static String MatchReport(String Text, String SubText) { if(Text.Length < 1) { return "there is no Text."; } if(SubText.Length < 1) { return "there is no SubText.";// just in case of "finger trouble" } if (Text.Length < SubText.Length) { return "The Text should be at least as long as the SubText"; } bool match = false, saveIndex; int k = 0; String Matches = String.Empty; String NoMatches = "<no matches>"; var textArray = Text.ToLower().ToCharArray();//no need to worry about case now, and we can match seperate chars by index var subtextArray = SubText.ToLower().ToCharArray(); for(int i = 0; i<textArray.Length - subtextArray.Length + 1; i++) { k = i + 1;// because the array index starts at zero and we need a count starting at 1 saveIndex = true; for(int j = 0; j<subtextArray.Length; j++)//check for matches in all positions along the subText length { if(textArray[i + j] != subtextArray[j]) { saveIndex = false; break; } } if (saveIndex)//if they all matched, save the index plus one value in the report string { match = true; if (Matches != String.Empty) { Matches += ", " + k.ToString();// subsequent positions have the comma and space added } else { Matches += k.ToString(); }// first position on its own } } if (match)
  • 39. 38 { return Matches;// the counted positions of the matches } else { return NoMatches; }// a message we didn't find any } } } Console: Please enter the Text to find matches in: Polly put the kettle on, polly put the kettle on, polly put the kettle on we'll all have tea Please enter the SubText to match: Polly 1, 26, 51 Please enter the SubText to match: polly 1, 26, 51 Press Enter to close Please enter the SubText to match: ll 3, 28, 53, 78, 82 Please enter the SubText to match: Ll 3, 28, 53, 78, 82 Please enter the SubText to match: X <no matches> Please enter the SubText to match: Polx <no matches> Press Enter to close
  • 40. 39 “FizzBuzz” is an interview question asked during interviews to check logical skills of developers. For Demonstration, we will print number input where it is not divisible by three or five. When a number is multiple of three, print “Fizz” instead of a number on the console and if multiple of five then print “Buzz” on the console. For numbers which are multiple of three as well five, print “FizzBuzz” on the console. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FizzBuzz { public class Program { public static void Main(string[] args) { int max; FizzyChecks fizz = new FizzyChecks(); Console.WriteLine("Please type the maximum number to test to."); String input = Console.ReadLine(); if (int.TryParse(input, out max)) { bool finished = fizz.FizzBuzz(max); } else Console.WriteLine("Sorry, your input was not recognised"); Console.ReadLine(); } } public class FizzyChecks { public bool FizzBuzz(int max) { for (int i = 0; i <= max; i++) { Console.WriteLine(FizzCheck(i)); } return true; } public String FizzCheck(int num) { String response = num.ToString(); if (num > 0) { if (DivisibleByThree(num)) { if (DivisibleByFive(num)) { response = "FizzBuzz";
  • 41. 40 return response;//no need to continue checking } else { response = "Fizz"; return response; } } else if (DivisibleByFive(num)) { response = "Buzz"; return response; } } return response; } public bool DivisibleByThree(int num) { bool isIt = false; if (num % 3 == 0) isIt = true; return isIt; } public bool DivisibleByFive(int num) { bool isIt = false; if (num % 5 == 0) isIt = true; return isIt; } } }
  • 42. 41 using Microsoft.VisualStudio.TestTools.UnitTesting; using FizzBuzz; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FizzBuzz.Tests { [TestClass()] public class ProgramTests { [TestMethod()] public void FizzBuzzTest() { FizzyChecks checker = new FizzyChecks(); bool expected = true; bool actual = checker.FizzBuzz(100001); Assert.AreEqual(expected, actual); } [TestMethod()] public void FizzCheckTest() { FizzyChecks checker = new FizzyChecks(); List<int> threeList = new List<int>(); for (int i = 1; i < 100001; i++) { int j = 3 * i;// up to 300003 threeList.Add(j); } int[] threeArray = threeList.ToArray(); List<int> fiveList = new List<int>(); for (int i = 1; i < 10001; i++) {
  • 43. 42 int j = 5 * i;// up to 50005 fiveList.Add(j); } int[] fiveArray = fiveList.ToArray(); String expected, actual; for (int i = 1; i< 1000; i++) { actual = checker.FizzCheck(i); if (threeArray.Contains(i)) { if (fiveArray.Contains(i)) { expected = "FizzBuzz"; } else { expected = "Fizz"; } } else if(fiveArray.Contains(i)) { expected = "Buzz"; } else { expected = i.ToString(); } Assert.AreEqual(expected, actual); } } [TestMethod()] public void DivisibleByThreeTest() { FizzyChecks checker = new FizzyChecks(); List<int> threeList = new List<int>(); for(int i = 1; i < 100001; i++) { int j = 3 * i; threeList.Add(j); } int[] threeArray = threeList.ToArray(); for(int k = 1; k < 10000; k++) { bool expected = false; if (threeArray.Contains(k)) { expected = true; } bool actual = checker.DivisibleByThree(k); Assert.AreEqual(expected, actual); } } [TestMethod()] public void DivisibleByFiveTest() { FizzyChecks checker = new FizzyChecks(); List<int> fiveList = new List<int>(); for (int i = 1; i < 10001; i++) {
  • 44. 43 int j = 5 * i; fiveList.Add(j); } int[] fiveArray = fiveList.ToArray(); for (int k = 1; k < 10000; k++) { bool expected = false; if (fiveArray.Contains(k)) { expected = true; } bool actual = checker.DivisibleByFive(k); Assert.AreEqual(expected, actual); } } } } using Microsoft.VisualStudio.TestTools.UnitTesting; using FizzBuzz; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FizzBuzz.Tests { [TestClass()] public class FizzyChecksTests { [TestMethod()] public void FizzBuzzTest() { FizzyChecks checker = new FizzyChecks(); bool expected = true; bool actual = checker.FizzBuzz(100001); Assert.AreEqual(expected, actual); } [TestMethod()] public void FizzCheckTest() { FizzyChecks checker = new FizzyChecks(); List<int> threeList = new List<int>(); for (int i = 1; i < 10001; i++) { int j = 3 * i; threeList.Add(j); } int[] threeArray = threeList.ToArray(); List<int> fiveList = new List<int>(); for (int i = 1; i < 10001; i++) { int j = 5 * i; fiveList.Add(j); } int[] fiveArray = fiveList.ToArray(); String outcome = String.Empty; for (int k = 1; k < 1000; k++) {
  • 45. 44 if (threeArray.Contains(k) && fiveArray.Contains(k)) { outcome = "FizzBuzz"; } else if (threeArray.Contains(k)) { if (fiveArray.Contains(k)) { outcome = "FizzBuzz"; } else { outcome = "Fizz"; } } else if(fiveArray.Contains(k)) { outcome = "Buzz"; } else { outcome = k.ToString(); } String test = checker.FizzCheck(k); Assert.AreEqual(outcome, test); } } [TestMethod()] public void DivisibleByThreeTest() { FizzyChecks checker = new FizzyChecks(); List<int> threeList = new List<int>(); for (int i = 1; i < 10001; i++) { int j = 3 * i; threeList.Add(j); } int[] threeArray = threeList.ToArray(); for (int k = 1; k < 30000; k++) { bool expected = false; if (threeArray.Contains(k)) { expected = true; } bool actual = checker.DivisibleByThree(k); Assert.AreEqual(expected, actual); } } [TestMethod()] public void DivisibleByFiveTest() { FizzyChecks checker = new FizzyChecks(); List<int> fiveList = new List<int>(); for (int i = 1; i < 10001; i++) { int j = 5 * i; fiveList.Add(j); } int[] fiveArray = fiveList.ToArray(); for (int k = 1; k < 50000; k++) { bool expected = false; if (fiveArray.Contains(k)) { expected = true; } bool actual = checker.DivisibleByFive(k); Assert.AreEqual(expected, actual); } } } }
  • 47. 46 I hold my hands up! When I wrote this, I couldn’t spell Fibonacci. The first program sequence calls the Fibinachi(i) method for each value from 1 to 25 and displays the single result. The second sequence calls the yield return IEnumerable method on the number 25 and then prints out the values in the IEnumerable in turn. We have overlooked the value for zero, as it is zero. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Fibinachi { class Program { static int x = 0; static void Main(string[] args) { for (int i = 1; i < 26; i++) { Console.WriteLine(" fib of " + i + ": " + Fibinachi(i)); Console.WriteLine(""); } int index = 1; foreach (int j in FibinachEnumerable(25)) { Console.WriteLine(" fib of " + index + ": " + j); Console.WriteLine(""); index++; } Console.ReadLine(); } public static int Fibinachi(int n) { if (n == 1 || n == 2) return 1; return Fibinachi(n - 1) + Fibinachi(n - 2); } public static IEnumerable<int> FibinachEnumerable(int n) { for (int i = 1; i <= n; i++) { if (i == 1 || i == 2) { x = 1; } else { x = Fibinachi(i - 1) + Fibinachi(i - 2); } yield return x;
  • 49. 48
  • 50. 49 The requirement is to take a price in pounds, euros, or dollars and retun an object with the relevant tax, duty, markup and total. Duty varies depending on the currency.
  • 51. 50
  • 52. 51 Services: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DataAccess; namespace cServices { public class Pricer { public String Cost { get; set; } public String Duty { get; set; } public String Markup { get; set; } public String Tax { get; set; } public String Total { get; set; } private volatile Type _dependency; public Pricer(string cost) { _dependency = typeof(System.Data.Entity.SqlServer.SqlProviderServices); APIsourcesEntities db = new APIsourcesEntities(); var currencies = db.Currencies.Select(c => c.Currency1).ToList() ; String Currency = cost[0].ToString(); String Value = cost.Substring(1, cost.Length - 1); if(currencies.Contains(Currency)){ double temp; if(Double.TryParse(Value, out temp)) { double Costnum = temp; double Dutynum = temp * db.Duties.Where(d => d.Currency.Equals(Currency)).Select(d => d.Duty1).FirstOrDefault(); double Markupnum = temp * db.TaxMarkups.Where(t => t.Id == 1).Select(t => t.Markup).FirstOrDefault(); double Taxnum = temp * db.TaxMarkups.Where(t => t.Id == 1).Select(t => t.Tax).FirstOrDefault(); double Totalnum = Costnum + Dutynum + Markupnum + Taxnum; Total = Currency + roundPrice(Totalnum); Tax = Currency + roundPrice(Taxnum); Markup = Currency + roundPrice(Markupnum); Duty = Currency + roundPrice(Dutynum); Cost = Currency + roundPrice(Costnum); } } } private String roundPrice(Double value) { return Math.Round(value, 2).ToString(); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
  • 53. 52 namespace cServices { public class APIServices : IAPIServices { public Pricer GetPrices(string price) { if (!String.IsNullOrEmpty(price)) { return new Pricer(price); } else return new Pricer("£0"); } } } namespace cServices { public interface IAPIServices { Pricer GetPrices(string price); } }
  • 54. 53 API: using System; using System.Collections.Generic; using System.Web.Http.Dependencies; using System.Linq; using System.Web; using Unity; using Unity.Exceptions; namespace API { public class UnityResolver : IDependencyResolver { protected IUnityContainer container; public UnityResolver(IUnityContainer container) { if (container == null) { throw new ArgumentNullException("container"); } this.container = container; } public object GetService(Type serviceType) { try { return container.Resolve(serviceType); } catch (ResolutionFailedException) { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return container.ResolveAll(serviceType); } catch (ResolutionFailedException) { return new List<object>(); } } public IDependencyScope BeginScope() { var child = container.CreateChildContainer(); return new UnityResolver(child); } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { container.Dispose();
  • 55. 54 } } } using cServices; using System.Web.Http; using Unity; using Unity.Lifetime; namespace API { public static class WebApiConfig { public static void Register(HttpConfiguration config) { var container = new UnityContainer(); container.RegisterType<IAPIServices, APIServices>(new HierarchicalLifetimeManager()); config.DependencyResolver = new UnityResolver(container); // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
  • 56. 55 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using cServices; namespace API.Controllers { public class ValuesController : ApiController { private IAPIServices servint; public ValuesController(IAPIServices _servint) { servint = _servint; } // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/price /*[api/values/?Price=%C2%A310] [/api/values/?Price=£10 ] */ public Pricer GetPrice([FromUri]String Price) { return servint.GetPrices(Price); } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
  • 57. 56
  • 58. 57
  • 59. 58