Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Construct a single round of a game tournament in which different 2-player board games are played on different tables.Using C# User Requirements The user is

Construct a single round of a game tournament in which different 2-player board games are played on different tables.Using C#

User Requirements

The user is holding a game tournament in which participants play various 2-player board games, such as chess, checkers, go, etc. Each participant registers to play a certain subset of the available games over the course of the tournament. The number of participants is exactly twice the number of tables; hence, every participant will play in each round. For each round, there are a number of allowable pairings consisting of the following information:

the first player in the pairing (for many games, this will be the player who plays first);

the second player in the pairing; and

the table at which these players would play (i.e., the game they would play).

These allowable pairings are provided as input (as described under "Input File Format" below), and have been determined by the user based on such factors as the games the players have registered to play, the games and opponents they have already played in the tournament, the relative strengths of the players, etc. From the given allowable pairings, your program must find a single subset that includes each player and each table exactly once, or report that this is impossible. If such a subset of the pairings is found, it will represent a single round of the tournament - each table has a first and second player, and each player is at exactly one table. (Your program does not need to find more than one round, as the allowable pairings for subsequent rounds would depend on the outcomes of the games in the current round.)

This problem is a slight generalization of the 3-dimensional matching problem, which is known to be computationally hard; hence, it is unreasonable to hope to find an efficient solution to the problem. However, because the instances will be fairly small, an inefficient solution will be satisfactory for our purposes. In the 3-dimensional matching problem, the subset of the pairings comprising the solution is known as a matching.

Whenever your program finds a matching, it must display the tournament round to the user. Furthermore, it must be possible for the user to save the tournament round to a file.

In what follows, we will describe the format of both the input and the output.

Input File Format

The first line of the input file should contain a single positive integer giving the number of tables. Let's call this integer n. Then on subsequent lines of input, the n tables will be represented by the integers 0, 1, . . ., n-1, and the 2n players will be represented by the integers 0, 1, . . ., 2n-1. Each line after the first will contain 3 integers, separated by commas. These three integers will represent the first player, the second player, and the table, respectively, of a single allowable pairing.

For example, consider the following input file:

3 0,1,0 1,2,0 3,4,1 5,0,2 

The first line states that there are 3 tables, 0, 1, and 2. Because there are 3 tables, there are 6 players, 0, 1, 2, 3, 4, and 5. The next four lines then describe four allowable pairings:

Player 0 as the first player vs. player 1 as the second player at table 0;

Player 1 as the first player vs. player 2 as the second player at table 0;

etc.

Output Format

For both the tournament round displayed to the user and the tournament round written to the file, the output should consist of n lines (where n is the number of tables) of the following form:

Table i: j vs. k

where i is the table number, j is the first player, and k is the second player. These lines should be listed in increasing order of table number. For example, given the input file described under "Input File Format" above, we would have the following output:

Table 0: 1 vs. 2 Table 1: 3 vs. 4 Table 2: 5 vs. 0 

Note that each pairing above is one of the allowable pairings given in the input (specifically, the last three pairings), each table has two players, and each player is at exactly one table. Note that the input's first pairing, 0 vs. 1 on table 0, could not be used because the only allowable pairing with player 2 is also on table 0; hence, the tournament round shown above is the only matching for this input.

Starting the Assignment

You must use Visual Studio 2017 for the homework assignments in this class. We recommend installing all updates. The Community Edition is not recommended, as we have had some problems with it.

Begin by creating a GitHub repository using this URL (Links to an external site.)Links to an external site., and cloning it to your local machine. This repository contains a new Windows Forms Application (with the class renamed to "UserInterface.cs"), a folder called "Data" containing several test data files, and an executable called "hw1.exe" that demonstrates the operation of the program.

User Interface

The program should display a window resembling the following:

image text in transcribed

The bar at the top is a ToolStrip, which is similar to a MenuStrip, except that it can contain other controls besides menus. This ToolStrip contains two buttons, which can be created using the drop-down menu on the ToolStrip in the Design Window. In order to allow the buttons to contain text, you will need to set their DisplayStyle properties to Text. Their Text properties can then be set to the text to be displayed. The "Open File" button should be enabled initially, but the "Save Tournament" button should disabled initially.

The large box below the ToolStrip is a multi-line TextBox. It should be impossible for the user to type anything directly into the TextBox (use its ReadOnly property to control this). It should have a vertical scroll bar, and if the user resizes the window, it should grow or shrink to fill the window (i.e., it should be anchored to all four sides).

If the user clicks the "Open File" button, an OpenFileDialog should be displayed. This dialog should have a filter (above the "OK" button) that shows only .csv files. The text shown in the filter should be "CSV files (*.csv)". It should be possible to click this filter and select another option, "All files (*.*)", to show all types of files. To obtain this functionality, set the dialog's Filter property to CSV files|*.csv|All files|*.*.

If the user selects a file, the program should attempt to read this file and find a matching for the data. If it finds one, it should display a tournament round in the TextBox as described under "Output Format" above (replacing any pre-existing text), and enable the "Save Tournament" button. If it fails to find a matching, it should display a MessageBox with the message, "No tournament found.", remove any text from the TextBox, and disable the "Save Tournament" button.

If the user clicks the "Save Tournament" button, a SaveFileDialog should be displayed. The filter for this dialog should initially show .txt files, and the text shown in the filter should be, "Text files (*.txt)". The other filter option should be all files, as in the OpenFileDialog above. The string for the Filter property should therefore be Text files|*.txt|All files|*.*. If the user selects a file, the program should attempt to save the contents of the TextBox to this file.

Exception Handling

If any exception occurs due to improper input or other I/O issues, the entire exception should be displayed in a MessageBox, and nothing in the main window should be changed. No other exceptions should occur. You will need to check explicitly for the following conditions:

If the number of tables is less than 1, an IOException containing the message, "The number of tables must be positive.", should be thrown.

If any of the values following the first input line is outside its allowable range, an IOException containing a message of the form, "Line i: The field is outside the allowable range." should be thrown. In this message, i is the line number in which the error occurred, where the first line is considered line 0, and field is either "first player", "second player", or "table", indicating which field was out of range.

If any line after the first contains the same value for both players, an IOException containing a message of the form, "Line i: The players are the same.", should be thrown. In this message, i is the line number in which the error occurred, as above.

If the input contains multiple errors, only the first should be displayed.

Software Architecture

Your program should be organized into three classes, as shown in the following class diagram:

image text in transcribed

The UserInterface class implements the GUI. MatchingFinder is a static class containing methods to read the input, find a matching, and format the output. Pairing is a class whose instances represent possible pairings.

You do not need to use the same names as shown above, as long as you follow the naming conventions for this class (Links to an external site.)Links to an external site..

Style Requirements

For this and all homework assignments in this class, you must follow the posted style requirements (Links to an external site.)Links to an external site.. In particular, note the naming conventions (Links to an external site.)Links to an external site. for each name that you choose, and the requirements for comments (Links to an external site.)Links to an external site. at the top of each file and before each class, field, and method definition.

Coding Requirements

The specific requirements for each of the classes is given in what follows. Each of these classes should be public. Feel free to include additional private methods in any of these classes if you feel it improves the code.

The Pairing Class

Each instance of this class will be an immutable representation of a pairing. It will need three public properties, each with a get accessor, but no set accessor:

FirstPlayer: gets an int giving the first player.

SecondPlayer: gets an int giving the second player.

Table: gets an int giving the table.

You can use the default implementation for each of these properties.

You will also need a public constructor that takes three ints as its parameters and uses them to initialize the above properties. Note that any property that uses the default implementation can be initialized in a constructor - it does not need a set accessor.

The MatchingFinder Class

This class should be static; hence, each of its methods must be static as well. It will need one public method and at least four private methods. These methods are each described in what follows. No exception handling should be done in the class. Because I/O must be done in this class, you will need a using directive for System.IO.

A private method to validate an input element

This method should take the following parameters:

A string containing a single field from a line of input.

An int giving an upper limit on a valid value contained in the field (i.e., the value should be strictly less than the limit).

An int giving the line number from which the element was taken.

A string containing the name of the field to be included in any exception that might need to be thrown (see the second bullet under "Exception Handling" above).

It should return an int containing the value represented by the first parameter.

This method will first need to convert the first parameter to an int using the Convert.ToInt32 (Links to an external site.)Links to an external site. method. It will then need to check that this value is at least 0 and less than the given limit. If not, it will need to throw an exception as described under "Exception Handling" above. To put a message into an exception, pass the message as a string to the exception's constructor; for example,

throw new IOException("This is the message included in the exception."); 

If the converted value is in the proper range, this value should be returned.

A private method to get the allowable pairings from the input lines

This method should take as its parameters a string[ ] whose elements are the lines from the input file, and an int giving the number of tables. It should return a Pairing[ ] containing the pairings from the input. It will need to construct a Pairing[ ] whose length is one less than the length of the given string[ ] (recall that the first line of input does not contain a pairing). It will then need to iterate through the input lines, skipping the first.

For each of these input lines, split the line into its fields using its Split (Links to an external site.)Links to an external site. method. If you pass this method the char ',' as its only parameter, it will return a String[ ] whose elements are the pieces of the string obtained by splitting it at each comma (the commas are removed). Thus, for example, if a string s is "0,1,2", then s.Split(',') will return a 3-element array containting the strings "0", "1", and "2". Once you have split the input line, validate each of the three elements using the above method. Then check to see whether the players are the same - if so, throw the appropriate exception as described under "Exception Handling" above. Finally, construct a Pairing from the values returned by the calls to the above method, and place it in the Pairing[ ]. Note that indices into the string[ ] parameter and the Pairing[ ] will differ by 1.

When the loop terminates, return the Pairing[ ].

A private method to find a matching

This method should take as its parameters a Pairing[ ] containing all allowable pairings and an int giving the number of tables. It should return a Pairing[ ] containing the pairings in a matching, such that each location i in this array contains the pairing at table i. If no matching is found, it should return null.

To find this matching, you will use a technique called backtracking. The main idea is to iterate through the allowable pairings, adding to a partial matching each one that contains players and a table that have not yet been included in the partial matching. If you find a complete matching in this way, return it. However, if you reach the end of the allowable pairings without having completed a matching, you will need to backtrack to the last pairing added to the partial matching. Note that this was the last point at which you had a choice - none of the following pairings could have been safely added to the partial matching. Because you made the choice to include this pairing, and you were unable to complete a matching based on this choice, you now know that this choice was wrong. You therefore remove this pairing from the partial matching and continue iterating through pairings from this point. If you ever reach a point where you have reached the end of the allowable pairings, but you cannot backtrack because there are no pairings in the partial matching, you can conclude that you have exhausted all possible choices, and hence there is no matching.

In order to implement this algorithm, you will need the following local variables:

A bool[ ] whose length is the number of players (i.e., twice the number of tables). You will use this array to keep track of which players have been included in the partial matching. Note that when you construct a bool[ ], all of its elements are initially false. We therefore use a value of true to indicate that a player is in the partial matching.

A Pairing[ ] whose length is the number of tables. You will use this array to keep track of which tables have been included in the partial matching. Note that when you construct a Pairing[ ], all of its elements are initially null. When a Pairing is added to the partial matching, it will be added to this array at the location given by its table; hence, that location will now be non-null. Furthermore, when the matching is complete, this array will contain exactly what you need to return.

A Stack containing indices into the array of allowable pairings. An index on the stack indicates that the associated pairing has been included in the partial matching. Because you will need to backtrack in last-in-first-out order, this stack can be used to guide the backtracking. Furthermore, when the number of elements in the stack reaches the number of tables, you will know that a matching is complete.

An int giving the current location in the array of allowable pairings. This value will iterate through the array of allowable pairings, backtracking when necessary. Hence, it will need to start at 0.

The algorithm then consists of a loop that iterates as long as either the current location is a valid index into the array of allowable pairings or the stack is nonempty (i.e., once the current location is invalid and the stack is empty, the loop terminates). On each iteration of this loop we do the following:

If the number of elements in the stack is the same as the number of tables, return the Pairing[ ] local variable, which now contains a complete matching.

Otherwise, if the current index is past the end of the array of allowable pairings, backtrack as follows:

Remove the value from the top of the stack and set the current index to this value.

Update the two array local variables to indicate that the allowable pairing indexed by the current index is no longer in the partial matching (i.e., two elements of the bool array will be set to false, and one element of the local Pairing[ ] will be set to null).

Otherwise, if the players and table in the current allowable pairing are not in the partial matching, place this pairing in the matching as follows:

Update the two array local variables to indicate that the current pairing is included in the partial matching.

Push the current index onto the stack.

At the end of each iteration, always increment the current index so that the next iteration will handle the next allowable pairing (if there is one).

If the above loop terminates without returning a matching, return null.

For example, suppose we have 3 tables with the following allowable pairings:

Pairing 0: Player 0 vs. Player 1 at Table 0

Pairing 1: Player 1 vs. Player 2 at Table 0

Pairing 2: Player 3 vs. Player 4 at Table 1

Pairing 3: Player 5 vs. Player 0 at Table 2

The algorithm will proceed as follows:

The current index is initially 0. Because the stack has fewer than 3 elements and the current index is still valid, we examine the bool[ ] to see that elements 0 and 1 (corresponding to players 0 and 1) are both false, and we examine the local Pairing[ ] to see that location 0 (corresponding to table 0) is null. We therefore add pairing 0 to the partial matching by setting elements 0 and 1 of the bool[ ] to true, setting element 0 of the local Pairing[ ] to pairing 0, and pushing 0 onto the stack. We then increment the current index to 1.

The stack has only 1 element, and the current index is valid. We therefore examine the bool[ ] and see that element 1 is true; hence, we can't add pairing 1 to the partial matching. We increment the current index to 2.

The stack has only 1 element, and the current index is valid. We therefore examine the bool[ ] and see that elements 3 and 4 are both false, and we examine the local Pairing[ ] and see that element 1 is null. We therefore add the pairing by setting elements 3 and 4 of the bool[ ] to true, setting element 1 of the local Pairing[ ] to pairing 2, and pushing 2 onto the stack. We then increment the current index to 3.

The stack has only 2 elements (0 and 2), and the current index is valid. We therefore examine the bool[ ] and see that element 5 is false, but element 0 is true; hence, we cannot add pairing 3 to the partial matching. We increment the current index to 4.

The stack has only 2 elements, but the current index is now beyond the array of allowable pairings. We therefore backtrack by popping 2 from the stack, making the current index 2, setting elements 3 and 4 (the players in pairing 2) of the bool[ ] to false, and setting element 1 (the table from pairing 2) of the local Pairing[ ] to null. We then increment the current index to 3.

As the algorithm continues, it will be unable to add pairing 3, so it will need to backtrack again, removing 0 from the partial matching. From that point, it will be able to add pairings 1, 2, and 3 on successive iterations. At this point, the stack will have 3 elements, and the local Pairing[ ] will contain the matching to be returned (i.e., pairings 1, 2, and 3 at locations 0, 1, and 2, respectively).

A private method to format the tournament round

This method should take as its only parameter a Pairing[ ] containing a matching. It should return a string describing the corresponding tournament round as explained under "Output Format" above. For efficiency, accumulate the result in a StringBuilder, then convert it to a string at the end. Iterate through the elements of the matching, appending the corresponding description for each one. For the end of a line, use the Environment.NewLine (Links to an external site.)Links to an external site. property, which gets a string.

A public method to get a tournament round

This method should take a string giving the name of the input file as its only parameter. It should return a stringdescribing a valid tournament round. If no valid tournament round exists, it should return null.

It will first need to read the file using the File.ReadAllLines (Links to an external site.)Links to an external site. method. This method is similar to the File.ReadAllTextmethod, but instead of returning a single string, it returns a string[ ] whose elements are the individual lines of the file. You will then need to convert the first line to an int, and check to see if it is positive. If not, you will need to throw an appropriate exception, as explained under "Exception Handling" above. Then using two of the above methods, you will need to obtain a Pairing[ ] containing all allowable pairings, and a second Pairing[ ] containing a matching. If this second array is null, return null; otherwise, use the above method to format the tournament, and return it.

The UserInterface Class

To this class, you will need to add event handlers for both of the buttons. They should each implement their respective functionality described under "User Interface" above. Note that most of the functionality of the "Open File" button is implemented by the public method in the MatchingFinder class. Both of these event handlers should handle any exceptions that might occur. Note that because one of the event handlers will need to write to a file, you will need a using directive for System.IO.

Tournament Generator _ Open File Save Tournament Tournament Generator _ Open File Save Tournament

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Concepts of Database Management

Authors: Philip J. Pratt, Joseph J. Adamski

7th edition

978-1111825911, 1111825912, 978-1133684374, 1133684378, 978-111182591

More Books

Students also viewed these Databases questions