Skip to content

Commit f3eb054

Browse files
author
Frederic Vogels
committed
Merge branch 'student' into solution
2 parents 2c26566 + 94fabcf commit f3eb054

File tree

15 files changed

+709
-20
lines changed

15 files changed

+709
-20
lines changed

PiCross/Domain/PiCross/IGameData.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,57 @@ public interface IPlayerProfile
6464
string Name { get; }
6565
}
6666

67+
/// <summary>
68+
/// An IPlayerPuzzleInformation object contains
69+
/// the information for one specific player
70+
/// about one specific puzzle.
71+
/// </summary>
6772
public interface IPlayerPuzzleInformation
6873
{
74+
/// <summary>
75+
/// Best time the player has achieved for the puzzle.
76+
/// TimeSpan is value type like int, so it cannot be null.
77+
/// We can make it nullable though by using TimeSpan?
78+
/// If this property is null, the player hasn't solved
79+
/// the puzzle yet.
80+
/// </summary>
6981
TimeSpan? BestTime { get; set; }
7082
}
7183

7284
public interface IPuzzleLibrary
7385
{
86+
/// <summary>
87+
/// Returns a list of all puzzles in the library.
88+
/// Note that this returns an IEnumerable, which
89+
/// offers limited functionality. Use
90+
/// its ToList() to turn it into a list (make sure
91+
/// using System.Linq is present at the top of your source file.)
92+
/// </summary>
7493
IEnumerable<IPuzzleLibraryEntry> Entries { get; }
7594

95+
/// <summary>
96+
/// Adds a new puzzle to the library.
97+
/// </summary>
98+
/// <param name="puzzle">Puzzle.</param>
99+
/// <param name="author">Author of the puzzle.</param>
100+
/// <returns>Entry that has been added to the library.</returns>
76101
IPuzzleLibraryEntry Create( Puzzle puzzle, string author );
77102
}
78103

104+
/// <summary>
105+
/// A IPuzzleLibraryEntry is an object that
106+
/// pairs up a Puzzle and its author.
107+
/// </summary>
79108
public interface IPuzzleLibraryEntry
80109
{
110+
/// <summary>
111+
/// Puzzle.
112+
/// </summary>
81113
Puzzle Puzzle { get; set; }
82114

115+
/// <summary>
116+
/// Author of the puzzle.
117+
/// </summary>
83118
string Author { get; set; }
84119
}
85120
}

PiCross/Domain/PiCross/IPlayablePuzzle.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,20 @@ public interface IPlayablePuzzle
4545

4646
/// <summary>
4747
/// Contains true if the Grid contains no more unknown squares,
48-
/// and all squares are correct.
48+
/// and all squares are correct. This property is observable.
4949
/// </summary>
5050
Cell<bool> IsSolved { get; }
5151

5252
/// <summary>
5353
/// Number of squares that are left unknown (i.e. have not been determined to be
54-
/// filled or empty.)
54+
/// filled or empty.) This property is observable.
5555
/// </summary>
5656
Cell<int> UnknownCount { get; }
5757

5858
/// <summary>
5959
/// True if there are unknowns left, false otherwise. Note:
6060
/// this does not correspond to a successfully solved puzzle.
61-
/// The player might have made mistakes.
61+
/// The player might have made mistakes. This property is observable.
6262
/// </summary>
6363
Cell<bool> ContainsUnknowns { get; }
6464
}

PiCross/Domain/PiCross/PiCrossFacade.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ public IGameData CreateDummyGameData()
3939

4040
/// <summary>
4141
/// Loads data from the given file.
42-
/// When the data is modified, changes are automatically written to the file.
42+
/// When the data is modified, changes are automatically written to the file,
43+
/// so you do not need to explicitly write changes back to file.
4344
/// </summary>
4445
/// <param name="path">Path to the file.</param>
46+
/// <param name="createIfNotExistent">If true, creates an new empty game data file if none is present at the given path.</param>
4547
/// <returns>An IGameData object.</returns>
4648
public IGameData LoadGameData( string path, bool createIfNotExistent = false )
4749
{

PiCross/Domain/PiCross/PlayablePuzzle.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal class PlayablePuzzle : IPlayablePuzzle
2020
public PlayablePuzzle( ISequence<Constraints> columnConstraints, ISequence<Constraints> rowConstraints )
2121
: this( new PlayGrid( columnConstraints: columnConstraints, rowConstraints: rowConstraints ) )
2222
{
23-
// NOP
23+
// NOP
2424
}
2525

2626
public PlayablePuzzle( PlayGrid playGrid )

PiCross/Domain/PiCross/Puzzle.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,38 @@ public static Puzzle FromConstraints( ISequence<Constraints> columnConstraints,
5050
}
5151
}
5252

53+
/// <summary>
54+
/// Creates a puzzle from constraints in string format.
55+
/// Constraints on the same row/column should be separated by a single space,
56+
/// while rows/columns should be separated by a semicolon. For example,
57+
/// "2 1;1;;4 1".
58+
/// </summary>
59+
/// <param name="columnConstraints">Column constraints.</param>
60+
/// <param name="rowConstraints">Row constraints.</param>
61+
/// <returns></returns>
62+
public static Puzzle FromConstraints( string columnConstraints, string rowConstraints )
63+
{
64+
var parsedColumnConstraints = ParseConstraints( columnConstraints );
65+
var parsedRowConstraints = ParseConstraints( rowConstraints );
66+
67+
return FromConstraints( columnConstraints: parsedColumnConstraints, rowConstraints: parsedRowConstraints );
68+
}
69+
70+
private static int[][] ParseConstraints(string constraints)
71+
{
72+
return constraints.Split( ';' ).Select( part =>
73+
{
74+
if ( part == "" )
75+
{
76+
return new int[0];
77+
}
78+
else
79+
{
80+
return part.Split( ' ' ).Select( int.Parse ).ToArray();
81+
}
82+
} ).ToArray();
83+
}
84+
5385
/// <summary>
5486
/// Creates a Puzzle from the constraints.
5587
/// Internally, the puzzle is automatically solved.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Linq;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
5+
namespace PiCross.Tests
6+
{
7+
[TestClass]
8+
public class PuzzleCreationTests
9+
{
10+
[TestMethod]
11+
[TestCategory( "Puzzle Creation" )]
12+
public void FromStringConstraints()
13+
{
14+
// x.x
15+
// .x.
16+
// ...
17+
var puzzle = Puzzle.FromConstraints( columnConstraints: "1;1;1", rowConstraints: "1 1;1;" );
18+
var columnConstraints = puzzle.ColumnConstraints.Select( c => c.Values.ToArray() ).ToArray();
19+
var rowConstraints = puzzle.RowConstraints.Select( c => c.Values.ToArray() ).ToArray();
20+
21+
Assert.AreEqual( 3, columnConstraints.Length );
22+
Assert.AreEqual( 3, rowConstraints.Length );
23+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[0], new int[] { 1 } ) );
24+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[1], new int[] { 1 } ) );
25+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[2], new int[] { 1 } ) );
26+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[0], new int[] { 1, 1 } ) );
27+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[1], new int[] { 1 } ) );
28+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[2], new int[] { } ) );
29+
}
30+
31+
[TestMethod]
32+
[TestCategory( "Puzzle Creation" )]
33+
public void FromRowStrings()
34+
{
35+
var puzzle = Puzzle.FromRowStrings(
36+
".....",
37+
".x...",
38+
".xx..",
39+
"x.xx.",
40+
"..xxx"
41+
);
42+
var columnConstraints = puzzle.ColumnConstraints.Select( c => c.Values.ToArray() ).ToArray();
43+
var rowConstraints = puzzle.RowConstraints.Select( c => c.Values.ToArray() ).ToArray();
44+
45+
Assert.AreEqual( 5, columnConstraints.Length );
46+
Assert.AreEqual( 5, rowConstraints.Length );
47+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[0], new int[] { 1 } ) );
48+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[1], new int[] { 2 } ) );
49+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[2], new int[] { 3 } ) );
50+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[3], new int[] { 2 } ) );
51+
Assert.IsTrue( Enumerable.SequenceEqual( columnConstraints[4], new int[] { 1 } ) );
52+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[0], new int[] { } ) );
53+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[1], new int[] { 1 } ) );
54+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[2], new int[] { 2 } ) );
55+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[3], new int[] { 1, 2 } ) );
56+
Assert.IsTrue( Enumerable.SequenceEqual( rowConstraints[4], new int[] { 3 } ) );
57+
}
58+
}
59+
}

PiCross/Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
<Compile Include="GridSelectionHelperTests.cs" />
6060
<Compile Include="Constraints_Generate.cs" />
6161
<Compile Include="Constraints_Superposition.cs" />
62+
<Compile Include="PuzzleCreationTests.cs" />
6263
<Compile Include="PuzzleIOTests.cs" />
6364
<Compile Include="Constraints_IsSatisfied.cs" />
6465
<Compile Include="Constraints_SatisfiedPrefix.cs" />

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PiCross Project
2+
3+
Work in progress. Watch the repo (see setup instructions) to be notified whenever we update this.
4+
5+
* [Setup Instructions](docs/setup.md)
6+
* [Overall Structure](docs/overall-structure.md)
7+
* [First Steps](docs/first-steps.md)
8+
* [Functionality](docs/functionality.md)
9+
* [Rules and Expectations](docs/rules.md)

docs/cookbook.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Cookbook
2+
3+
This page contains some short samples of how you can interact with the domain.
4+
5+
## `IGameData`
6+
7+
```C#
8+
// Creating a dummy `IGameData` object
9+
var facade = new PiCrossFacade();
10+
var gameData = facade.CreateDummyGameData();
11+
12+
// Reading an `IGameData` object from file, fails if file does not exist
13+
var facade = new PiCrossFacade();
14+
var gameData = facade.LoadGameData(path);
15+
16+
// Reading an `IGameData` object from file, creates new file if no file is present at path
17+
var facade = new PiCrossFacade();
18+
var gameData = facade.LoadGameData( path, createIfNotExistent: true );
19+
```
20+
21+
## Puzzle Library
22+
23+
```C#
24+
// Creating a Puzzle object from constraints for
25+
// .....
26+
// .x...
27+
// .xx..
28+
// x.xx.
29+
// ..xxx
30+
var puzzle = Puzzle.FromConstraints(columnConstraints: "1;2;3;2;1",
31+
rowConstraints: ";1;2;1 2;3");
32+
33+
// Creating a Puzzle object from solution
34+
var puzzle = Puzzle.FromRowStrings(
35+
".....",
36+
".x...",
37+
".xx..",
38+
"x.xx.",
39+
"..xxx"
40+
);
41+
42+
// Getting a list of puzzle entries in the puzzle library
43+
var puzzleEntries = gameData.PuzzleLibrary.Entries;
44+
45+
// Adding a new puzzle to the Puzzle Library
46+
var puzzleEntry = gameData.PuzzleLibrary.Create(puzzle, author);
47+
```
48+
49+
## Playing
50+
51+
```C#
52+
// Creating an IPlayablePuzzle
53+
var facade = new PiCrossFacade();
54+
var puzzle = GetHoldOfAPuzzleSomehow();
55+
var playablePuzzle = facade.CreatePlayablePuzzle(puzzle);
56+
57+
// Marking the upper left square as filled
58+
var position = new Vector(0, 0);
59+
var square = playablePuzzle.Grid[position];
60+
square.Contents.Value = Square.FILLED; // square.Contents is a Cell and therefore observable
61+
62+
// Checking if puzzle is solved (observable)
63+
if ( playablePuzzle.IsSolved.Value ) { ... }
64+
65+
// Checking if there are cells marked unknown left (observable)
66+
if ( playablePuzzle.ContainsUnknowns.Value ) { ... }
67+
68+
// Number of cells marked unknown left (observable)
69+
var count = playablePuzzle.UnknownCount.Value;
70+
71+
// Checking if upper row constraints are satisfied (observable)
72+
if ( playablePuzzle.RowConstraints[0].IsSatisfied.Value ) { ... }
73+
74+
// Getting the values in the upper row constraints
75+
var values = playablePuzzle.RowConstraints[0].Values;
76+
```
77+
78+
## Player Database
79+
80+
```C#
81+
// Get player names
82+
var facade = new PiCrossFacade();
83+
var playerNames = facade.PlayerDatabase.PlayerNames;
84+
85+
// Get player profile
86+
var playerProfile = facade.PlayerDatabase[playerName];
87+
88+
// Find out if player has played puzzle before
89+
var puzzleEntry = facade.PuzzleLibrary.Entries.First();
90+
if ( playerProfile[puzzleEntry].BestTime.HasValue ) { ... }
91+
92+
// Get player's best time
93+
if ( playerProfile[puzzleEntry].BestTime.Value ) { ... }
94+
```

0 commit comments

Comments
 (0)