I'm making a game that involves with the players choice of gender and want to reflect the dialogue of the player's choice with the correct pronouns. I was thinking of using boolean but was advice not to as it seems kind of bad making one of the genders to be true and the other to be false. So trying to use enums on this but my only problem is how to implement it correctly and have it working. Haven't really used enums that much before to be use for strings.
This is what I have so far:
public class UITextBoxScript : MonoBehaviour
{
public Text mytext;
enum Gender
{
None, Male, Female
}
enum States
{
Instructions, Warning, YourGender, Test
}
Gender playerGender = Gender.None;
Gender playersGender = Gender.Male;
Gender playGender = Gender.Female;
int gender = 0; // using 0 or 1 (or 0, 1, 2.. if you might ever have 'unset')
string[] heshe = { "he", "she" };
string[] hisher = { "his", "her" };
string[] himher = { "him", "her" };
Then this is the target area of where it should hit and affect the user's choice:
void state_YourGender()
{
mytext.text = "Okay!" +
"\n" +
"\n" +
"What is your love interest gender?" +
"\n" +
"\n" +
"\n" +
"\n" +
"A) Male" +
"\n" +
"\n" +
"S) Female";
timer -= Time.deltaTime;
if (Input.GetKeyDown(KeyCode.A))
{
myState = States.Test;
gender = 0;
Gender playersGender = Gender.Male;
}
else if (Input.GetKeyDown(KeyCode.S))
{
myState = States.Test;
}
}
void state_Test()
{
string phrase=" _heshe_was really happy";
string newPhrase = phrase.Replace("_HESHE_", heshe[gender]);
timer -= Time.deltaTime;
if (timer <= 0 && Input.GetKeyDown(KeyCode.Space))
{
timer = timerVal;
myState = States.YourGender;
}
}
I have been trying to experiment and find a way to call out the string to return to me but the string itself is not returning at all. I'm also using mytextbox and the area of a small box for the dialogue to show up and it has been working fine; no issues there. Any advice or tips?
Using enums to store exclusive values like gender is a good idea, but there are a few design decisions in your code that are not good ideas. First, you already have four global variables just to store one player's gender roles. That's already too many, and will get worse with every player or NPC you add. Instead, create a class for storing people:
public class Person
{
public string Name { get; private set; }
public Gender Gender { get; private set; }
public Gender LoveInterestGender { get; private set; }
public Person(string name, Gender gender, Gender loveInterestGender)
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name));
Name = name;
Gender = gender;
LoveInterestGender = loveInterestGender;
}
}
Beginners are strangely reluctant to create new classes. Don't be; that is the main way you will simplify your code. Now you can create your player through code or a UI:
var player = new Person(name: "Hiro Protagonist", gender: Gender.Male, loveInterestGender: Gender.Female);
It's also a bad idea to try to customize dialog using string replacement; often you want to change the actual dialog, not just replace every “he” with “she” or such. You need to specify rules for dialogs to follow. For example, we could specify a different rule for each dialog depending on the gender of the speaker and listener. How do you do that? With another class, of course. Though, for reasons I won't go into, in this particular case a readonly struct would be better:
public struct DialogSpecifier : IEquatable<DialogSpecifier>
{
public readonly Gender SpeakerGender;
public readonly Gender ListenerGender;
public DialogSpecifier(Gender speakerGender, Gender listenerGender)
{
SpeakerGender = speakerGender;
ListenerGender = listenerGender;
}
public bool Equals(DialogSpecifier other)
{
return SpeakerGender==other.SpeakerGender
&& ListenerGender==other.ListenerGender;
}
}
Okay, so now we have people, and rules for dialogs. How do we make people speak to each other using these rules? We could write a bunch of code for each person for each rule for each gender. Wow, that's a lot of code! How do we simplify code again? Oh yeah, create a class:
public class Dialogue
{
Dictionary<DialogSpecifier, string> specifiedDialog = new Dictionary<DialogSpecifier, string>();
public Dialogue(string noneToNone)
{
specifiedDialog.Add(new DialogSpecifier(Gender.None, Gender.None), noneToNone);
}
public Dialogue Add(DialogSpecifier specifier, string dialogue)
{
specifiedDialog.Add(specifier, dialogue);
return this;
}
public string OpeningGambit(Person speaker, Person listener)
{
string gambit;
if (specifiedDialog.TryGetValue(new DialogSpecifier(speakerGender: speaker.Gender, listenerGender: listener.Gender),
out gambit))
return gambit;
return specifiedDialog[new DialogSpecifier(Gender.None, Gender.None)];
}
}
Okay, so now let's create some people and dialogues:
var introduction = new Dialogue("Hello")
.Add(new DialogSpecifier(Gender.Male, Gender.Male), "Wassup?");
var npc = new Person(name: "Juanita Marquez", gender: Gender.Female, loveInterestGender: Gender.Male);
var gambit = introduction.OpeningGambit(player, npc);
Simple, right? That's because we created classes and didn't try to write code for every possible permutation. This is easily extensible, too; we can Add gambits for different situations, or change specifiedDialog to a Dictionary<DialogSpecifier, List<string>> so we can have a list of gambits instead of a single one for each specifier. We could add more rules to DialogSpecifier, for example to behave differently if the listener is the speaker's LoveInterestGender. Doing that only requires changing one class; you don't have to rewrite all your code every time you add something.
Related
Step 1: I have created a C# application called : Student details
Step 2: Added four TextBoxes and named them as :
Image below to refer:
Studentname.Text
StudentSurname.Text
StudentCity.Text
StudentState.Text
DATA INSIDE CSV FILE
vikas,gadhi,mumbai,maharashtra
prem,yogi,kolkata,maha
roja,goal,orissa,oya
ram,kala,goa,barka
Issue is How do I fetch all the data(surname,city,state) of user prem into above textboxes studentsurname,studentcity,studentstate from csv file when I search the name in textbox 1 => studentname.Text as prem
Below is the Code where I am stuck at return null and code inside Load_Script_Click
void Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
}
}
return;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Connection_fetch_details cd = Connection_fetch_details(con_env);
textusername.Text = cd.username;
}
==============================================================
Class file name : Address.class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DDL_SCRIPT_GENERATOR
{
public class Connection_fetch_details
{
public string username { get; set; }
}
}
The main problem is that your method is void, which means it doesn't return any value. So even though you may be finding a match, and creating a Connection_fetch_details object, you aren't returning that result back to the calling method.
This will fix that problem:
Connection_fetch_details Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
return cd; //return the object containing the matched username
}
}
return null;
}
Now it will return a Connection_fetch_details object if there is a match, or null if there is no match.
Next, you asked about returning all the fields, not just one. For that you would need to
a) add more properties to your object
b) add more code to populate those properties from the CSV
c) add code to populate the textboxes with the results from the object.
I'm also going to rename "username" to something more relevant, since none of the field names you described in the question match that. I'm also going to rename your class to "Student", and rename your search method, for the same reason.
Here's an example:
Student searchStudent(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var split = line.Split(',');
if (split[0].Equals(searchName))
{
Student s = new Student()
{
firstname = searchName,
surname = split[1],
city = split[2],
state = split[3]
};
return s; //return the object containing the matched name
}
}
return null;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Student st = searchStudent(con_env);
textsurname.Text = st.surname;
txtcity.Text = st.city;
txtstate.Text = st.state;
}
namespace DDL_SCRIPT_GENERATOR
{
public class Student
{
public string firstname { get; set; }
public string surname { get; set; }
public string city { get; set; }
public string state { get; set; }
}
}
To accomplish your goal you have to further separate your problem in more granular steps and also distinguish between what you show in your UI and what informations you hold in the background in which format.
Create a class with the desired properties
public class Student { public string Name { get; set; } ... }
Learn how to read a csv file into such an object by using an existing library like CsvHelper or CsvReader.
When you have something like List<Student> from this part. Learn how you can visualize such a thing by using some Binding (also depends on the visualization you use Winforms, WPF, etc.).
Depending on the visualization component it already supports filtering or you need to filter by yourself by using e.g. LINQ to get the matching elements students.Where(student => student.Name.StartsWith(search)).
So far a lot of smaller problems which is simply to much to answer in a single one. Please try to break down your problems into smaller ones and search for their solutions. If you get stuck, ask a new question. That's all I can do for you now.
I'm trying to create a quest system. I have QuestCreator, Quest and multiple objective classes that inherits an interface(TalkObjective, LocationObjective etc.)
In Quest class' constructor, I have created a list like List<IObjective>.
It didn't work.
Then I created a class to hold all different types of lists. But I lost the ability of ordering my objectives.
My question is; Is there a better way/design to do that?
[Edit]
I'm sorry that I didn't detailed it enough. Since I changed my code, I can't post it here. I tried to create the same code but this time the code is not giving me error. So I solve the problem on my own.
I was using a tutorial that wasn't completed/abandoned.
Here is the link to github
I built my Item/Inventory system with abstract classes and it was the first thing that came to my mind. But my intention was to create this quest system the way creator of the tutorial designed, so that I can learn his way.
I wanted to put objects of different Objective Classes in a list with the interface that they using in common way.
public class QuestCreator : MonoBehaviour {
#region fields
private List<IQuestObjective> objectives;
private GameObject itemManager;
private ItemDatabase itemdb;
private Location location;
private Quest quest;
//For Saving Quest
private Quest_data quests;
#endregion
void Update()
{
//Just for the test purpose
if (Input.GetKeyDown (KeyCode.E))
{
itemManager = GameObject.Find ("GameManager");
itemdb = itemManager.GetComponent<ItemDatabase>();
Item item = new Item ();
Item item2 = new Item ();
item = itemdb.weapon_database[0];
item2 = itemdb.weapon_database [1];
CollectionObjective collectionObjective = new CollectionObjective ("Find", 3, item, "Find this precious item");
CollectionObjective collectionObjective2 = new CollectionObjective ("Find", 1, item2, "Find Sword of Warrior from Dark Passage");
LocationObjective locationObjective = new LocationObjective ("Go to Green Valley", "Go to " + location, location, false);
objectives = new List<IQuestObjective> ();
objectives.Add(collectionObjective);
objectives.Add (collectionObjective2);
objectives.Add (locationObjective);
QuestText questText = new QuestText ();
QuestIdentifier questIdentifier = new QuestIdentifier();
questText.Title = "Finding Sword of Warrior";
questText.DescriptionSummary = "Summary...";
questText.Hint = "Hint...";
questIdentifier.QuestID = 1;
questIdentifier.SourceID = 1;
quest = new Quest (questIdentifier, questText, objectives);
Debug.Log (quest.Objectives[1].Description);
Debug.Log (quest.Objectives.Count);
}
}
You need to look into inheritance and polymorphism.
In your case you'd have a IObjective class that contains all the common logic:
public abstract IObjective : MonoBehaviour
{
public abstract void CommonMethod();
public virtual void OverrideIfNeeded(){}
public void UseAsIs(){}
}
CommonMethod has to be overrriden by subclass. OverrideIfNeeded may be overriden or used as it is. UseAsIs cannot be overriden (it can be hidden though).
Then you have a collection:
IEnumerable<IObjective> collection;
it contains all kind of different objects that are all IObjective and you can iterate and call all methods from the IObjective:
foreach(IObjective obj in collection)
{
obj.CommonMethod();
obj.UseAsIs();
...
}
Here is an example of the code you may have for your problem.
public class Program
{
public struct Location
{
// Assumes 2D game location
public int X;
public int Y;
}
public struct Character
{
public int GameCharId;
}
public class BaseObjective
{
public string Title;
public string Description;
}
public class TalkObjective : BaseObjective
{
public Character TargetCharacter;
}
public class LocationObjective : BaseObjective
{
public Location TargetLocation;
}
public static void Main(string[] args)
{
List<BaseObjective> currentObjectives = new List<BaseObjective>();
TalkObjective obj1 = new TalkObjective(){ Title = "Talk to Bob", Description = "Bob has some useful information for you", TargetCharacter = new Character(){GameCharId = 87}};
LocationObjective obj2 = new LocationObjective(){ Title = "Find the thing", Description = "Bob informed you of a thing, go and find it", TargetLocation = new Location(){ X = 33, Y=172}};
currentObjectives.Add(obj1);
currentObjectives.Add(obj2);
}
}
At first to all game programming, I'm highly suggesting going through this web book - http://gameprogrammingpatterns.com/contents.html (it also offers PDF/book variant for some money). It helps You with some game-pattern examples and You will get an idea how games are made.
Your question is kind of broad and related to each person opinion, which should not be listed as a Q on SO, however:
Logically to me it is like: There is 1 Quest (created by factory QuestCreator), which contains List<Objectives>.
Objective should be an abstract class, containing some variables and methods (Is objective done? - other things that all Objectives have in common).
After that You should inherit smaller objective (like TalkObjective, ItemObjective) and override inner implementation of the methods -> IsObjectiveDone.
On
To be honest, in game-programming, developers are stepping away to avoid inheritance as much as possible. It is too hard to create inheritance tree and then go through the code. Instead they are trying to rely on pattern like Component (same source as above).
Adding some example:
public abstract class Objective
{
public bool IsObjectiveDone { get; private set; }
public virtual void CheckIfDone();
}
public class ObjectiveGroup
{
public bool AllObjectivesDone => SubObjectives.All(a => a.IsObjectiveDone);
public Objective[] SubObjectives { get; private set; }
public static ObjectiveGroup Create(TypeOfQuest aType, Requirements[] aReq)
{ /* factory implementation */ }
}
Once You have the example above, You can define each type of "special" objective:
public class ItemObjective : Objective
{
public Item RequiredItem { get; private set; }
override public void CheckIfDone()
{
this.IsObjectiveDone = Player.GetInstance().Inventory.Contains(RequiredItem);
}
}
Once You will want to start new Quest, You will call the factory, which will create the Quest, containing group of objectives. On each objective You will CheckIfDone everytime user do some action/get new item or so.
public class Quest
{
public ObjectiveGroup { get; private set; }
public Quest(TypeOfQuest aType, Requirements[] aReq)
{
this.ObjectiveGroup = ObjectiveGroup.Create(aType, aReq);
}
}
public class Player
{
public List<Quest> Quests = new List<Quest>();
public List<Item> Inventory = new List<Item>();
}
public void Main(/* ... */)
{
Player player = new Player();
player.Quests.Add(new Quest(TypeOfQuest.ItemObtain, new Requirements[] { Item["Sword of Conan"] });
while(true)
{
player.Quests.ObjectiveGroup.ForEach(a => a.SubObjectives.ForEach(b => b.CheckIfDone()));
foreach(var objGrp in player.Quests.ObjectiveGroup)
if(objGrp.IsObjectiveDone) Console.WriteLine("Quest completed");
}
}
The better design, will be using Finite Automaton for this task, not some sort of list of objective.
So, your quest will be described with graph of predicates (conditions where to move to state or not, event listeners if you want) and states (accompishments in quest). For example, let's imagine hero entered some tavern, then he also enters some different quest lines. One of them describes town robber quest:
[Start] -(talked with barmen about robber)-> [Kill robber]
[Start] -(talked with robber wife) -> [Ask robber to return items]
//this is made for karma decision between two quest lines, so you are free to chose what to do with poor robber, take robber money or gain karma in town.
[Ask robber to return items] -(talked with barmen about robber)-> [Kill robber]
[Kill robber] -(talked with robber wife) -> [Ask robber to return items]
//barmen quest line
[Kill robber] -(robber killed)-> [Success quest (you can take money as reward)]
[Kill robber] -(robber spared)-> [Fail quest]
//wife quest line
[Ask robber to return items] -(robber convinced)-> [Success quest (you can now sleep with his wife for free)]
[Ask robber to return items] -(robber not convinced)-> [Ask robber to return items]
[Ask robber to return items] -(robber got bored of your questions)-> [Fail quest]
As you see this is all described with simple automaton rules and you can make pretty complex quests without much effort. In case of your list of objective you can't possibly branch your quest into different states, so only possible way to complete your quest is to meet ALL actions described one by one, even if it has two possible and successful outcomes.
Predicates in this example can be described as events, and states - as simple numbers or strings.
This is just very slow example of how I see it:
public class QAutomaton
{
private readonly Dictionary<string, Dictionary<string, string>> _graph = new Dictionary<string, Dictionary<string, string>>();
public void AddState(string state)
{
_graph.Add(state, new Dictionary<string, string>());
}
public void AddCondition(string from, string condition, string to)
{
_graph[from].Add(condition, to);
}
public string GetNext(string from, string condition)
{
var conds = _graph[from];
string nextState;
conds.TryGetValue(condition, out nextState);
return nextState;
}
}
public class Quest
{
public string CurrentState = "Start";
private readonly QAutomaton _automaton;
public Quest(QAutomaton automaton)
{
_automaton = automaton;
}
public void FeedEvent(string condition)
{
var nextState = _automaton.GetNext(CurrentState, condition);
if (nextState != null)
{
CurrentState = nextState;
}
}
}
public static void Main()
{
var fa = new QAutomaton();
fa.AddState("Start");
fa.AddState("Kill robber");
fa.AddState("Ask robber to return items");
fa.AddCondition("Start", "talked with barmen about robber", "Kill robber");
fa.AddCondition("Start", "talked with robber wife", "Ask robber to return items");
//describe rest here...
_quest = new Quest(fa);
}
public static void OnTalkedWithBarmenAboutRobberEventHandler()
{
_quest.FeedEvent("talked with barmen about robber");
var state = _quest.CurrentState;
if (state == "Kill robber")
{
//locate him on global map or something
}
}
I wish to create an online quiz that can ask any question from thousands of programmed questions. Each question is created via a function that is given an array of int whose values determine the exact question displayed. I have each question as a class:
public class AddingTwoDigitNumbers : IQuestion
{
public string QName() { return "Adding Two-Digit Numbers" };
public int[] QParams() { return int[]() {Random(10, 99), Random(10, 99) };
public void Question(int[] values) {
Console.WriteLine(string.Format("What is {1} + {2}?", values[0], values[1]);
}
public void Answer(int[] values) {
Console.WriteLine(values[0] + values[1]).ToString());
}
}
QParams creates the array of int (to determine exactly the question created), that is given to both Question and Answer to create the question and answer.
I want a List of questions searchable by QName but would rather not have to create (and name) thousands of classes all implementing IQuestion.
So here is my second solution:
public class Question
{
public string QName { get; set; }
public Func<int[]> QParams { get; set; }
public Action<int[]> Question { get; set; }
public Action<int[]> Answer { get; set; }
}
public class QuestionRepository
{
public static Dictionary<string, Question> Questions = new Dictionary<string, Question>();
public static void AddQuestions(Question[] qs) {
foreach (Question q in qs) Questions.Add(q.QName, q);
}
}
public class FirstSetOfQuestions
{
static void AddQuestions()
{
QuestionRepository.AddQuestions(new Question[]
{
new Question()
{
QName = "Adding Two-Digit Numbers",
QParams = () => int[]() {Random(10, 99), Random(10, 99) },
Question = (v) => {Console.WriteLine(string.Format("What is {1} + {2}?", v[0], v[1]);},
Answer = (v) => {Console.WriteLine(values[0] + values[1]).ToString());}
},
new Question()
{
QName = "Subtracting Three-Digit Numbers",
QParams = () => int[]() {Random(100, 999), Random(100, 999) },
Question = (v) => {Console.WriteLine(string.Format("What is {1} - {2}?", v[0], v[1]);},
Answer = (v) => {Console.WriteLine(values[0] - values[1]).ToString());}
}
}
}
}
So my question is which is better? Do I create thousands of classes, having to provide a name for each one, or do I create thousands of anonymous functions and a class that stores these using (I assume) delegates? Is there a problem with the second solution if I have thousands of questions, or even a better way to do this?
(Obviously the questions I wish to create are much more complicated than shown here, and involve fractions, algebra etc.)
Just to get you started with fluent syntax, throwing in some stubs and ideas in there as well.
class Question
{
public string Name { get; set; }
public string QuestionFormat { get; set; }
public List<Range> Args { get; set; }
public Expression<Func<int[], int>> ValExp { get; set; }
public Question(string name, string questionFormat)
{
this.Name = name;
this.QuestionFormat = questionFormat;
this.Args = new List<Range>();
}
public Question Rand(int min, int max)
{
this.Args.Add(new Range(min, max));
return this;
}
public void Val(Expression<Func<int[], int>> exp)
{
this.ValExp = exp;
}
public CompiledQuestion Compile()
{
// Generate args in the appropriate ranges
// Evaluate the result with the ValExp
// Return a new CompiledQuestion with the information -
// basically just replacing Args, ValExp with RealArgs, Val
}
public ICoolDataObject Save()
{
}
public static Question Load(ICoolDataObject hmm)
{
}
}
class Range
{
public int Min { get; set; }
public int Max { get; set; }
public Range(int min, int max)
{
this.Min = min;
this.Max = max;
}
}
It's almost fun, creating questions now:
new Question("simple addition",
"whats {0} + {1}?")
.Rand(10, 99)
.Rand(10, 99)
.Val(v => v[0] + v[1]);
You can obviously add some validation checks to avoid bad number of arguments due to late hours of work, and use double or decimal instead of int wherever.
Both approaches are wrong. I presume you are not going to have thousands of different types of calculations. You are only going to have a dozen or a few dozen different types of calculations, operating on a huge variety of data.
So, you need to normalize your data so as to end up with about a dozen or a few dozen different well defined calculations on a database of well defined data, end then write about a dozen or a few dozen classes, one for each kind of calculation, only.
You might think that this is too complicated, and you might think that writing thousands of classes (or delegates, it does not really matter) might be a lot of work but each piece is small and easy, but trust me, you will bitterly regret doing it this way as soon as something needs to change on the interface or the implementation of all of these classes, and most chances are that something will need to change at some point in time.
I am trying to add 300 Challenges into my program, but only display them if the CompletionValue.IsChecked = false;
If you were creating this program. How would you store the Challenges?
I am using a switch but having 300 cases is overkill, is there a better way?
Any recommendation on to improve the code is well appreciated.
I am somewhat new to this.
Random rand = new Random();
// Constructor
public MainPage()
{
InitializeComponent();
AnswerValue.Visibility = Visibility.Collapsed;
Load();
}
private void Load()
{
int random = rand.Next(1, 4);
switch (random)
{
case 1:
Challenge1();
break;
case 2:
Challenge2();
break;
case 3:
Challenge3();
break;
}
}
private void Challenge1()
{
DifficultyValue.Text = "20%";
CompletionValue.IsChecked = false;
TitleValue.Text = "Chicken or Egg?";
QuestionValue.Text = "Can you answer the ancient question: Which came first the chicken of the egg?";
bmp.UriSource = new Uri("Images/Challenge1.png", UriKind.Relative);
ImageValue.Source = bmp;
ImageValue.Visibility = Visibility.Visible;
ResourceValue.Text = "Resource: Brain Games";
AnswerValue.Text = "The Egg. According to paleontologists, reptiles and dinosaurs existed long before birds and chickens. Fossilized eggs dating back on hundred millions years have been uncovered. Thus it can be said that eggs came before chickens.";
}
private void Challenge2()
{
DifficultyValue.Text = "25%";
CompletionValue.IsChecked = false;
TitleValue.Text = "Halving Seven";
QuestionValue.Text = "Can you prove that seven is half of twelve?";
bmp.UriSource = new Uri("Images/Challenge2.png", UriKind.Relative);
ImageValue.Source = bmp;
ImageValue.Visibility = Visibility.Visible;
ResourceValue.Text = "Resource: Yahoo Questions";
AnswerValue.Text = "Roman numeral for 12 - XII \n Cut the roman numeral in half. you will get VII, which is 7.";
}
private void Challenge3()
{
DifficultyValue.Text = "25%";
CompletionValue.IsChecked = false;
TitleValue.Text = "Three-coin flip";
QuestionValue.Text = "You ask a friend about probability, and he tells you the following: The odds of three tossed coins turning up all heads or all tails is one in two, that is, fifty-fifty. That’s because anytime you toss three coins, at least two must match, either two heads or two tails. So that means the third coin—which is equally likely to be heads or tails—determines the odds.” Is your friend right? If not, what are the odds of three tossed coins turning up all heads or all tails?";
bmp.UriSource = new Uri("Images/Challenge3.png", UriKind.Relative);
ImageValue.Source = bmp;
ImageValue.Visibility = Visibility.Visible;
ResourceValue.Text = "Resource: Brain Games";
AnswerValue.Text = "Answer will be available soon";
}
Your challenges look awfully similar to each other, right? This is a case where you want to extract out a common data structure, and have each challenge represented as a piece of data.
With a uniform representation for your challenges, you set up the UI based on the challenge data for a particular challenge ID.
It is always possible to move your data into XML files, JSON files, or a database, but first see if the simple C# solution works for you:
// Note: This example is simplified for readability
// Here is the common data structure that can represent all challenges
private class Challenge
{
public string Title { get; set; }
public string Question { get; set; }
public string ImagePath { get; set; }
}
// All of the challenges are defined right here, as simple data
private Challenge[] _allChallenges = new Challenge[]
{
new Challenge
{
Title = "Chicken or Egg?",
Question = "Can you answer the ancient question: Which came first the chicken of the egg?",
ImagePath = "Images/Challenge1.png",
},
new Challenge
{
Title = "Halving Seven?",
Question = "Can you prove that seven is half of twelve?",
ImagePath = "Images/Challenge1.png",
},
}
// Choosing challenges is as simple as indexing into the array
private void Load()
{
int random = rand.Next(1, 4);
Challenge chosenChallenge = _allChallenges[random];
LoadChallenge(chosenChallenge);
}
// Setting up the UI for a challenge means extracting information from the data structure
private void LoadChallenge(Challenge chosenChallenge)
{
TitleValue.Text = chosenChallenge.Title;
QuestionValue.Text = chosenChallenge.Text;
bmp.UriSource = new Uri(chosenChallenge.ImagePath, UriKind.Relative);
ImageValue.Source = bmp;
ImageValue.Visibility = Visibility.Visible;
}
You can consider this as a form of declarative programming. An important part of your program, the challenges themselves, have been converted from imperative statements (setting UI properties) into very simple data declarations.
By making this conversion, you can even check each challenge to make sure that all of the parts are filled out. Then you'll be sure that the title, question, resource, answer, etc. is set for each of your 300 challenges.
You can save the challenges in a database or a file. I do see you are using a random number and display only 1 challenge. The DB can be something like
ChallengeId, DifficultyValue, TitleValue ...
The ChallengeId will be the questionId number. So depending on the random number generated you can choose the particular ChallengeId and the relevant data.
What you should really look into is encapsulation and polymorphic code. By encapsulating your like properties into a single class, you have a better way of representing the "Challenge" as a whole, and being able to reuse the parts that you have to type over and over again (.Text = "...") will make your future coding life infinitely better. Granted, even coding the list of Challenge entities, as I have below, would be not fun, you have to enter that data somewhere sometime. We're just going to consider this a coding exercise, you could easily adapt the code below to populate _challenges from a database or serialized file.
public class Challenge
{
public int Id {get;set;}
public int Difficulty {get;set;}
public bool IsCompleted {get;set;}
public string Title {get;set;}
public string Question {get;set;}
public string Answer {get;set;}
}
public class MainPage
{
private List<Challenge> _challenges;
private Random rand = new Random();
public MainPage()
{
_challenges = new List<Challenge> {
new Challenge {
Id = 1,
Difficulty = 20,
Title = "What came first?",
Question = "The chicken or the egg?",
Answer = "The egg." },
new Challenge {
Id = 2,
Difficulty = 30,
Title = "Make 7 from 12?",
Question = "Can you prove 7 is half of 12?",
Answer = "VII" }};
}
public void LoadChallenge(Challenge challenge)
{
Difficulty.Test = String.Format("%{0}", callenge.Difficulty);
Completeted.Value = challenge.IsCompleted;
Title.Test = challenge.Title;
// etc
}
public void StartNewChallenge()
{
Challenge nextChallenge = null;
while(nextChallenge == null)
{
var nextId = rand.Next(1,2);
nextChallenge = _challenges
.Where(x => x.Id == nextId && !x.IsCompleted)
.SingleOrDefault(); // default to null if completed == true
}
LoadChallenge(nextChallenge);
}
}
Yet another alternative might be some kind of factory method:
MyForm.cs
public class MyForm
{
Random rand = new Random();
// Constructor
public MainPage()
{
InitializeComponent();
AnswerValue.Visibility = Visibility.Collapsed;
Load();
}
private void Load()
{
int random = rand.Next(1, 4);
DisplayChallenge(ChallengeFactory.GetChallenge(random));
}
private void DisplayChallenge(ChallengeFactory.Challenge challengeToDisplay)
{
DifficultyValue.Text = String.Format("{0}%", challengeToDisplay.Difficulty);
CompletionValue.IsChecked = challengeToDisplay.IsChecked;
TitleValue.Text = challengeToDisplay.Title;
QuestionValue.Text = challengeToDisplay.Question;
ImageValue.Source = challengeToDisplay.ImageSource;
ImageValue.Visibility = challengeToDisplay.Visible;
ResourceValue.Text = challengeToDisplay.ResourceValue;
AnswerValue.Text = challengeToDisplay.Answer;
}
}
ChallengeFactory.cs
public static class ChallengeFactory
{
public class Challenge
{
public int Difficulty { get; set; }
public bool IsChecked { get; set; }
public string Title { get; set; }
public string Question { get; set; }
public Uri ImageSource { get; set; }
public bool Visible { get; set; }
public string ResourceValue { get; set; }
public string Answer { get; set; }
private Challenge(int difficulty, bool isChecked, string title, string question, Uri imageSource, bool visible, string resourceValue, string answer)
{
// assign each of the arguments to the instance properties
}
}
public static Challenge GetChallenge(int challengeNumber)
{
switch(challengeNumber)
{
case 1:
return new Challenge(20, false, "Chicken or Egg?", "Can you answer the ancient question: Which came first the chicken of the egg?", new Uri("Images/Challenge1.png", UriKind.Relative), true, "Resource: Brain Games", "The Egg...");
break;
case 2:
// new challenge for challenge #2
break;
case 3:
// new challenge for challenge #3
break;
}
}
}
Note that I have made the Challenge class a nested class inside of the Factory class. The good thing about doing this is that you can make the constructor of the challenge private (meaning that you cannot create "invalid" types of challenges through anything but the factory method. The bad thing about doing this is that you have to further qualify the Challenge class by prefixing it with it's containing class, that is, ChallengeFactory. I think it's worth the extra qualifier in this case.
Ultimately I think you are stuck having to create a switch SOMEWHERE if you plan on defining all of your challenges in code. As others have said, you can significantly reduce the amount of code you need to write (and thus, the switch) by defining your challenges in an external data source (such as a database) and having a single method to read, parse, and create a Challenge instance.
i am trying to create a football simulation program. i have a main class named "team" and 4 derived classes named "goalKeeper", "defender", "forward" and "midfielder".
i am creating players according to their position.
ex:
team fb = new team("fb");
forward alex = new forward(fb.tName, "alex", 73, 77, 77, 69, 70);
my team class:
public class team
{
public string tName;
public team(string tName)
{
this.tName = tName;
}
public string teamInfo()
{
return tName;
}
}
forward class:
class forward:team
{
//özellikler
public string pName;
public string pPosName;
public int finishing;
public int longShots;
public int composure;
public int offTheBall;
public int firstTouch;
public forward(string tName, string pName, int finishing, int longShots, int composure, int offTheBall, int firstTouch)
: base(tName)
{
this.pName = pName;
this.pPosName = "Forward";
this.finishing = finishing;
this.longShots = longShots;
this.composure = composure;
this.offTheBall = offTheBall;
this.firstTouch = firstTouch;
}
//etkiyi hesapla
public double influence
{
get
{
//calculations
return processed;
}
}
//futbolcunun genel bilgileri
public void playerInfo()
{
Console.WriteLine( "\n##############################\n" + pName + "-" + tName + "-" + pPosName + "\n" + "Finishing= " + finishing + "\n" + "Long Shots= " + longShots + "\n" + "Composure= " + composure + "\n" + "Off the ball= " + offTheBall + "\n" + "Frist Touch= " + firstTouch + "\n##############################\n");
}
}
as you can see i am calculating influence of each player according to their technical attributes.
what i want is automating the process. for example i've created a team.. added players, and i want all player's influence to be called via team name. i am going to give team name and position name and it is gonna give me average influence of players in that team's chosen position.
how can i do this?
thanks in advance...
note: my code might look stupid. i am a newbie :)
A forward IS A team?
Not at all... A team HAS A forward...
Dont use inheritance... use composition instead.
A player is not a team, this would give you an idea
public class Team
{
private IList<Player> _players
...
}
public class Player
{
public string Name {get;set;}
public abstract Influence { get; }
}
public class Forward : Player
{
public override Influence
{
get { return //calculation }
}
}
I would suggest rethinking your inheritence strategy.
When a class inherits another this implies that the child class 'is a' base class. Applying this to your model implies that a forward 'is a' team which doesn't make much sense. In reality a team 'has a' forward(s).
A more accurate model for what you are trying to achieve is to have a player class as your base class that your foward class, defender class etc inherits from. Your team class can then contains a collection of player classes.