Initial Commit

This commit is contained in:
kougyokugentou 2022-03-15 21:16:45 -07:00
parent 14960a7fc6
commit 666687a47f
38 changed files with 5189 additions and 3 deletions

6
.gitignore vendored
View File

@ -1,6 +1,6 @@
*/bin/*
*/obj/*
*/.vs/*
*\bin\*
*\obj\*
*\.vs\*
Cs*Apps/*/bin/*
Cs*Apps/*/obj/*
Cs*Apps/*/.vs/*

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{204522AA-27C2-49AC-BA28-BE82547473C9}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Airline</RootNamespace>
<AssemblyName>Airline</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

254
Cs3Apps/Airline/Program.cs Normal file
View File

@ -0,0 +1,254 @@
/* Shaun Marquardt
* TINFO 200
* CS3: Airline
* ****************************************************
* Change History
* Date Developer Description
* 2020-02-18 marqusa File creation and initial implementation.
* I decided to split PurchaseFirstClassTicket
* and PurchaseEconomyTicket into two seperate functions to make it easier to call
* if one class of ticket was full and it was acceptable to buy the other seats.
* Created a SeatsRemaining function to inform the
* user if the flight's all booked up and check seats remaining in a given class
* if one type is full.
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Airline
{
class Program
{
//Make the seating chart a more globally available variable.
//REQ 1: Use a one-dimensional array of type bool
//to represent the 10 seats of the plane
static bool[] seatingChart = new bool[10];
/* This is a program for a small airline to manage its new
* reservation system. This program assigns seats on each
* flight of the airline's only plane (capacity: 10 seats).
* The user will be presented with a menu to choose
* first class (seats 1-5) or economy (seats 6-10).
*
* Requirements:
* 1) Use a one-dimensional array of type bool to represent
* the seating chart of the plane, initialized to false to
* indicate all seats are empty.
* 2) As each seat is assigned, set the corresponding element
* to true to indicate the seat is no longer available.
* 3) The program should never assign a seat that is already
* assigned.
* 4) When the economy section is full, the app should ask the
* person if it's acceptable to sit in first class or vice/versa.
* 4a) If acceptable, make the seat assignment. If not acceptable
* then display the message "Next flight leaves in 3 hours".
*/
static void Main(string[] args)
{
string mainMenuChoice;
//Initialize each seat to false.
for (int i = 0; i < seatingChart.Length; i++)
{
seatingChart[i] = false;
}
// user interface
// 1 - sell the user of the software to the user
// 2 - instructions (basic) on how to use the software
Console.WriteLine(@"
****************************************************
**** Welcome to the Airline Reservation System *****
****************************************************
This is a program for Small Airlines Incorporated
to assign seats for all flights on the airline's
only plane (capacity, 10 seats -- book now!).
You will be presented with a menu if you would like
to fly First Class or Economy. After choosing, you
will be assigned a seat if it is available. If no
seat is available, you will be asked if you would
like a seat in the other class of seats. If that is
still not satisfactory for your flying needs or all
seats are taken, we will inform you of our next flight
departure time.
Please watch the printed warnings about input types
carefully so that you don't crash the program!
****************************************************
");
//Enter main program loop to keep purchasing tickets
//like a ticketing agent.
do
{
//Input
//Display the menu.
Console.WriteLine("1) First Class");
Console.WriteLine("2) Economy");
Console.WriteLine("3) Exit Program");
Console.Write("What tickets would you like to purchase (1, 2, or 3): ");
//Get the input from the user and store it as a string
//as C# allows us to switch on a string, and does not
//risk crashing the program on int.Parse()
mainMenuChoice = Console.ReadLine();
switch (mainMenuChoice)
{
case "1":
PurchaseFirstClassTicket();
break;
case "2":
PurchaseEconomyTicket();
break;
case "3":
break;
default:
Console.WriteLine("Sorry, that's not a valid selection.");
break;
} //end switch mainMenuChoice
} //end do... while
while (mainMenuChoice != "3");
//salutation
Console.WriteLine("\nThank you for using this program! Good bye!");
} //END main
private static void PurchaseEconomyTicket()
{
string userAcceptsSeatClassChange = String.Empty;
//If there are seats remaining in the Economy class.
if (SeatsRemaining("Economy") > 0)
{
for (int i = 5; i < seatingChart.Length; i++)
{
/* Assign the next empty seat.
* Unfortunately I use break here because
* I don't know where the next index of False is
* in the range of seating area. Normally this is
* done with while, but since I am working in the
* middle of an array, it can't be done like that.
*/
if (!seatingChart[i])
{
seatingChart[i] = true;
break;
}
}
Console.WriteLine("Thank you for booking an Economy class ticket with us.");
}
else if(SeatsRemaining("First Class") > 0) //Economy is full, but First Class has seats.
{
Console.Write("Sorry, Economy section is full. " +
"Is it acceptable to be seated in First Class? (Y/N): ");
userAcceptsSeatClassChange = Console.ReadLine();
if(userAcceptsSeatClassChange.ToUpper() == "Y" )
{
PurchaseFirstClassTicket();
}
else //User does not want first class seats.
{
Console.WriteLine("Next flight leaves in 3 hours.");
}
}
else //The flight is full.
{
Console.WriteLine("Sorry, we're all booked up. Next flight leaves in 3 hours.");
}
} //END PurchaseEconomyTicket
private static void PurchaseFirstClassTicket()
{
string userAcceptsSeatClassChange = String.Empty;
//If there are seats remaining in First Class.
if (SeatsRemaining("First Class") > 0)
{
for (int i = 0; i < 5; i++)
{
/* Assign the next empty seat.
* Unfortunately I use break here because
* I don't know where the next index of False is
* in the range of seating area. Normally this is
* done with while, but since I am working in the
* middle of an array, it can't be done like that.
*/
if (!seatingChart[i])
{
seatingChart[i] = true;
break;
}
}
Console.WriteLine("Thank you for booking a First Class ticket with us.");
}
else if (SeatsRemaining("Economy") > 0) //First Class is full, but economy has seats.
{
Console.Write("Sorry, First Class section is full. " +
"Is it acceptable to be seated in Economy? (Y/N): ");
userAcceptsSeatClassChange = Console.ReadLine();
if (userAcceptsSeatClassChange.ToUpper() == "Y")
{
PurchaseEconomyTicket();
}
else
{
Console.WriteLine("Next flight leaves in 3 hours.");
}
}
else //The flight is full.
{
Console.WriteLine("Sorry, we're all booked up. Next flight leaves in 3 hours.");
}
} //END PurchaseFirstClassTicket
/* Gets the number of seats remaining in
* a given seating class, "Economy" or "First Class"
*
* Preconditions: not yet
* Inputs: string seatClass as "Economy" or "First Class"
* Outputs: integer
* Postconditions: not yet
*/
private static int SeatsRemaining(string seatClass)
{
//Setup variables.
int countOfSeatsRemaining = 0;
int start_index = 0;
int end_index = 0;
//Depending on seat class, we change where we
//start and end our for-loop to count the
//number of seats remaining in a given class.
switch(seatClass)
{
case "Economy":
start_index = 5;
end_index = 9;
break;
case "First Class":
start_index = 0;
end_index = 4;
break;
}
//For loop to count the number of seats remaining, seatClass agnostic.
for(int i=start_index; i<=end_index; i++)
{
if (!seatingChart[i])
countOfSeatsRemaining++;
}
//Return the number of seats remaining.
return countOfSeatsRemaining;
} //END SeatsRemaining
} //END class Program
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Airline")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Airline")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("204522aa-27c2-49ac-ba28-be82547473c9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

37
Cs3Apps/Cs3Apps.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29728.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elimination", "Elimination\Elimination.csproj", "{6C32EC6B-CF2B-4032-B536-28900D5D52F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Airline", "Airline\Airline.csproj", "{204522AA-27C2-49AC-BA28-BE82547473C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TicTacToe", "TicTacToe\TicTacToe.csproj", "{6DA041E1-08F7-4FEB-8201-252D03BE5D34}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6C32EC6B-CF2B-4032-B536-28900D5D52F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C32EC6B-CF2B-4032-B536-28900D5D52F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C32EC6B-CF2B-4032-B536-28900D5D52F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C32EC6B-CF2B-4032-B536-28900D5D52F0}.Release|Any CPU.Build.0 = Release|Any CPU
{204522AA-27C2-49AC-BA28-BE82547473C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{204522AA-27C2-49AC-BA28-BE82547473C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{204522AA-27C2-49AC-BA28-BE82547473C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{204522AA-27C2-49AC-BA28-BE82547473C9}.Release|Any CPU.Build.0 = Release|Any CPU
{6DA041E1-08F7-4FEB-8201-252D03BE5D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DA041E1-08F7-4FEB-8201-252D03BE5D34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DA041E1-08F7-4FEB-8201-252D03BE5D34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DA041E1-08F7-4FEB-8201-252D03BE5D34}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {01C3A74D-113A-49E8-9AC1-D323643747A6}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6C32EC6B-CF2B-4032-B536-28900D5D52F0}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Elimination</RootNamespace>
<AssemblyName>Elimination</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,162 @@
/* Shaun Marquardt
* TINFO 200
* CS3: Elimination
* ****************************************************
* Change History
* Date Developer Description
* 2020-02-18 marqusa File creation and initial implementation, Microsoft
*
* REFERENCES
* https://docs.microsoft.com/en-us/dotnet/api/system.array.resize?view=netframework-4.8
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Elimination
{
class Program
{
/* This is a program that asks the user for five numbers
* between 1 and 100 inclusive to be input.
* It uses a one-dimensional array, and as the number is read,
* the program will display the number only if it's not a duplicate
* of a number already read.
*
* This program has the following requirements:
* 1) There must be 5 input values that are ultimately accepted
* by the program before it is halted.
* 2) To be accepted, the value must be between 10-100 inclusive.
* 3) To be accepted, the value must be unique having never been
* entered BEFORE that point in time.
* 4) As each value is accepted, the program displays the contents
* of the unique set of values gathered so far.
*/
static void Main(string[] args)
{
//Initialize variables.
int[] eliminationArray = new int[0];
int userInputNumber;
// user interface
// 1 - sell the user of the software to the user
// 2 - instructions (basic) on how to use the software
Console.WriteLine(@"
****************************************************
********** Welcome to the Elimination App **********
****************************************************
This program will ask you, the user, for five numbers
to be input and display only the unique values that
were provided. It can be used to deduplicate
PIN numbers, combination locks, or anywhere where
a sequence of 1 to 5 unique values is required.
You will be asked to provide five whole numbers between
1 and 100 inclusively, such as 12, 42, 39, 98, etc.
Please watch the printed warnings about input types
carefully so that you don't crash the program!
****************************************************
");
/* This for loop will prompt and ask the user for
* input a total of five times.
*
* Implements Requirement 1:
* There must be 5 input values that are ultimately accepted
* by the program before it is halted.
*/
for (int i = 0; i < 5; i++)
{
//INPUT
//Requirement 2 (10-100 inclusive)
//is implemented in GetNumber.
userInputNumber = GetNumber();
//PROCESSING
/* If-check to implement requirement 3:
* To be accepted, the value must be unique having never been
* entered BEFORE that point in time.
* So if the eliminationArray DOES NOT contain the
* input number, add it to the array.
*/
if (!eliminationArray.Contains(userInputNumber))
{
//Add one more element to the elimination array
//ensuring we use the smallest possible array for each
//run of the program.
//Ref: Microsoft
Array.Resize(ref eliminationArray, eliminationArray.Length + 1);
//Insert the unique number into the end of the array.
eliminationArray[eliminationArray.Length - 1] = userInputNumber;
}
//OUTPUT
/* Implement Requirement 4: As each value is accepted,
* the program displays the contents of the unique set
* of values gathered so far.
*/
Console.Write($"The current unique values are: ");
//Instead of writing a standard loop, I can write it
//as an expression-bodied lamda statement.
//Convert the eliminationArray ToList, and iterate using ForEach method.
//"item" goes to "console.write <current unique integer in the array>"
eliminationArray.ToList().ForEach(item => Console.Write($"{item.ToString()} "));
//Insert some space bewtween the output and our next prompt.
Console.WriteLine();
} //end for
//salutation
Console.WriteLine("\nThank you for using this program! Good bye!");
} //end main
/* Gets a number from the user on the console.
* Implements Requirement 2: To be accepted, the
* value must be between 10-100 inclusive.
*
* Preconditions: not yet
* Inputs: no args
* Outputs: integer
* Postconditions: not yet
* Ref: marqusa / cs2 barchart
*/
private static int GetNumber()
{
//PROCESSING SECTION
//setup variables
bool isValidNumber = false;
int userInputNumber;
//Loop to check for valid input between 10-100.
do
{
//Prompt the user for input.
Console.Write("Please enter a whole number from 10-100: ");
//Store the input as an integer in the userInputNumber variable.
userInputNumber = int.Parse(Console.ReadLine());
//If the number is between 10 and 100 inclusive
//the input is valid. Set the isValidNumber boolean value
//to true to break out of the while loop.
if (userInputNumber >= 10 && userInputNumber <= 100)
isValidNumber = true;
//If the number is not valid, inform the user and return to the start of do..while
if (!isValidNumber)
Console.WriteLine("Sorry, that's not a valid number.");
}
while (!isValidNumber);
//Return the valid input number, between 10 and 100 inclusive.
return userInputNumber;
} //END GetNumber
} // END class Program
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Elimination")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Elimination")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6c32ec6b-cf2b-4032-b536-28900d5d52f0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="TicTacToe.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<userSettings>
<TicTacToe.Properties.Settings>
<setting name="PlayVsCPU" serializeAs="String">
<value>False</value>
</setting>
<setting name="CPUAsPlayer" serializeAs="String">
<value>2</value>
</setting>
</TicTacToe.Properties.Settings>
</userSettings>
</configuration>

332
Cs3Apps/TicTacToe/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,332 @@
/* The 'codebehind' the Form1.cs GUI interface.
* This is Microsoft Visual Studio generated code.
* It has not been mucked with by hand, all the code
* seen here was generated by Visual Studio.
*/
namespace TicTacToe
{
partial class frmTicTacToe
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tlpProgramControls = new System.Windows.Forms.TableLayoutPanel();
this.mainMenuStrip = new System.Windows.Forms.MenuStrip();
this.gameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.newGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.playVsCPUToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cPUAsPlayer1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cPUAsPlayer2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.quitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.lblPlayerTurn = new System.Windows.Forms.Label();
this.tlpMainGame = new System.Windows.Forms.TableLayoutPanel();
this.lbl22 = new System.Windows.Forms.Label();
this.lbl21 = new System.Windows.Forms.Label();
this.lbl12 = new System.Windows.Forms.Label();
this.lbl11 = new System.Windows.Forms.Label();
this.lbl20 = new System.Windows.Forms.Label();
this.lbl10 = new System.Windows.Forms.Label();
this.lbl02 = new System.Windows.Forms.Label();
this.lbl01 = new System.Windows.Forms.Label();
this.lbl00 = new System.Windows.Forms.Label();
this.CPUTurnTimer = new System.Windows.Forms.Timer(this.components);
this.tlpProgramControls.SuspendLayout();
this.mainMenuStrip.SuspendLayout();
this.tlpMainGame.SuspendLayout();
this.SuspendLayout();
//
// tlpProgramControls
//
this.tlpProgramControls.ColumnCount = 2;
this.tlpProgramControls.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpProgramControls.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpProgramControls.Controls.Add(this.mainMenuStrip, 0, 0);
this.tlpProgramControls.Controls.Add(this.lblPlayerTurn, 1, 0);
this.tlpProgramControls.Dock = System.Windows.Forms.DockStyle.Top;
this.tlpProgramControls.Location = new System.Drawing.Point(0, 0);
this.tlpProgramControls.Name = "tlpProgramControls";
this.tlpProgramControls.RowCount = 1;
this.tlpProgramControls.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpProgramControls.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 41F));
this.tlpProgramControls.Size = new System.Drawing.Size(800, 41);
this.tlpProgramControls.TabIndex = 2;
//
// mainMenuStrip
//
this.mainMenuStrip.GripMargin = new System.Windows.Forms.Padding(2, 2, 0, 2);
this.mainMenuStrip.ImageScalingSize = new System.Drawing.Size(24, 24);
this.mainMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.gameToolStripMenuItem});
this.mainMenuStrip.Location = new System.Drawing.Point(0, 0);
this.mainMenuStrip.Name = "mainMenuStrip";
this.mainMenuStrip.Size = new System.Drawing.Size(400, 36);
this.mainMenuStrip.TabIndex = 0;
this.mainMenuStrip.Text = "mainMenuStrip";
//
// gameToolStripMenuItem
//
this.gameToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.newGameToolStripMenuItem,
this.playVsCPUToolStripMenuItem,
this.quitToolStripMenuItem});
this.gameToolStripMenuItem.Name = "gameToolStripMenuItem";
this.gameToolStripMenuItem.Size = new System.Drawing.Size(74, 32);
this.gameToolStripMenuItem.Text = "&Game";
//
// newGameToolStripMenuItem
//
this.newGameToolStripMenuItem.Name = "newGameToolStripMenuItem";
this.newGameToolStripMenuItem.Size = new System.Drawing.Size(213, 34);
this.newGameToolStripMenuItem.Text = "&New Game";
this.newGameToolStripMenuItem.Click += new System.EventHandler(this.newGameToolStripMenuItem_Click);
//
// playVsCPUToolStripMenuItem
//
this.playVsCPUToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.cPUAsPlayer1ToolStripMenuItem,
this.cPUAsPlayer2ToolStripMenuItem});
this.playVsCPUToolStripMenuItem.Name = "playVsCPUToolStripMenuItem";
this.playVsCPUToolStripMenuItem.Size = new System.Drawing.Size(213, 34);
this.playVsCPUToolStripMenuItem.Text = "Play vs &CPU";
this.playVsCPUToolStripMenuItem.Click += new System.EventHandler(this.playVsCPUToolStripMenuItem_Click);
//
// cPUAsPlayer1ToolStripMenuItem
//
this.cPUAsPlayer1ToolStripMenuItem.Name = "cPUAsPlayer1ToolStripMenuItem";
this.cPUAsPlayer1ToolStripMenuItem.Size = new System.Drawing.Size(236, 34);
this.cPUAsPlayer1ToolStripMenuItem.Text = "CPU as Player 1";
this.cPUAsPlayer1ToolStripMenuItem.Click += new System.EventHandler(this.cPUAsPlayer1ToolStripMenuItem_Click);
//
// cPUAsPlayer2ToolStripMenuItem
//
this.cPUAsPlayer2ToolStripMenuItem.Name = "cPUAsPlayer2ToolStripMenuItem";
this.cPUAsPlayer2ToolStripMenuItem.Size = new System.Drawing.Size(236, 34);
this.cPUAsPlayer2ToolStripMenuItem.Text = "CPU as Player 2";
this.cPUAsPlayer2ToolStripMenuItem.Click += new System.EventHandler(this.cPUAsPlayer2ToolStripMenuItem_Click);
//
// quitToolStripMenuItem
//
this.quitToolStripMenuItem.Name = "quitToolStripMenuItem";
this.quitToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
this.quitToolStripMenuItem.Size = new System.Drawing.Size(213, 34);
this.quitToolStripMenuItem.Text = "&Quit";
this.quitToolStripMenuItem.Click += new System.EventHandler(this.quitToolStripMenuItem_Click);
//
// lblPlayerTurn
//
this.lblPlayerTurn.AutoSize = true;
this.lblPlayerTurn.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblPlayerTurn.Location = new System.Drawing.Point(403, 0);
this.lblPlayerTurn.Name = "lblPlayerTurn";
this.lblPlayerTurn.Size = new System.Drawing.Size(394, 41);
this.lblPlayerTurn.TabIndex = 1;
this.lblPlayerTurn.Text = "Player Turn: **GAME OVER **\nClick to Start";
this.lblPlayerTurn.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// tlpMainGame
//
this.tlpMainGame.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Outset;
this.tlpMainGame.ColumnCount = 3;
this.tlpMainGame.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.Controls.Add(this.lbl22, 2, 2);
this.tlpMainGame.Controls.Add(this.lbl21, 1, 2);
this.tlpMainGame.Controls.Add(this.lbl12, 2, 1);
this.tlpMainGame.Controls.Add(this.lbl11, 1, 1);
this.tlpMainGame.Controls.Add(this.lbl20, 0, 2);
this.tlpMainGame.Controls.Add(this.lbl10, 0, 1);
this.tlpMainGame.Controls.Add(this.lbl02, 2, 0);
this.tlpMainGame.Controls.Add(this.lbl01, 1, 0);
this.tlpMainGame.Controls.Add(this.lbl00, 0, 0);
this.tlpMainGame.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpMainGame.Location = new System.Drawing.Point(0, 41);
this.tlpMainGame.Name = "tlpMainGame";
this.tlpMainGame.RowCount = 3;
this.tlpMainGame.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tlpMainGame.Size = new System.Drawing.Size(800, 409);
this.tlpMainGame.TabIndex = 3;
//
// lbl22
//
this.lbl22.AutoSize = true;
this.lbl22.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl22.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl22.Location = new System.Drawing.Point(537, 272);
this.lbl22.Name = "lbl22";
this.lbl22.Size = new System.Drawing.Size(258, 135);
this.lbl22.TabIndex = 8;
this.lbl22.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl22.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl21
//
this.lbl21.AutoSize = true;
this.lbl21.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl21.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl21.Location = new System.Drawing.Point(271, 272);
this.lbl21.Name = "lbl21";
this.lbl21.Size = new System.Drawing.Size(258, 135);
this.lbl21.TabIndex = 7;
this.lbl21.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl21.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl12
//
this.lbl12.AutoSize = true;
this.lbl12.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl12.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl12.Location = new System.Drawing.Point(537, 137);
this.lbl12.Name = "lbl12";
this.lbl12.Size = new System.Drawing.Size(258, 133);
this.lbl12.TabIndex = 6;
this.lbl12.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl12.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl11
//
this.lbl11.AutoSize = true;
this.lbl11.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl11.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl11.Location = new System.Drawing.Point(271, 137);
this.lbl11.Name = "lbl11";
this.lbl11.Size = new System.Drawing.Size(258, 133);
this.lbl11.TabIndex = 5;
this.lbl11.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl11.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl20
//
this.lbl20.AutoSize = true;
this.lbl20.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl20.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl20.Location = new System.Drawing.Point(5, 272);
this.lbl20.Name = "lbl20";
this.lbl20.Size = new System.Drawing.Size(258, 135);
this.lbl20.TabIndex = 4;
this.lbl20.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl20.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl10
//
this.lbl10.AutoSize = true;
this.lbl10.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl10.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl10.Location = new System.Drawing.Point(5, 137);
this.lbl10.Name = "lbl10";
this.lbl10.Size = new System.Drawing.Size(258, 133);
this.lbl10.TabIndex = 3;
this.lbl10.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl10.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl02
//
this.lbl02.AutoSize = true;
this.lbl02.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl02.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl02.Location = new System.Drawing.Point(537, 2);
this.lbl02.Name = "lbl02";
this.lbl02.Size = new System.Drawing.Size(258, 133);
this.lbl02.TabIndex = 2;
this.lbl02.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl02.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl01
//
this.lbl01.AutoSize = true;
this.lbl01.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl01.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl01.Location = new System.Drawing.Point(271, 2);
this.lbl01.Name = "lbl01";
this.lbl01.Size = new System.Drawing.Size(258, 133);
this.lbl01.TabIndex = 1;
this.lbl01.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl01.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// lbl00
//
this.lbl00.AutoSize = true;
this.lbl00.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbl00.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lbl00.Location = new System.Drawing.Point(5, 2);
this.lbl00.Name = "lbl00";
this.lbl00.Size = new System.Drawing.Size(258, 133);
this.lbl00.TabIndex = 0;
this.lbl00.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lbl00.Click += new System.EventHandler(this.GameBoardLbl_Click);
//
// CPUTurnTimer
//
this.CPUTurnTimer.Tick += new System.EventHandler(this.CPUTurnTimer_Tick);
//
// frmTicTacToe
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.tlpMainGame);
this.Controls.Add(this.tlpProgramControls);
this.Name = "frmTicTacToe";
this.Text = "Tic Tac Toe";
this.Load += new System.EventHandler(this.frmTicTacToe_Load);
this.tlpProgramControls.ResumeLayout(false);
this.tlpProgramControls.PerformLayout();
this.mainMenuStrip.ResumeLayout(false);
this.mainMenuStrip.PerformLayout();
this.tlpMainGame.ResumeLayout(false);
this.tlpMainGame.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tlpProgramControls;
private System.Windows.Forms.MenuStrip mainMenuStrip;
private System.Windows.Forms.ToolStripMenuItem gameToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem newGameToolStripMenuItem;
private System.Windows.Forms.TableLayoutPanel tlpMainGame;
private System.Windows.Forms.Label lbl10;
private System.Windows.Forms.Label lbl02;
private System.Windows.Forms.Label lbl01;
private System.Windows.Forms.Label lbl00;
private System.Windows.Forms.Label lbl22;
private System.Windows.Forms.Label lbl21;
private System.Windows.Forms.Label lbl12;
private System.Windows.Forms.Label lbl11;
private System.Windows.Forms.Label lbl20;
private System.Windows.Forms.ToolStripMenuItem playVsCPUToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem quitToolStripMenuItem;
private System.Windows.Forms.Label lblPlayerTurn;
private System.Windows.Forms.ToolStripMenuItem cPUAsPlayer1ToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem cPUAsPlayer2ToolStripMenuItem;
private System.Windows.Forms.Timer CPUTurnTimer;
}
}

472
Cs3Apps/TicTacToe/Form1.cs Normal file
View File

@ -0,0 +1,472 @@
/* Shaun Marquardt
* TINFO 200
* CS3: TicTacToe
* ****************************************************
* Change History
* Date Developer Description
* 2020-02-18 marqusa File creation and initial implementation,
* Martyr2 (Coders Lexicon), Microsoft, Chuck Costarella L5Life
* 2020-02-22 marqusa Add functionality to clear the game board labels.
* Implement Winner and Draw Game.
* Completed program, add documentation.
* 2020-02-23 marqusa Add functionality to have CPU play as player 1 or player 2.
* Moved winner stuff out of GameLbl_Click
* 2020-02-24 marqusa Fixed the form menu system for Play vs CPU checkboxes,
* they were acting funky. Split PlayVsCPU(int turn) into new function.
* Also updated the CPUTimer_Tick to do nothing
* if the game is over.
*
* The Form1.cs class acts as the primary driver for the TicTacToe class
* which actually plays the game proper. Most of my comments regarding how
* the game actually works will be in the TicTacToe.cs file.
*
* Recieves a delegate event from TicTacToe to update the label in the cell
* that was clicked after the 3x3 2d array called 'gameBoard' in the
* TicTacToe class gets updated
*
* REFERENCES
* https://www.coderslexicon.com/passing-data-between-forms-using-delegates-and-events/
* https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.controlcollection.find?view=netframework-4.8
* https://docs.microsoft.com/en-us/dotnet/api/system.eventargs?view=netframework-4.8
*
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TicTacToe
{
public partial class frmTicTacToe : Form
{
/* This is a program to play the classic game,
* Tic-Tac-Toe. The form you see displayed (and this class)
* is primarily a driver for the TicTacToe class
* which actually plays the game behind the scenes.
*
* Requirements:
* 1) Class TicTacToe enables us to create a complete app to play
* the game of Tic-Tac-Toe.
* 2) This class contains a private 3x3 rectangular array of integers.
* 3) The constructor initializes the empty board.
* 4) Each move should be in an empty square.
* 5) Determine win, lose, or draw.
*
* Extra Credit:
* The app is developed using a Windows Form application.
* It is possible to play vs CPU with CPU as Player 1 or Player 2.
*
* Extra Fun Stuff:
* The game actively tracks the current player's turn.
* I used an enum for both player turn and X and O.
* I included a delegate and custom event args to pass
* data from the TicTacToe class and update the correct label.
* The game is really handled by basically everything in the
* TicTacToe class with the form as a GUI frontend.
*/
//Create a new instance of the TicTacToe class
// and store it as a new object called 'game'.
TicTacToe game;
//Visual studio generated code.
public frmTicTacToe()
{
InitializeComponent();
}
/* Update the label in a given row/column with X or O
* according to what XorO enum value was placed using a delegate.
* Ref: Martyr2, Coders Lexicon'
* Preconditions: not yet
* Inputs: object sender, TicTacToe.RowColumnEventArgs e
* Outputs: void return
* Postconditions: not yet
*/
public void MessageReceived(object sender, EventArgs e)
{
//Ref: Microsoft, EventArgs
TicTacToe.RowColumnEventArgs args = (TicTacToe.RowColumnEventArgs)e;
//DEBUGGING:
//MessageBox.Show($"row: {args.row} col: {args.col}");
//Construct the label name we need.
string lblName = $"lbl{args.row}{args.col}";
//Get the label by constructed name.
//ref: microsoft, Controls.Find
Label theLabel = (Label)this.Controls.Find(lblName, true)[0];
//Place an X or an O in the square.
//Not playing against CPU is the easy case.
//Player 1 is always X. Player 2 is O
if (!Properties.Settings.Default.PlayVsCPU)
{
if (game.CurrentPlayerTurn == TicTacToe.PlayerTurn.Player1)
theLabel.Text = TicTacToe.XorO.x.ToString();
else
theLabel.Text = TicTacToe.XorO.o.ToString();
}
else //We are playing against CPU.
{
//If it's the CPU turn, place the CPU move.
if (game.CurrentPlayerTurn == TicTacToe.PlayerTurn.CPU)
{
if (Properties.Settings.Default.CPUAsPlayer == 1)
{
theLabel.Text = TicTacToe.XorO.x.ToString();
}
else //CPU as player 2.
{
theLabel.Text = TicTacToe.XorO.o.ToString();
}
}
else //It's the player's turn
{
//The CPU is player 1, place an O for human's move.
if (Properties.Settings.Default.CPUAsPlayer == 1)
theLabel.Text = TicTacToe.XorO.o.ToString();
else //The CPU is player 2, place an X for human's move.
theLabel.Text = TicTacToe.XorO.x.ToString();
}
}
}
/* Visual studio generated delegate
* on form load. Instansiates a new TicTacToe class
* and stores it into the game object.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void frmTicTacToe_Load(object sender, EventArgs e)
{
//Pass the current TicTacToe form into the TicTacToe class
//so the event handler delegate can be hooked in and we
//can change the label in the tableGridView from the TicTacToe class.
game = new TicTacToe(this);
//If we are playing as CPU
if (Properties.Settings.Default.PlayVsCPU)
{
playVsCPUToolStripMenuItem.Checked = true;
//Check the CPU as player 1 tool strip menu item
if (Properties.Settings.Default.CPUAsPlayer == 1)
{
cPUAsPlayer1ToolStripMenuItem.Checked = true;
}
else //Check the CPU as player 2 tool strip menu item.
{
cPUAsPlayer2ToolStripMenuItem.Checked = true;
}
}
/* Start the timer to watch for CPU Turn.
* This must be outside the if statement
* as "Play vs CPU" can be checked (or unchecked) anytime
* there is a "Game Over" status.
*/
CPUTurnTimer.Start();
}
/* Starts a new game on Game > New Game click.
* Visual Studio Generated Delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
{
game.StartNewGame();
ClearGameLabels();
//Must set GameOver to true here
//so if the user clicks the new game menu item
//it is also possible to click the "Play vs CPU"
//menu item/option.
game.GameOver = true;
}
/* Clear all the labels on the board of X or O.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void ClearGameLabels()
{
//Loop through each control docked in the
//table main game layout panel that holds all
//the labels for Xs and Os to go into.
foreach (var tlpControl in tlpMainGame.Controls)
{
Label label = (Label)tlpControl;
label.Text = string.Empty;
}
//Reset the player turn to Game Over.
lblPlayerTurn.Text = "Player Turn: **GAME OVER **\nClick to Start";
}
/* Quit the game and exits the application.
* Visual Studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void quitToolStripMenuItem_Click(object sender, EventArgs e)
{
//Salutation
MessageBox.Show("Thank you for playing! Good bye!");
Environment.Exit(0);
}
/* This is the main delegate that is called when a player
* clicks a position on the game board to play the game.
* Visual Studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void GameBoardLbl_Click(object sender, EventArgs e)
{
//If the game is over, start a new game.
if (game.GameOver)
{
game.StartNewGame();
ClearGameLabels();
//If the player is playing against CPU
//and CPU is player 1, adjust the turn to CPU turn.
if (Properties.Settings.Default.PlayVsCPU
&& Properties.Settings.Default.CPUAsPlayer == 1)
game.CurrentPlayerTurn = TicTacToe.PlayerTurn.CPU;
}
//If the player is playing against the CPU
//and it is not their CurrentPlayerTurn, do nothing.
if (Properties.Settings.Default.PlayVsCPU && game.CurrentPlayerTurn == TicTacToe.PlayerTurn.CPU)
return;
//Get the name of the label and parse it to find out our indexes.
Label clickedGamePosition = (Label)sender;
//Do not allow placing a move in a taken position.
if (clickedGamePosition.Text != "")
return;
//Each label is named 'lblXX' where XX is the row and column
//that was clicked. So first pick off 'lbl', to leave 'xx'
string rowColumn = clickedGamePosition.Name.Remove(0, 3);
//Now get the row and column.
//ToString() must be called as rowColumn[x] returns type char.
int row = int.Parse(rowColumn[0].ToString());
int col = int.Parse(rowColumn[1].ToString());
//Take the current player's CurrentPlayerTurn.
game.TakePlayerTurn(game.CurrentPlayerTurn, row, col);
//Swap to the next player's CurrentPlayerTurn.
TicTacToe.XorO winningPlayer = game.TogglePlayerTurn(game.CurrentPlayerTurn);
//Update the player turn label
string playerStr = (game.CurrentPlayerTurn.ToString() == TicTacToe.PlayerTurn.CPU.ToString()) ? "CPU (THINKING...)" : game.CurrentPlayerTurn.ToString();
lblPlayerTurn.Text = $"Player turn: {playerStr}";
//Update winner
//Check for a winner which will overwrite the turn label.
UpdateWinner(winningPlayer);
} //GameBoardLbl_Click
/* Update the form label if there is a winner.
* Preconditions: not yet
* Inputs: XorO enum winningPlayer
* Outputs: void return
* Postconditions: not yet
*/
private void UpdateWinner(TicTacToe.XorO winningPlayer)
{
//Check for a winner which will overwrite the turn label.
if (game.GameOver) //There is a winner
{
string winningPlayerText = "**WINNER**: ";
//Not playing against CPU, easy case.
if (!Properties.Settings.Default.PlayVsCPU)
{
if (winningPlayer == TicTacToe.XorO.x) //Player 1 wins.
winningPlayerText += "Player 1";
else if (winningPlayer == TicTacToe.XorO.o)
winningPlayerText += "Player 2"; //Player 2 wins.
else
winningPlayerText = "**DRAW GAME!**";
}
else // (PLAY VS CPU)
{
//Player 1 CPU Wins
if (winningPlayer == TicTacToe.XorO.x && Properties.Settings.Default.CPUAsPlayer == 1)
winningPlayerText += "CPU";
else if (winningPlayer == TicTacToe.XorO.x) //Player 1 Wins
winningPlayerText += "Player 1";
else if (winningPlayer == TicTacToe.XorO.o && Properties.Settings.Default.CPUAsPlayer == 2) //player 2 cpu wins
winningPlayerText += "CPU";
else if (winningPlayer == TicTacToe.XorO.o) // player 2 wins
winningPlayerText += "Player 2";
else //Draw Game.
winningPlayerText = "**DRAW GAME!**";
} //end else
//Add Game Over text.
winningPlayerText += "\n **GAME OVER** - Click to Start";
//Update the player turn label with the winner.
lblPlayerTurn.Text = winningPlayerText;
} // if GameOver
} //UpdateWinner
/* Sets CPU as Player 1
* Visual Studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void cPUAsPlayer1ToolStripMenuItem_Click(object sender, EventArgs e)
{
//If we are playing vs CPU and If the current box for
//P1 CPU is checked, Clear PlayVsCPU options.
if (Properties.Settings.Default.PlayVsCPU && cPUAsPlayer1ToolStripMenuItem.Checked == true)
{
SetPlayVsCPU(0);
}
else //We are not currently playing vs CPU. Start doing so with CPU as player 1.
{
SetPlayVsCPU(1);
}
}
/* Sets CPU as Player 2
* Visual Studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void cPUAsPlayer2ToolStripMenuItem_Click(object sender, EventArgs e)
{
//If we are playing vs CPU and If the current box for
//P2 CPU is checked, Clear PlayVsCPU options.
if (Properties.Settings.Default.PlayVsCPU && cPUAsPlayer2ToolStripMenuItem.Checked == true)
{
SetPlayVsCPU(0);
}
else //We are not currently playing vs CPU. Start doing so with CPU as player 2.
{
SetPlayVsCPU(2);
}
}
/* Clears playing vs CPU if set.
* Visual Studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void playVsCPUToolStripMenuItem_Click(object sender, EventArgs e)
{
if(Properties.Settings.Default.PlayVsCPU)
SetPlayVsCPU(0);
}
/* Set the correct menu checkboxes and application settings.
* called from the menu tool strip delegate events.
* Preconditions: not yet
* Inputs: int cpuAsPlayer
* Outputs: void return
* Postconditions: not yet
*/
private void SetPlayVsCPU(int cpuAsPlayer)
{
//If the game is not over, alert the player.
if (!game.GameOver)
{
MessageBox.Show("A game is already underway, start a new one.");
return;
}
//Set the correct menu checkboxes and application settings.
Properties.Settings.Default.CPUAsPlayer = cpuAsPlayer;
switch (cpuAsPlayer)
{
case 0:
Properties.Settings.Default.PlayVsCPU = false;
playVsCPUToolStripMenuItem.Checked = false;
cPUAsPlayer1ToolStripMenuItem.Checked = false;
cPUAsPlayer2ToolStripMenuItem.Checked = false;
break;
case 1: //CPU as player 1
Properties.Settings.Default.PlayVsCPU = true;
playVsCPUToolStripMenuItem.Checked = true;
cPUAsPlayer1ToolStripMenuItem.Checked = true;
cPUAsPlayer2ToolStripMenuItem.Checked = false;
break;
case 2: //CPU as player 2
Properties.Settings.Default.PlayVsCPU = true;
playVsCPUToolStripMenuItem.Checked = true;
cPUAsPlayer1ToolStripMenuItem.Checked = false;
cPUAsPlayer2ToolStripMenuItem.Checked = true;
break;
}
//Save the settings.
Properties.Settings.Default.Save();
} //SetPlayVsCPU
/* Game timer delegate to watch for the CPU Turn.
* Visual studio generated delegate.
* Preconditions: not yet
* Inputs: object sender, EventArgs e
* Outputs: void return
* Postconditions: not yet
*/
private void CPUTurnTimer_Tick(object sender, EventArgs e)
{
//If the game is over, do not take a CPU turn.
if (game.GameOver)
return;
TicTacToe.XorO winningPlayer;
string playerStr = string.Empty;
//Take the CPU turn.
if (game.CurrentPlayerTurn == TicTacToe.PlayerTurn.CPU)
{
//Row and col can be 0,0 here as TakeCPUTurn will be called
//which will randomly pick a row/col to play in.
game.TakeCPUTurn();
//Swap to the next player's turn
winningPlayer = game.TogglePlayerTurn(game.CurrentPlayerTurn);
//Update the player turn label after CPU turn.
playerStr = (game.CurrentPlayerTurn.ToString() == TicTacToe.PlayerTurn.CPU.ToString()) ? "CPU (THINKING...)" : game.CurrentPlayerTurn.ToString();
lblPlayerTurn.Text = $"Player turn: {playerStr}";
UpdateWinner(winningPlayer);
}
} //CPUTurnTimer_Tick
} // frmTicTacToe
}

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="mainMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>18, 13</value>
</metadata>
<metadata name="CPUTurnTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>205, 13</value>
</metadata>
</root>

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TicTacToe
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmTicTacToe());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TicTacToe")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TicTacToe")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6da041e1-08f7-4feb-8201-252d03be5d34")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TicTacToe.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TicTacToe.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TicTacToe.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool PlayVsCPU {
get {
return ((bool)(this["PlayVsCPU"]));
}
set {
this["PlayVsCPU"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("2")]
public int CPUAsPlayer {
get {
return ((int)(this["CPUAsPlayer"]));
}
set {
this["CPUAsPlayer"] = value;
}
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="TicTacToe.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="PlayVsCPU" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="CPUAsPlayer" Type="System.Int32" Scope="User">
<Value Profile="(Default)">2</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,426 @@
/* Shaun Marquardt
* TINFO 200
* CS3: TicTacToe
* ****************************************************
* Change History
* Date Developer Description
* 2020-02-18 marqusa File creation and initial implementation,
* Martyr2 (Coders Lexicon), Microsoft, Chuck Costarella L5Life
* 2020-02-22 marqusa Implement TakeCPUTurn.
* Implement draw game scenario (Thanks, Wargames).
* 2020-02-23 marqusa Add functionality to have CPU play as player 1 or player 2.
*
* REFERENCES
* https://www.coderslexicon.com/passing-data-between-forms-using-delegates-and-events/
* https://docs.microsoft.com/en-us/dotnet/api/system.eventargs?view=netframework-4.8
*
* AND NOW In English, a more descriptive part of what is going on here.
* -----------------
* So the first thing that happens on Form1_Load, is the form will instantiate
* a new TicTacToe class and pass in the form to the constructor.
* The constructor will attach the form delegate and initialize the game board
* along with setting the GameOver variable to False.
*
* When a label is clicked, a specific row and column is passed to TakePlayerTurn
* along with the current player's turn identifier (by PlayerTurn enum type).
*
* TakePlayerTurn will check for a winner using CheckForWinner.
*
* CheckForWinner will set GameOver to TRUE if win or draw.
* if win, returns winning player's X or O symbol using XorO enum type.
* If draw, still sets GameOver to TRUE, but returns NONE XorO enum type.
*
* After that, the player turn will be toggled using TogglePlayerTurn, to
* signal to the players and the game whose turn it is.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToe
{
class TicTacToe
{
/* This is the class to play the classic game,
* Tic-Tac-Toe. The form you see displayed (Form1.cs)
* is primarily a driver for this TicTacToe class
* which actually plays the game behind the scenes.
*
* Requirements:
* 1) Class TicTacToe enables us to create a complete app to play
* the game of Tic-Tac-Toe.
* 2) This class contains a private 3x3 rectangular array of integers.
* 3) The constructor initializes the empty board.
* 4) Each move should be in an empty square.
* 5) Determine win, lose, or draw.
*
* Extra Credit:
* The app is developed using a Windows Form application.
* It is possible to play vs CPU as CPU player 1 or player 2.
*
* Extra Fun Stuff:
* The game actively tracks the current player's turn.
* I used an enum for both player turn and X and O.
* I included a delegate and custom event args to pass
* data from the TicTacToe class and update the correct label.
* The game is really handled by basically everything in this
* TicTacToe class with the form as a GUI frontend.
*/
//Game Over auto-implemented property
//with internal set
public bool GameOver { get; internal set; }
//Current player turn is of type enum PlayerTurn.
//with internal set
//This helps the game track whose turn it currently is.
public PlayerTurn CurrentPlayerTurn { get; internal set; }
//The class contains a private 3-by-3 rectangular array of integers.
private int[,] gameBoard;
//Enum XorO describes X as 1, O as 2, and none as 0.
//We need a 'none' value to help pass along 'nothing'
//or the winning player back to the form on TogglePlayerTurn.
public enum XorO
{
none = 0,
x = 1,
o = 2
}
//Enum PlayerTurn helps track which player's turn it is
//using Player 1=1, Player2=2, and CPU=3.
public enum PlayerTurn
{
Player1 = 1,
Player2 = 2,
CPU = 3
}
//Delegates to pass data to the GUI Form. Ref: Coder's Lexicon
public delegate void SendMessage(object obj, EventArgs e);
public event SendMessage OnSendMessage;
//An eventarg class to send to the GUI form via the delegate. Ref: Microsoft
public class RowColumnEventArgs : EventArgs
{
public int row { get; set; }
public int col { get; set; }
}
// Class constructor
// 1 - Create the object - chunk out memory on the heap for the actual storage.
// 2 - initialize all relevant variables to reasonable defaults.
public TicTacToe(frmTicTacToe frm)
{
//Construct a 3x3 game board.
gameBoard = new int[3, 3];
//The constructor should initialize the empty board to all blank's.
InitializeGameBoard();
//Set the game to be "over"
GameOver = true;
//form driver, says "attach its MessageReceived function to the event"
OnSendMessage += frm.MessageReceived;
}
//Initializes the game board to the start state of raw storage
//Preconditions: not yet
//Inputs: no args
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella, L5Life
private void InitializeGameBoard()
{
//iterate through each row
for (int r = 0; r < 3; r++)
{
//iterate through each column in an individual row
for (int c = 0; c < 3; c++)
{
//init all cells in the game board to the init start status - none
gameBoard[r,c] = (int)XorO.none;
}
}
}
/* Starts a new game.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
internal void StartNewGame()
{
//Start the game.
GameOver = false;
//Reset the game board.
InitializeGameBoard();
//Set to the first player's CurrentPlayerTurn.
CurrentPlayerTurn = PlayerTurn.Player1;
}
/* Take a given player's turn.
* Preconditions: not yet
* Inputs: PlayerTurn, row, col
* Outputs: void return
* Postconditions: not yet
*/
internal void TakePlayerTurn(PlayerTurn playerTurn, int row, int col)
{
//If the game's over, don't take any more turns.
if (GameOver)
return;
//If the requested row or column is already taken, don't make a move.
//Do not allow placing a move in a spot that already has been placed.
if (gameBoard[row,col] != 0)
return;
//ref: Microsoft
RowColumnEventArgs args = new RowColumnEventArgs();
args.row = row;
args.col = col;
switch (playerTurn)
{
case PlayerTurn.Player1: //Take the first player's CurrentPlayerTurn.
if(gameBoard[row,col] == (int)XorO.none)
{
gameBoard[row, col] = (int)XorO.x; //The first player is X.
OnSendMessage?.Invoke(this, args); //ref: Coder's Lexicon
}
break;
case PlayerTurn.Player2: //Take the second player's turn.
if (gameBoard[row, col] == (int)XorO.none)
{
gameBoard[row, col] = (int)XorO.o; //The second player is O.
OnSendMessage?.Invoke(this, args); //ref: Coder's Lexicon
}
break;
case PlayerTurn.CPU: //Take the CPU's turn.
TakeCPUTurn();
break;
}
}
/* Take the CPU's turn. Uses Random.Next
* which automatically seeds the random number generator
* to the current system time.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
public void TakeCPUTurn()
{
//If the game is over, do nothing.
if (GameOver)
return;
//Create a new instance of the System.Random class.
//It is automatically seeded with the current system time.
Random rnd = new Random();
//Create a string list of available indexes.
//as I won't know how big the collection will be.
List<string> availableIndexes = new List<string>();
//Parse through the gameBoard and find all
//the indexes that are still 0.
//For each row in the gameboard
for (int r = 0; r < 3; r++)
{
//Iterate through each column.
for(int c = 0; c < 3; c++)
{
//If there is nothing in the current position
if(gameBoard[r,c] == 0)
{
//add it to the availableIndexes list collection.
availableIndexes.Add($"{r}{ c}");
}
}
} //end for
//no more spaces left on the game board.
if (availableIndexes.Count == 0)
{
GameOver = true;
return;
}
//Now determine where the computer is going to
//place the move.
int randomIndex = rnd.Next(0, availableIndexes.Count);
string computerMove = availableIndexes[randomIndex];
int row = int.Parse(computerMove[0].ToString());
int col = int.Parse(computerMove[1].ToString());
//Setup the event args to pass back
//to the main game form.
//ref: Microsoft
RowColumnEventArgs args = new RowColumnEventArgs();
args.row = row;
args.col = col;
//Now place the computer move in the determined
//row and column of the game board
//and update the form.
if(Properties.Settings.Default.CPUAsPlayer == 1)
gameBoard[row, col] = (int)XorO.x;
else
gameBoard[row, col] = (int)XorO.o; //The second player is O.
OnSendMessage?.Invoke(this, args); //ref: Coder's Lexicon
} //TakeCPUTurn
/* Toggles a player turn between player 1 and player 2
* or player 1 and CPU.
* Also runs the CheckForWinner function before toggling player turn.
* Preconditions: not yet
* Inputs: PlayerTurn enum type
* Outputs: XorO enum type
* Postconditions: not yet
*/
internal XorO TogglePlayerTurn(PlayerTurn playerTurn)
{
//Check for winning player before toggling player turn.
XorO winningPlayer = CheckForWinner(playerTurn);
//If we do not have a winner
if (!GameOver)
{
//Swap the player turns.
//First is the easy case: If we are not playing vs CPU
//simply swap player turn.
if(!Properties.Settings.Default.PlayVsCPU)
{
if (CurrentPlayerTurn == PlayerTurn.Player1)
CurrentPlayerTurn = PlayerTurn.Player2;
else
CurrentPlayerTurn = PlayerTurn.Player1;
}
else //We are playing against CPU.
{
//Determine if CPU is Player 1 or Player 2.
if(Properties.Settings.Default.CPUAsPlayer == 1) //CPU is player 1.
{
if (CurrentPlayerTurn == PlayerTurn.Player2)
{
CurrentPlayerTurn = PlayerTurn.CPU;
}
else
{
CurrentPlayerTurn = PlayerTurn.Player2;
}
}
else //CPU is player 2.
{
if (CurrentPlayerTurn == PlayerTurn.Player1)
{
CurrentPlayerTurn = PlayerTurn.CPU;
}
else
{
CurrentPlayerTurn = PlayerTurn.Player1;
}
}
}
} //end if !GameOver
//Return 'none' if no winning player,
//else return the winning player.
return winningPlayer;
} // TogglePlayerTurn
/* Checks for a winner.
* If we have a winner, set GameOver to True
* and return the winning player's game piece.
* Preconditions: not yet
* Inputs: PlayerTurn enum
* Outputs: XorO enum
* Postconditions: not yet
*/
private XorO CheckForWinner(PlayerTurn playerTurn)
{
//chicken dinner
bool bWinnerWinner = true;
XorO winningPlayer = XorO.none;
//Draw Game. In this foreach loop,
//bWinnerWinner is most likely set false.
foreach (var value in gameBoard)
{
//It's not a draw game.
if (value == 0)
{
bWinnerWinner = false;
break;
}
}
//Winner on a column.
for (int row = 0; row < 3; row++)
{
if(gameBoard[row,0] != 0 //rowN col0 has something in it
&& gameBoard[row,0] == gameBoard[row,1] //rowN col0 is equal to col1
&& gameBoard[row,0] == gameBoard[row,2])//and rowN col0 is equal to col2
{
bWinnerWinner = true;
//ref: chuck
Enum.TryParse<XorO>(gameBoard[row, 0].ToString(), out winningPlayer);
}
}
//Winner on a row.
for(int col = 0; col < 3; col++)
{
if (gameBoard[0, col] != 0 //rowN col0 has something in it
&& gameBoard[0, col] == gameBoard[1, col] //colN row0 is equan to row1
&& gameBoard[0, col] == gameBoard[2, col])//and colN row0 is equal to row2
{
bWinnerWinner = true;
//ref: chuck
Enum.TryParse<XorO>(gameBoard[0, col].ToString(), out winningPlayer);
}
}
//Winner diagonally.
if(gameBoard[1,1] != 0 //the middle has something in it.
&& ( (gameBoard[0,0] == gameBoard[1,1] //Winner from top left to btm right
&& gameBoard[1,1] == gameBoard[2,2])
||(gameBoard[0,2] == gameBoard[1,1] //OR winner from top rt to btm lft
&& gameBoard[2,0] == gameBoard[1,1]) )
) //end if
{
bWinnerWinner = true;
Enum.TryParse<XorO>(gameBoard[1, 1].ToString(), out winningPlayer);
}
//We have a winner or draw game.
if (bWinnerWinner)
{
//Set the game to be over.
GameOver = true;
//Return the winning player's piece.
return winningPlayer;
}
//Return no game piece as the game is not over.
return XorO.none;
}
} //CheckForWinner()
}

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6DA041E1-08F7-4FEB-8201-252D03BE5D34}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>TicTacToe</RootNamespace>
<AssemblyName>TicTacToe</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TicTacToe.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

6
GLife/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

54
GLife/GLife.csproj Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{07CD2938-EF48-458A-AAD8-8EA66D5724AF}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>GLife</RootNamespace>
<AssemblyName>GLife</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Game.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

25
GLife/GLife.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GLife", "GLife.csproj", "{07CD2938-EF48-458A-AAD8-8EA66D5724AF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{07CD2938-EF48-458A-AAD8-8EA66D5724AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07CD2938-EF48-458A-AAD8-8EA66D5724AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07CD2938-EF48-458A-AAD8-8EA66D5724AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07CD2938-EF48-458A-AAD8-8EA66D5724AF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1C933385-BCD4-4180-8D3F-994BF291729E}
EndGlobalSection
EndGlobal

392
GLife/Game.cs Normal file
View File

@ -0,0 +1,392 @@
/*
* Change History
* Date Developer Description
* 2020-01-16 marqusa File creation and initial implementation -- Charles Costarella
* 2020-01-28 marqusa Game Board Initialization --Charles Costarella
* Process game board, determine if cell is dead or alive
* Add main game rule logic & count neighbors.
* Add a StreamWriter to write out the gameboard per generation to a file.
*/
using System;
using System.IO;
namespace GLife
{
//ref: Chuck Costarella
public class Game
{
public StreamWriter outfile;
//const has to be assigned immediately and can never be changed.
//Readonly does not need to be assigned immediately.
// once readonly is assigned, can never be changed.
// size the game boards
public const int ROW_SIZE = 32;
public const int COL_SIZE = 120;
//Define characters for dead or alive cells.
public const char DEAD = '-';
public const char LIVE = 'o';
// game boards
//initialize board as two dimentional array
private char[,] gameBoard;
private char[,] tempBoard;
// Class constructor
// 1 - Create the object - chunk out memory on the heap for the actual storage.
// 2 - initialize all relevant variables to reasonable defaults.
public Game()
{
//Create a new file with a name.
//StreamWriter will make a text file.
outfile = new StreamWriter("OUTPUT.txt");
// construct the two gameboards.
gameBoard = new char[ROW_SIZE, COL_SIZE];
tempBoard = new char[ROW_SIZE, COL_SIZE];
// playing the game consists of
// step 1 - initializing the gameboard to some start pattern
// superimposed over the field
// the initial field will be all DEAD
InitializeBoards();
// superimpose some start patterns over the initial board.
InsertStartPatterns();
}
// main processing loop for the game
// plays the game by setting a number of generations to display
// and then looping for each generation
// each generation
// 1 - displays the results of the current generation
// 2 - processes the next gen to the results board (tempBoard)
// 3 - swaps the 2 boards
//Preconditions: not yet
//Inputs: no args
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
public void PlayGame()
{
// get the number of generations to display from the user
Console.Write("Enter the number of generations: ");
int numberOfGenerations = int.Parse(Console.ReadLine());
for (int generation = 1; generation <= numberOfGenerations; generation++)
{
// 1 - displays the results of the current generation
DisplayBoard(generation);
// 2 - processes the next gen to the results board (tempBoard)
ProcessGameBoard();
// 3 - swaps the 2 boards
char[,] tempLocation = gameBoard;
gameBoard = tempBoard;
tempBoard = tempLocation;
}
//release resource
outfile.Close();
}
//Processes the game board according to
//Conway's Game of Life rules
//Iterate through the current gameboard and
//determine if that cell will live or die (in the next gen)
//store the results back into the results board (tempBoard)
//Preconditions: not yet
//Inputs: no args
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
private void ProcessGameBoard()
{
// 2 - processes the next gen to the results board (tempBoard)
// Count the neighbors for each cell
for (int r = 0; r < ROW_SIZE; r++)
{
for (int c = 0; c < COL_SIZE; c++)
{
// determine if [r,c[ will live or die
//store the results back into the results board (tempBoard)
tempBoard[r, c] = DetermineDeadOrAlive(r,c);
}
}
}
//Determine if a specific cell is dead or alive in the next gen by doing the following
//count the neighbors to get a total
//apply the rules of the game.
//Preconditions: not yet
//Inputs: int row, int column
//Outputs: char DEAD or char ALIVE.
//Postconditions: not yet
//ref: Chuck Costarella
private char DetermineDeadOrAlive(int r, int c)
{
//YOU SPIN ME RIGHT ROUND BABY
//RIGHT ROUND
//LIKE A RECORD BABY RIGHT ROUND ROUND ROUND
//count the neighbors to get a total
int count = CountNeighbors(r, c);
//apply the rules of the game
//Any live cell with fewer than two live neighbours dies, as if by underpopulation.
//Any live cell with two or three live neighbours lives on to the next generation.
//Any live cell with more than three live neighbours dies, as if by overpopulation.
//Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
if (count == 2) return gameBoard[r, c]; //status quo rule
else if (count == 3) return LIVE; //spontaneous birth
else return DEAD; //It's dead, Jim.
}
//Inserts start patterns to both game boards
//Preconditions: not yet
//Inputs: int row, int column
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
private int CountNeighbors(int r, int c)
{
int count = 0;
if(r == 0 && c == 0)
{
//EXCEPTIONAL CASE -- Top Left corner
//if (gameBoard[r - 1, c - 1] == LIVE) count++;
//if (gameBoard[r - 1, c] == LIVE) count++;
//if (gameBoard[r - 1, c + 1] == LIVE) count++;
//if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
//if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if(r==0 && c==COL_SIZE-1)
{
//EXCEPTIONAL CASE -- Top Right corner
//if (gameBoard[r - 1, c - 1] == LIVE) count++;
//if (gameBoard[r - 1, c] == LIVE) count++;
//if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
//if (gameBoard[r, c + 1] == LIVE) count++;
if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
//if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (r==ROW_SIZE-1 && c==0)
{
//EXCEPTIONAL CASE -- Bottom Left corner
//if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
if (gameBoard[r - 1, c + 1] == LIVE) count++;
//if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
//if (gameBoard[r + 1, c - 1] == LIVE) count++;
//if (gameBoard[r + 1, c] == LIVE) count++;
//if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (r==ROW_SIZE-1 && c==COL_SIZE-1)
{
//EXCEPTIONAL CASE -- Bottom Right corner
if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
//if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
//if (gameBoard[r, c + 1] == LIVE) count++;
//if (gameBoard[r + 1, c - 1] == LIVE) count++;
//if (gameBoard[r + 1, c] == LIVE) count++;
//if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (r==0)
{
//EXCEPTIONAL CASE -- Top Edge
//if (gameBoard[r - 1, c - 1] == LIVE) count++;
//if (gameBoard[r - 1, c] == LIVE) count++;
//if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (c==COL_SIZE-1)
{
//EXCEPTIONAL CASE -- Right Edge
if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
//if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
//if (gameBoard[r, c + 1] == LIVE) count++;
if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
//if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (r==ROW_SIZE-1)
{
//EXCEPTIONAL CASE -- Bottom Edge
if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
//if (gameBoard[r + 1, c - 1] == LIVE) count++;
//if (gameBoard[r + 1, c] == LIVE) count++;
//if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else if (c==0)
{
//EXCEPTIONAL CASE -- Left Edge
//if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
if (gameBoard[r - 1, c + 1] == LIVE) count++;
//if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
//if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
else
{
//No edges, no corners.
if (gameBoard[r - 1, c - 1] == LIVE) count++;
if (gameBoard[r - 1, c] == LIVE) count++;
if (gameBoard[r - 1, c + 1] == LIVE) count++;
if (gameBoard[r, c - 1] == LIVE) count++;
if (gameBoard[r, c + 1] == LIVE) count++;
if (gameBoard[r + 1, c - 1] == LIVE) count++;
if (gameBoard[r + 1, c] == LIVE) count++;
if (gameBoard[r + 1, c + 1] == LIVE) count++;
}
return count;
} //end CountNeighbors
//Inserts start patterns to both game boards
//Preconditions: not yet
//Inputs: no args
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
private void InsertStartPatterns()
{
//row, column
InsertStartPattern1(20,25);
}
//Initializes the game boards to the start state of raw storage
//Preconditions: not yet
//Inputs: no args
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
private void InitializeBoards()
{
//iterate through each row
for (int r = 0; r < ROW_SIZE; r++)
{
//iterate through each column in an individual row
for (int c = 0; c < COL_SIZE; c++)
{
//init all cells in boath boards to the init start status - DEAD
gameBoard[r, c] = DEAD;
tempBoard[r, c] = DEAD;
}
}
}
//Initializes the game boards to the start state of raw storage
//Preconditions: not yet
//Inputs: integer number of the current generation
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
public void DisplayBoard(int generation)
{
//Move the cursor to overwrite the old gameboard.
Console.SetCursorPosition(0, Console.WindowTop + 1);
Console.WriteLine($"GENERATION #: {generation}");
outfile.WriteLine($"GENERATION #: {generation}");
//iterate through each row
for (int r = 0; r < ROW_SIZE; r++)
{
//iterate through each column in an individual row
for (int c = 0; c < COL_SIZE; c++)
{
//Write the cell [DEAD OR LIVE] to the console.
Console.Write(gameBoard[r, c]);
outfile.Write(gameBoard[r, c]);
}
//insert CRLF at the end of every row
Console.WriteLine();
outfile.WriteLine();
}
}
//Inserts start patterns to both game boards
//Preconditions: not yet
//Inputs: integer row, integer column
//Outputs: void return
//Postconditions: not yet
//ref: Chuck Costarella
private void InsertStartPattern1(int r, int c)
{
//8 LIVE cells
gameBoard[r, c + 1] = LIVE;
gameBoard[r, c + 2] = LIVE;
gameBoard[r, c + 3] = LIVE;
gameBoard[r, c + 4] = LIVE;
gameBoard[r, c + 5] = LIVE;
gameBoard[r, c + 6] = LIVE;
gameBoard[r, c + 7] = LIVE;
gameBoard[r, c + 8] = LIVE;
//1 DEAD SPACE - c == 9
//5 LIVE cells
gameBoard[r, c + 10] = LIVE;
gameBoard[r, c + 11] = LIVE;
gameBoard[r, c + 12] = LIVE;
gameBoard[r, c + 13] = LIVE;
gameBoard[r, c + 14] = LIVE;
//3 DEAD cells - c == 15,16,17
//3 LIVE cells
gameBoard[r, c + 18] = LIVE;
gameBoard[r, c + 19] = LIVE;
gameBoard[r, c + 20] = LIVE;
//6 DEAD cells - c == 21-26
//7 LIVE cells
gameBoard[r, c + 27] = LIVE;
gameBoard[r, c + 28] = LIVE;
gameBoard[r, c + 29] = LIVE;
gameBoard[r, c + 30] = LIVE;
gameBoard[r, c + 31] = LIVE;
gameBoard[r, c + 32] = LIVE;
gameBoard[r, c + 33] = LIVE;
//1 DEAD cell c==34
//5 LIVE cells
gameBoard[r, c + 35] = LIVE;
gameBoard[r, c + 36] = LIVE;
gameBoard[r, c + 37] = LIVE;
gameBoard[r, c + 38] = LIVE;
gameBoard[r, c + 39] = LIVE;
} //END InsertStartPattern1
} // END class
} // END namespace

29
GLife/Program.cs Normal file
View File

@ -0,0 +1,29 @@
/* Shaun Marquardt
* TINFO 200
* Game of Life simulation
* ****************************************************
* Change History
* Date Developer Description
* 2020-01-16 marqusa File creation and initial implementation -- Charles Costarella
* 2020-01-28 marqusa --Charles Costarella
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GLife
{
class Program
{
static void Main(string[] args)
{
// create a top level object that represents the game
Game game = new Game();
// start the main game simulation
game.PlayGame();
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GLife")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GLife")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("07cd2938-ef48-458a-aad8-8ea66d5724af")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

6
StudentDB/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

57
StudentDB/GradStudent.cs Normal file
View File

@ -0,0 +1,57 @@
/* This is the GradStudent class which inherits from Student class.
* See StuDB for full change history
* It adds tuitionCredit and Faculty Advisor to the student class.
*
* Change History
* Date Developer Description
* 2020-02-13 marqusa In-class work on the program, Chuck Costarella
* through 25
* 2020-02-27 marqusa documentation
*/
namespace StudentDB
{
class GradStudent : Student
{
//Auto-implemented properties of TuitionCredit and FacultyAdvisor
public decimal TuitionCredit { get; set; }
public string FacultyAdvisor { get; set; }
//GradStudent constructor inherits from Student constructor,
//addding the credit and faculty advisor arguments.
public GradStudent(string first, string last, double gpa, string email,
decimal credit, string advisor)
: base(first, last, gpa, email)
{
TuitionCredit = credit;
FacultyAdvisor = advisor;
}
// conversion to a lamda expression - mechanism of functional programming.
// lamda operator is "=>" abd reads "goes to"
// C# calls this an "expression-bodied method"
// This is only used for one-liners or very simple things.
public override string ToString() => base.ToString() + $"Credit: {TuitionCredit:C}\n Fac: {FacultyAdvisor}\n";
//the overriden method in the base class must be marked "virtual"
public override string ToStringForOutputFile()
{
//Prepend the discriminator to the base student information
string str = StuDB.GRADSTUDENT + "\n" + base.ToStringForOutputFile();
// append the "local information"
str += $"{TuitionCredit}\n";
str += $"{FacultyAdvisor}\n";
return str;
}
/* This is the "Standard?" way instead of the lamda way.
* I am just leaving this in here for my reference.
public override string ToString()
{
return base.ToString() + $"Credit: {TuitionCredit:C}\n Fac: {FacultyAdvisor}\n";
}
*/
}
}

42
StudentDB/Program.cs Normal file
View File

@ -0,0 +1,42 @@
/* Shaun Marquardt
* TINFO 200
* L6: OOP
* ****************************************************
* Change History
* Date Developer Description
* 2020-02-11 marqusa File creation and initial implementation, Chuck Costarella
* See StuDB for fuller change history
* 2020-02-29 marqusa Removed TestMain as I have [I]nsert test driver data in the menu.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StudentDB
{
class Program
{
/* This is a program for a student database application.
* This program has the capability to read/write to a plain
* ascii text file to save the data to disk. When the data is read
* it loads each type of student, UNDERGRAD or GRADSTUDENT into a
* new list of students. The program operates on this list until
* the QUIT menu choice is selected. At said time, the program
* will save the current list of students in memory back out to disk.
*/
/* This is the main driver program for the StuDB class.
* Simply instantiates a new StuDB object and calls GoDatabase()
* which presents the main program to the user proper, starting
* with the main menu.
*/
static void Main(string[] args)
{
StuDB app = new StuDB();
app.GoDatabase();
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("StudentDB")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("StudentDB")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("767514ee-9c14-4590-8e4f-be06473a5c03")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

774
StudentDB/StuDB.cs Normal file
View File

@ -0,0 +1,774 @@
/*
* Change History
* Date Developer Description
* 2020-02-11 marqusa File creation and initial implementation.
* -added student class to start with. Add user input and output to files.
* 2020-02-13 marqusa Continue with in-class work on the program, Chuck Costarella
* - Implemented and updated new input functionality.
* 2020-02-18 marqusa Continue with in-class work on the program, Chuck Costarella
* -Made GradStudent and Undergrad classes.
* -Implementing reading and writing of student types
* 2020-02-20 marqusa Continue with in-class work on the program, Chuck Costarella
* -Started coding for find, delete, and modify records
* 2020-02-25 marqusa Continue with in-class work on the program, Chuck Costarella
* -DeleteStudentRecord(), ListAllEmailAddresses()
* 2020-02-26 marqusa Fix the output error when writing to output file in wrong order in undergrad
* 2020-02-27 marqusa clean up adding new student.
* Wrap deletion in a confirmation.
* Move constants to top of StuDB
* Add documentation.
* Add shell to-do for inserting test student data into DB.
* Add GetChoice with a maximum range above 9 as
* GetSelectionFromUser only gets a single key, and does not
* support numbers above 9. Ref: Microsoft
* 2020-02-28 marqusa ModifyStudentRecord.
* 2020-02-29 marqusa Finish completely implementing ModifyStudentRecord/ModifyUnderGrad/ModifyGrad
* Complete all listed TODO items other than adding more rules for email address.
* REFERENCES
* https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/how-to-determine-whether-a-string-represents-a-numeric-value
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace StudentDB
{
internal class StuDB
{
//Constants.
const string STUDENT_DB_DATA_FILE = "STUDENT_DB_DATA_FILE.txt";
public const string UNDERGRAD = "UNDERGRAD";
public const string GRADSTUDENT = "GRADSTUDENT";
// the more or less persistent storage for students during runtime
private List<Student> students = new List<Student>();
/* Main entry point to the StuDB application.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
public void GoDatabase()
{
//read the data in fron the input file
ReadDataFromInputFile();
// setup a loop that will repeatedly prompt the user for an action
//CRUD - Create, Read, Update, Delete
while (true)
{
// display a main menu to the user
DisplayMainMenu();
// CRUD - capture the user selection
ConsoleKeyInfo selection = GetSelectionFromUser();
//Add space after reading the key.
Console.WriteLine();
switch (selection.KeyChar)
{
case 'I':
case 'i':
InsertTestStudentsIntoDB();
break;
case 'L':
case 'l':
ListAllEmailAddresses();
break;
case 'M':
case 'm':
ModifyStudentRecord();
break;
case 'D':
case 'd':
DeleteStudentRecord();
break;
case 'F':
case 'f':
Console.Write("Enter email ID to search for: ");
string email = Console.ReadLine();
Student searchStudent = FindStudentRecord(email);
if (searchStudent != null)
{
Console.WriteLine(searchStudent);
}
else
{
Console.WriteLine($"{email} not currently in the database.");
}
break;
case 'N':
case 'n':
System.Diagnostics.Process.Start("notepad");
break;
case 'A':
case 'a':
AddStudentRecord();
break;
case 'P':
case 'p':
PrintAllRecords();
break;
case 'Q':
case 'q':
case 'X':
case 'x':
ExitTheDatabaseApp();
break;
case 'S':
case 's':
SaveDataToOutputFile();
break;
default:
Console.WriteLine($"... sorry, '{selection.KeyChar}' isn't a valid choice.");
break;
}
}
}
/* List all email addresses currently in the Student list
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void ListAllEmailAddresses()
{
Console.WriteLine("*************************");
for (int i = 0; i < students.Count; i++)
{
Console.WriteLine($"{i + 1}: {students[i].EmailAddress}");
}
Console.WriteLine("END of email list");
}
/* Deletes a student record out of the in-memory student list
* after asking "Are you sure you want to delete?"
* The confirmation takes Y or y for yes, and
* anything else will not delete the student.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void DeleteStudentRecord()
{
//show the user a list of possible deletions in concise format
ListAllEmailAddresses();
Console.Write("Your selection: ");
int recordToDelete = GetChoice(Console.ReadLine(), students.Count);
//adjust the record to delete to correctly index.
//GetChoice returns -1 if choice is not valid, which is checked in the below ifcheck.
recordToDelete -= 1;
//Insert a space to pretty up the formatting.
Console.WriteLine();
// Check to see if recordToDelete is between 0 and <students.Count
if (recordToDelete < 0 || recordToDelete > students.Count - 1)
{
Console.WriteLine("Sorry, you did not make a valid choice.");
return;
}
ConsoleKeyInfo confirmDelete = GetSelectionFromUser($"Are you sure you want to delete {students[recordToDelete].EmailAddress} [y/n]? ");
Console.WriteLine();
switch (confirmDelete.KeyChar)
{
case 'Y':
case 'y':
students.RemoveAt(recordToDelete);
//Say something nice and make the user feel all warm and fuzzy
Console.WriteLine("After delete, now the list is:");
ListAllEmailAddresses();
break;
default:
Console.WriteLine("Record NOT deleted.");
break;
}
}
/* Modify a student record.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*
* NOTE: There is no requirement to be able to modify a student's subtype,
* i.e, an Undergrad need not be editable to become a GradStudent, or vice versa
*/
private void ModifyStudentRecord()
{
ListAllEmailAddresses();
Console.Write("Your selection: ");
int choice = GetChoice(Console.ReadLine(), students.Count);
//Decrement choice to properly index into the student list.
choice -= 1;
//GetChoice returns -1 if choice is not valid.
//So any negative choice "index" is not valid.
if (choice < 0)
{
Console.WriteLine("... sorry, that's an invalid choice.");
return;
}
//The record is found. Show the record to the user.
var studentToModify = students[choice];
//If this is a grad student, cast studentToModify
//into GradStudent type.
if (studentToModify is GradStudent)
studentToModify = (GradStudent)studentToModify;
else
studentToModify = (Undergrad)studentToModify;
//Display a sub-menu for edit
DisplayEditMenu(studentToModify);
// when done editing-
// display new version of record
Console.WriteLine("\nHere is the new record of that student after modification:");
Console.Write(studentToModify);
}
/* Modify student / Edit submenu
* Preconditions: not yet
* Inputs: Student
* Outputs: void return
* Postconditions: not yet
*/
private void DisplayEditMenu(Student studentToModify)
{
//Must be up here to check on While, below.
ConsoleKeyInfo selection;
//Shows the edit menu until the choice is Q.
do
{
Console.WriteLine(@"
********************************
******* Edit Student Menu ******
********************************
");
//Display something to the user indicating what type of student this is.
if (studentToModify is GradStudent)
Console.Write("This is a Grad Student.");
else
Console.Write("This is an Undergrad Student.");
Console.Write(@"
What data for this student would you like to change?
[F]irst name: " + studentToModify.FirstName +
"\n [L]ast name: " + studentToModify.LastName +
"\n [G]PA: " + studentToModify.GradePtAvg +
"\n [E]mail: " + studentToModify.EmailAddress
);
if (studentToModify is GradStudent)
ShowGradStudentEditMenu((GradStudent)studentToModify);
else
ShowUndergradEditMenu((Undergrad)studentToModify);
Console.WriteLine(@" [Q]uit editing this student.");
// capture the user selection
selection = GetSelectionFromUser();
//Add space after reading the key.
Console.WriteLine();
switch (selection.KeyChar)
{
case 'F': //FirstName
case 'f':
Console.Write("Enter new first name: ");
string newFirstName = Console.ReadLine();
studentToModify.FirstName = newFirstName;
break;
case 'L': //LastName
case 'l':
Console.Write("Enter new last name: ");
string newLastName = Console.ReadLine();
studentToModify.LastName = newLastName;
break;
case 'G': //GPA
case 'g':
Console.Write("Enter new GPA between 0 and 4.0 inclusive: ");
double newGPA = double.Parse(Console.ReadLine());
studentToModify.GradePtAvg = newGPA;
break;
case 'E': //Email Address
case 'e':
Console.Write("Enter the new valid email address with @ symbol: ");
string newEmailAddy = Console.ReadLine();
//Check to see if another student has the desired email address.
if (FindStudentRecord(newEmailAddy) == null)
studentToModify.EmailAddress = newEmailAddy;
else
Console.WriteLine("Sorry, another student has that email. Try again.");
break;
//Take care of modifying gradstudents.
case 'T': //Tuition credit
case 't':
if (studentToModify is GradStudent)
ModifyGradStudent((GradStudent)studentToModify, 't');
break;
case 'A': //Faculty [A]dvisor
case 'a':
if (studentToModify is GradStudent)
ModifyGradStudent((GradStudent)studentToModify, 'a');
break;
//Take care of modifying undergrad students.
case 'Y': //YearRank
case 'y':
if (studentToModify is Undergrad)
ModifyUndergrad((Undergrad)studentToModify, 'y');
break;
case 'D': //DegreeMajor
case 'd':
if (studentToModify is Undergrad)
ModifyUndergrad((Undergrad)studentToModify, 'd');
break;
case 'Q': //Done editing student.
case 'q':
break;
default: //Invalid selection
Console.WriteLine("...Sorry, that was an invalid choice.");
break;
} //end switch
} while (selection.KeyChar.ToString().ToUpper() != "Q"); //Check if the user is done editing.
} // end DisplayEditMenu
/* Modify student
* This function is for Grad Students.
* Preconditions: not yet
* Inputs: GradStudent, char choice as 'T' or 'A'
* Outputs: void return
* Postconditions: not yet
*/
private void ModifyGradStudent(GradStudent studentToModify, char choice)
{
switch (choice)
{
case 'T': //Modify the TuitionCredit
case 't':
Console.Write("Enter the amount of the tuition credit without the dollar sign: ");
decimal newCredit = decimal.Parse(Console.ReadLine());
studentToModify.TuitionCredit = newCredit;
break;
case 'A': //Modify the faculty advisor
case 'a':
Console.Write("Enter the name of the faculty advisor: ");
studentToModify.FacultyAdvisor = Console.ReadLine();
break;
default: //We shouldn't get here, but if we do, display an error to the user.
Console.WriteLine("**BUG**: ModifyGradStudent got called with an invalid selection. Please contact developer.");
break;
}
}
/* Modify student
* This function is for Undergrad Students.
* Preconditions: not yet
* Inputs: Undergrad, choice as 'Y' or 'D'
* Outputs: void return
* Postconditions: not yet
*/
private void ModifyUndergrad(Undergrad studentToModify, char choice)
{
switch (choice)
{
//Modify the YearRank of the undergrad student.
case 'Y':
case 'y':
YearRank rank;
Console.Write("Enter the year in school as Freshman, Sophmore, Junior, or Senior: ");
//If it's a valid rank, save to the student.
if (Enum.TryParse(Console.ReadLine(), out rank))
studentToModify.Rank = rank;
else
Console.WriteLine("Sorry, that was invalid year, please try again.");
break;
case 'D':
case 'd':
Console.Write("Enter the student's Degree Major: ");
studentToModify.DegreeMajor = Console.ReadLine();
break;
default: //We shouldn't get here, but if we do, display an error to the user.
Console.WriteLine("**BUG**: ModifyUndergrad got called with an invalid selection. Please contact developer.");
break;
}
}
/* Modify student / Edit submenu
* This function is for Undergrad Students.
* Preconditions: not yet
* Inputs: Undergrad
* Outputs: void return
* Postconditions: not yet
*/
private void ShowUndergradEditMenu(Undergrad studentToModify)
{
Console.WriteLine(@"
[Y]ear Rank: " + studentToModify.Rank +
"\n [D]egree Major: " + studentToModify.DegreeMajor
);
}
/* Modify student / Edit submenu
* This function is for Grad Students.
* Preconditions: not yet
* Inputs: GradStudent
* Outputs: void return
* Postconditions: not yet
*/
private void ShowGradStudentEditMenu(GradStudent studentToModify)
{
Console.WriteLine(@"
[T]uition Credit: " + studentToModify.TuitionCredit +
"\n [A]dvisor (Faculty): " + studentToModify.FacultyAdvisor
);
}
/* Gets user integer choice between 1 and maxChoiceNumber
* Preconditions: not yet
* Inputs: string choice, maxChoiceNumber
* Outputs: integer or -1 if not a valid choice.
* Postconditions: not yet
*/
private int GetChoice(string userChoice, int maxChoiceNumber)
{
int choice;
//Check if choice is an integer (as a string).
//ref: microsoft
if (int.TryParse(userChoice, out choice))
{
//If the choice is not between 0 and range, return -1.
if (choice < 0 || choice > maxChoiceNumber)
return -1;
else
return choice;
}
else //If the choice is not an integer, return -1.
return -1;
}
/* searches the list collection for a student and either returns
* a reference to the found student or null if not found.
* Preconditions: not yet
* Inputs: string email address
* Outputs: Student or null
* Postconditions: not yet
*/
private Student FindStudentRecord(string email)
{
//Iterate through each student type in the student list.
foreach (var student in students)
{
//If the currently focused student's email address
//is equal to the passed in email argument,
//return the student.
if (student.EmailAddress == email)
{
return student;
}
}
//Student not found, return null.
return null;
}
/* Add a student record.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void AddStudentRecord()
{
//First prompt for the email address as that is the key
//discriminator between students in the database --
//no two students may have the same email address.
Console.Write("Desired email address: ");
string email = Console.ReadLine();
Student studentToAdd = FindStudentRecord(email);
// if the key (email address) does not already exist - add the student
if (studentToAdd == null)
{
Console.Write("First Name:");
string first = Console.ReadLine();
Console.Write("Last Name: ");
string last = Console.ReadLine();
Console.Write("GPA: ");
double gpa = double.Parse(Console.ReadLine());
//Prompt user for graduate student or not
//to add the correct type of student to the list.
switch (GetSelectionFromUser("Graduate student[y/n]? ").KeyChar)
{
case 'Y':
case 'y':
//Grad student
Console.Write("\nTotal amount of tuition credit: ");
decimal credit = decimal.Parse(Console.ReadLine());
Console.Write("Name of faculty advisor: ");
string advisor = Console.ReadLine();
//now make a GradStudent and add to the list
students.Add(new GradStudent(first, last, gpa, email, credit, advisor));
break;
default:
//undergrad student
//Tell the user how to enter the year as it is an enum.
Console.Write("\nEnter the year in school as Freshman, Sophmore, Junior, or Senior: ");
YearRank rank;
Enum.TryParse<YearRank>(Console.ReadLine(), out rank);
Console.Write("What is the student's major: ");
string degree = Console.ReadLine();
// make a new undergrad stu with the gathered info and insert in the list
students.Add(new Undergrad(first, last, gpa, email, rank, degree));
break;
}
}
else //A student with that email address was found
{
//Another student with that email address was found.
Console.WriteLine("Sorry, another student with that email address is already in the database.");
}
}
/* Prints all the student records in the list.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void PrintAllRecords()
{
//For each type of student in the list,
foreach (var student in students)
{
//call the type of student object's ToString() overridden method.
Console.WriteLine(student);
}
}
/* Save data to the output file.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void SaveDataToOutputFile()
{
// create a file object to attach to the actual file on disk
StreamWriter outfile = new StreamWriter(STUDENT_DB_DATA_FILE);
//Debugging
//StreamWriter outfile = new StreamWriter("OUTPUT.txt");
// use it - write the contents of the students collection to the file
for (int i = 0; i < students.Count; i++)
{
//There is no CRLF at the end of a student from this code
outfile.Write(students[i].ToStringForOutputFile());
}
//release the resource
outfile.Close();
}
/* Exits the application.
* this method also saves all the current changes that have been made to the list.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void ExitTheDatabaseApp()
{
//salutation
Console.WriteLine("Thank you for using the Student Database Application.\n" +
"Your work has been saved. Good bye!");
//save the data.
SaveDataToOutputFile();
// zero typically means no errors- normal exit
Environment.Exit(0);
}
/* Get the user selected operation character
* Preconditions: not yet
* Inputs: string prompt (default "User Selection: ")
* Outputs: ConsoleKeyInfo (single key)
* Postconditions: not yet
*/
private ConsoleKeyInfo GetSelectionFromUser(string prompt = "User selection: ")
{
Console.Write(prompt);
return Console.ReadKey();
}
/* Display the main menu of the application.
* This is the main user interface of the program.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void DisplayMainMenu()
{
Console.WriteLine(@"
********************************
***** Student Database App *****
********************************
[P]rint all records
[F]ind a student record
[L]ist all email addresses
[A]dd a new student record
[D]elete a student record
[M]odify a student record
[N]otes utility
[I]nsert test driver student data into DB
[S]ave the records and continue
[Q]uit database app (includes save)
");
}
/* Read in the input file data.
* make student objects from the read in data
* and store them in a semi-persistent data structure.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void ReadDataFromInputFile()
{
StreamReader infile = null;
//The student database file exists, read it.
if (File.Exists(STUDENT_DB_DATA_FILE))
{
infile = new StreamReader(STUDENT_DB_DATA_FILE);
}
else //The file does not yet exist, do not load data.
{
return;
}
string studentType = string.Empty;
//Boilerplate code to read for a file.
//Read the file line by line, until the end of the file.
//Once infile.readline() reaches EOF, str becomes NULL.
while ((studentType = infile.ReadLine()) != null)
{
string firstName = infile.ReadLine();
string lastName = infile.ReadLine();
double grades = double.Parse(infile.ReadLine());
string email = infile.ReadLine();
if (studentType == UNDERGRAD)
{
//reading into an enum type.
//chapter 7, book
YearRank rank;
Enum.TryParse<YearRank>(infile.ReadLine(), out rank);
string degree = infile.ReadLine();
students.Add(new Undergrad(firstName, lastName, grades,
email, rank, degree));
}
else if (studentType == GRADSTUDENT)
{
decimal credit = decimal.Parse(infile.ReadLine());
string advisor = infile.ReadLine();
//The reason we can put a grad student in a list of students
//is because a GradStudent IS A KIND OF student.
students.Add(new GradStudent(firstName, lastName, grades,
email, credit, advisor));
}
else
{
Console.WriteLine($"ERROR: Unsupported student type: {studentType}");
}
//Now that we have variables for a student,
//Create a student object and add it to our list.
//new Student is an anonymous object - it doesn't have a name.
//now that all data for an obj has been read in - make the object and insert in the list
//No longer need this code because of the above switch statement.
//students.Add(new Student(firstName, lastName, grades, email));
}
//Release the resource.
infile.Close();
}
/* Inserts test students into the student list
* if those test students are not already present.
* Preconditions: not yet
* Inputs: no args
* Outputs: void return
* Postconditions: not yet
*/
private void InsertTestStudentsIntoDB()
{
List<Student> testStudents = new List<Student>();
//The test driver inserts a list of 8 students
//into the Student list, if they are not already present.
//First setup the Grad Students -- Pro Wrestlers.
GradStudent gs1 = new GradStudent("Hulk", "Hogan", 4.0, "hhogan@uw.edu", (decimal)45000.99, "Dr. Hulkamaiac");
testStudents.Add(gs1);
GradStudent gs2 = new GradStudent("Randy", "Savage", 2.8, "rsavage@uw.edu", (decimal)42350.99, "Dr. Hurtzalot");
testStudents.Add(gs2);
GradStudent gs3 = new GradStudent("Rick", "Flair", 1.2, "rflair@uw.edu", (decimal)23000.99, "Dr. Dirtyplayer");
testStudents.Add(gs3);
GradStudent gs4 = new GradStudent("Bret", "Hart", 1.2, "bhart@uw.edu", (decimal)32975.98, "Dr. Hart");
testStudents.Add(gs4);
//Now setup the Undergrad Students -- Football players with hilarious degrees.
Undergrad ug1 = new Undergrad("Tom", "Brady", 3.4, "tbrady@uw.edu", YearRank.Freshman, "BS-Deflategate");
testStudents.Add(ug1);
Undergrad ug2 = new Undergrad("Michael", "Vick", 2.5, "mvick@uw.edu", YearRank.Sophmore, "BS-Dogfighting");
testStudents.Add(ug2);
Undergrad ug3 = new Undergrad("Russel", "Wilson", 1.2, "rwilson@uw.edu", YearRank.Junior, "BS-PaidTooMuch");
testStudents.Add(ug3);
Undergrad ug4 = new Undergrad("Joe", "Montana", 3.9, "jmontana@uw.edu", YearRank.Senior, "BS-BeingTheMan");
testStudents.Add(ug4);
//Now for each of our test students in the list,
//If the test student is NOT already in the database, add them.
foreach (var student in testStudents)
{
if (FindStudentRecord(student.EmailAddress) == null)
students.Add(student);
}
Console.WriteLine("Test student data has been added if it was not present.");
return;
}
}
}

109
StudentDB/Student.cs Normal file
View File

@ -0,0 +1,109 @@
/* This is the Student class. Undergrad and GradStudent "is a type of" student.
* See StuDB for full change history.
*
* Change History
* Date Developer Description
* 2020-02-13 marqusa In-class work on the program, Chuck Costarella
* through 25
*/
namespace StudentDB
{
internal class Student
{
// auto implemented props
public string FirstName { get; set; }
public string LastName { get; set; }
// instance variable
private double gradePtAvg;
private string emailAddress;
// 1 - allocate storage for the object
// 2 - init all vars to reasonable defaults
//If first is not called with a variable, it has a default.
//default values have to be piled up on the right side of the constructor
public Student(string first,
string last = "Last name",
double grades = 0.7,
string email = "newstudent@uw.edu")
{
FirstName = first;
LastName = last;
GradePtAvg = grades;
EmailAddress = email;
}
//Public variable to set the private emailAddress instance variable.
public string EmailAddress
{
get
{
return emailAddress;
}
set
{
// TODO: Add more "rules" to what exactly an email can be.
// -- ABANDONED --
if(value.Contains("@"))
{
emailAddress = value;
}
}
}
//Public variable to set the private gradePtAvg instance variable.
public double GradePtAvg
{
get
{
return gradePtAvg;
}
set
{
// check if GPA is in valid range
if (0.0 <= value && value <= 4.0)
{
gradePtAvg = value;
}
}
}
// specifically formatted for the output/input file
// no labels on any of the data
// The virtual keyword allows for the method to be overriden.
public virtual string ToStringForOutputFile()
{
// mkae an empty string
string str = string.Empty;
// build up the string with data we want to print
// note this finishes a student output with a CRLF
str += $"{FirstName}\n";
str += $"{LastName}\n";
str += $"{GradePtAvg}\n";
str += $"{EmailAddress}\n";
// return the string
return str;
}
//Data to go to the user
//Overrides the ToString method found in "Object".
public override string ToString()
{
// mkae an empty string
string str = string.Empty;
// build up the string with data that you want to print from the object
str += "***************************\n";
str += $"First: {FirstName}\n";
str += $" Last: {LastName}\n";
str += $" GPA: {GradePtAvg:0.0}\n";
str += $"Email: {EmailAddress}\n";
// return the string
return str;
}
}
}

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{767514EE-9C14-4590-8E4F-BE06473A5C03}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>StudentDB</RootNamespace>
<AssemblyName>StudentDB</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="GradStudent.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StuDB.cs" />
<Compile Include="Student.cs" />
<Compile Include="Undergrad.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

25
StudentDB/StudentDB.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StudentDB", "StudentDB.csproj", "{767514EE-9C14-4590-8E4F-BE06473A5C03}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{767514EE-9C14-4590-8E4F-BE06473A5C03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{767514EE-9C14-4590-8E4F-BE06473A5C03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{767514EE-9C14-4590-8E4F-BE06473A5C03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{767514EE-9C14-4590-8E4F-BE06473A5C03}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D8208617-6FE0-4787-A651-E0832AA80E29}
EndGlobalSection
EndGlobal

1064
StudentDB/Testing Run.txt Normal file

File diff suppressed because it is too large Load Diff

62
StudentDB/Undergrad.cs Normal file
View File

@ -0,0 +1,62 @@
/* This is the Undergrad class which inherits from Student class.
* See StuDB for full change history.
* It adds YearRank enum type and MajorDegree data to a student.
*
* Change History
* Date Developer Description
* 2020-02-13 marqusa In-class work on the program, Chuck Costarella
* through 25
* 2020-02-26 marqusa Fix the output error when writing to output file in wrong order in undergrad
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StudentDB
{
public enum YearRank
{
Freshman = 1,
Sophmore = 2,
Junior = 3,
Senior = 4
}
// The way we indicate inheritance is using a colon, then indicate the base class.
class Undergrad : Student
{
public YearRank Rank { get; set; }
public string DegreeMajor { get; set; }
//Must have at least the same constructor as the parent.
//use :base() to call the parent constructor and supply the arguments
//that the parent class needs.
public Undergrad(string first, string last, double gpa, string email, YearRank rank, string degree)
: base(first, last, gpa, email)
{
Rank = rank;
DegreeMajor = degree;
}
// conversion to a lamda expression - mechanism of functional programming.
// lamda operator is "=>" and reads "goes to"
// C# calls this an "expression-bodied method"
// This is only used for one-liners or very simple things.
public override string ToString() => base.ToString() + $"Year: {Rank}\nDegree: {DegreeMajor}\n";
public override string ToStringForOutputFile()
{
string str = StuDB.UNDERGRAD + "\n" + base.ToStringForOutputFile();
// append the "local information"
str += $"{Rank}\n";
str += $"{DegreeMajor}\n";
return str;
}
}
}