In the following code, I'm trying to learn how to get objects to interact with each other, because I feel that's a bit more important than what I have done now which is simply collect a bunch of variables assign to each object.
For fun, what I want these different objects to do is to kill each other. The person named Jack can kill. The other two can not. What I want Jack to do is strike the other two, making them lose 1, 5 or 10 HitPoints multiple times until they are dead, and then set their Alive to false.
I don't know how to even start this, but I think it would be a very fun and interesting exercise.
The most important thing about doing this is learning how one object can directly change something about a different object, just because it can, and that the objects it has then changed, will then suffer a consequence from this action.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OOP_Learning
{
class Program
{
static void Main(string[] args)
{
Person p1;
p1 = new Person("Jack", 27, true, true, 10);
Person p2;
p2 = new Person("Vincent", 63, true, false, 10);
Person p3;
p3 = new Person("Tim", 13, true, false, 10);
Console.ReadLine();
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool Alive { get; set; }
public bool AbilityToKill { get; set; }
public int HitPoints { get; set; }
public Person(string name, int age, bool alive, bool abilityToKill, int hitPoints)
{
HitPoints = hitPoints;
AbilityToKill = abilityToKill;
Alive = alive;
Name = name;
Age = age;
}
}
}
You need 2 methods in the Person class.
Hit -> This method reduce the HitPoints on self object with each hit. When the HitPoints become Zero, status Alive is set to false.
Kill -> This will take person as a parameter and call Hit method on that person till that person is Alive.
Add following methods to Person class:
public void Hit()
{
if(Alive)
{
if(HitPoints > 0)
{
HitPoints -= 1;
}
else
{
Alive = false;
}
}
}
public bool Kill(Person person)
{
if(!AbilityToKill)
{
Console.WriteLine("You don't have ability to kill! You cannont kill {0}.", person.Name);
return false;
}
while(person.Alive)
{
person.Hit();
}
Console.WriteLine("{0} is dead.", person.Name);
return true;
}
Call Kill method in Main method.
p2.Kill(p3);
p1.Kill(p2);
p1.Kill(p3);
Hope this helps!
Is this the kind of thing you mean?
public class Person
{
public string Name { get; private set; }
public int Age { get; private set; }
public bool Alive { get; private set; }
public bool AbilityToKill { get; private set; }
public int HitPoints { get; private set; }
public void Hit(int points)
{
this.HitPoints -= points;
if (this.HitPoints <= 0)
{
this.HitPoints = 0;
this.Alive = false;
}
}
public Person(string name, int age, bool alive, bool abilityToKill, int hitPoints)
{
this.HitPoints = hitPoints;
this.AbilityToKill = abilityToKill;
this.Alive = alive;
this.Name = name;
this.Age = age;
}
}
Now with the check for AbilityToKill:
public class Person
{
public string Name { get; private set; }
public int Age { get; private set; }
public bool Alive { get; private set; }
public bool AbilityToKill { get; private set; }
public int HitPoints { get; private set; }
public int Attack(Person victim, int points)
{
var hp = victim.HitPoints;
if (this.AbilityToKill)
{
victim.HitPoints -= points;
if (victim.HitPoints <= 0)
{
victim.HitPoints = 0;
victim.Alive = false;
}
}
hp -= victim.HitPoints;
return hp;
}
public Person(string name, int age, bool alive, bool abilityToKill, int hitPoints)
{
this.HitPoints = hitPoints;
this.AbilityToKill = abilityToKill;
this.Alive = alive;
this.Name = name;
this.Age = age;
}
}
This can be used like this:
var jack = new Person("Jack", 27, true, true, 10);
var vincent = new Person("Vincent", 63, true, false, 10);
var tim = new Person("Tim", 13, true, false, 10);
var damage_done = jack.Attack(vincent, 20);
Console.WriteLine(damage_done);
The Attack method returns the actual number of hits points reduced by the attack - the damage dealt.
And here's a more strongly-typed version. Using bool for properties isn't always the clearest way to code. Through in some enums and it's clearer.
public class Person
{
public string Name { get; private set; }
public int Age { get; private set; }
public Alive Alive { get; private set; }
public AbilityToKill AbilityToKill { get; private set; }
public int HitPoints { get; private set; }
public int Attack(Person victim, int points)
{
var hp = victim.HitPoints;
if (this.AbilityToKill == AbilityToKill.Yes)
{
victim.HitPoints -= points;
if (victim.HitPoints <= 0)
{
victim.HitPoints = 0;
victim.Alive = Alive.No;
}
}
hp -= victim.HitPoints;
return hp;
}
public Person(string name, int age, Alive alive, AbilityToKill abilityToKill, int hitPoints)
{
this.HitPoints = hitPoints;
this.AbilityToKill = abilityToKill;
this.Alive = alive;
this.Name = name;
this.Age = age;
}
}
public enum Alive { Yes, No }
public enum AbilityToKill { Yes, No }
It's used like this:
var jack = new Person("Jack", 27, Alive.Yes, AbilityToKill.Yes, 10);
var vincent = new Person("Vincent", 63, Alive.Yes, AbilityToKill.No, 10);
var tim = new Person("Tim", 13, Alive.Yes, AbilityToKill.No, 10);
var damage_done = jack.Attack(vincent, 20);
Console.WriteLine(damage_done);
Related
My "Hero" created character class has this code:
public virtual User User { get; set; }
public override List<Weapon> WeaponSack { get; set; } = new() { Weapon.ElectricityWand, Weapon.ElementalStaff };
Whenever I log back into a character, these items overwrite the weapons added through gameplay.
My looting class has this code which is supposed to add and save looted weapons to the character. The weapons are added successfully and I can use them until I log out and they get overwritten.
I am able to modify player attributes like health and experience and save those by logging out and in, but I cannot see why the weapons won't stick:
{
var CurrentCharacter = SelectCharacter.CurrentHero;
//Damage player for a percentage of their health
var damage = CurrentCharacter.Health - (CurrentCharacter.Health * 0.70);
context.User.Update(user);
CurrentCharacter.LoseHealth(CurrentCharacter, CurrentCharacter.Health, (int)damage);
context.SaveChanges();
Console.WriteLine($"You have lost {damage} health.");
Console.WriteLine($"You have {CurrentCharacter.Health} health left.");
Console.WriteLine("Press any key to collect your loot!");
Console.ReadKey();
//Generate a random weapon
Random random = new Random();
var weapon = new Weapon();
var weaponName = new List<string> { "Sword", "Axe", "Mace", "Dagger", "Bow", "Staff", "Spear", "Wand", "Hammer", "Sickle" };
var weaponType = new List<string> { "Heavy", "Defensive", "Offensive", "Light", "Damaged", "Reinforced", "Magic", "Wooden", "Metallic", "Colorful" };
var weaponLevel = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var weaponDamage = new List<int> { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 };
var weaponRarity = new List<string> { "Common", "Uncommon", "Rare", "Epic", "Legendary" };
var weaponRarityChance = new List<int> { 70, 15, 10, 4, 1 };
var weaponRarityChanceTotal = weaponRarityChance.Sum();
var weaponRarityChanceRandom = random.Next(1, weaponRarityChanceTotal + 1);
var weaponRarityChanceIndex = 0;
for (var i = 0; i < weaponRarityChance.Count; i++)
{
weaponRarityChanceIndex += weaponRarityChance[i];
if (weaponRarityChanceRandom <= weaponRarityChanceIndex)
{
weapon.Rarity = weaponRarity[i];
break;
}
}
weapon.Name = weaponName[random.Next(0, weaponName.Count)];
weapon.Degradation = random.Next(1, 15);
weapon.Type = weaponType[random.Next(0, weaponType.Count)];
weapon.Damage = weaponDamage[random.Next(0, weaponDamage.Count)];
weapon.Level = weaponLevel[random.Next(0, weaponLevel.Count)];
context.Hero.Update(CurrentCharacter);
CurrentCharacter.WeaponSack.Add(weapon);
context.SaveChanges();
Console.WriteLine($"You have found a [level {weapon.Level}] [{weapon.Rarity}] ({weapon.Type} {weapon.Name})! It has {weapon.Degradation} uses left.");
Console.WriteLine("Press any key to continue your adventure!");
Console.ReadKey();
Adventure.AdventureStart(user, hero);
break;
}
When weapons are looted, they are tied to the UserId in the database, but they won't stay in the Hero's weapon list. So I have a whole table of weapons tied to Id's that are inaccessible.
Is the public override of list in the Hero class my problem? I tried to find a way to retrieve the weapons that are tied to the userId and populate that in but I could not figure it out.
Classes as requested:
namespace HeroModels
{
public class Weapon
{
public int Id { get; set; }
public string Name { get; set; }
public int Damage { get; set; }
public int Level { get; set; }
public string Rarity { get; set; }
public string Type { get; set; }
public int Degradation { get; set; }
public Weapon(string name, int damage, int level, string rarity, string type, int degradation)
{
Name = name;
Damage = damage;
Level = level;
Rarity = rarity;
Type = type;
Degradation = 10;
}
public Weapon()
{
}
/*Magic weapons*/
public static Weapon ElectricityWand =
new(name: "Electricity Wand", damage: 5, level: 1, rarity: "Common", type: "Magic", degradation: 10);
public static Weapon ElementalStaff =
new(name: "Elemental Staff", damage: 30, level: 5, rarity: "Common", type: "Magic", degradation: 10);
public int CalculateDamage(Weapon weapon)
{
Random random = new();
var damage = random.Next(weapon.Damage);
return damage;
}
}
}
Hero class :
using HeroModels;
using SolutionItems;
using System.ComponentModel.DataAnnotations;
namespace UserRegistration
{
public class Hero : IHero
{
public Hero()
{
}
[Key]
public new int Id { get; set; }
public override string? Name { get; set; } = "Harry Potter";
public override string Class { get; set; } = "Mage";
public override int Health { get; set; } = 100;
public override int Damage { get; set; } = 10;
public override int Armor
{ get; set; } = 5;
public override int Level
{ get; set; } = 1;
public override int Experience
{ get; set; } = 0;
public override int Gold
{ get; set; } = 0;
public override int Strength
{ get; set; } = 10;
public virtual User User { get; set; }
public virtual List<Weapon> WeaponSack { get; set; } = new() { Weapon.ElectricityWand, Weapon.ElementalStaff };
public override List<Food> FoodSack { get; set; } = new() { Food.trout, Food.salmon };
public override string Attack(IHero hero)
{
return "";
}
public override int GainExperience(IHero hero, int experience)
{
return hero.Experience += experience;
}
public override int GainGold(IHero hero, int gold)
{
return hero.Gold += gold;
}
public override string GainHealth(IHero hero, int health)
{
hero.Health += health;
if (hero.Health >= 100)
{
hero.Health = 100;
}
return $"Your health is now at {hero.Health}!";
}
public override string LoseHealth(IHero hero, int health, int damage)
{
hero.Health -= damage;
if (hero.Health <= 0)
{
Environment.Exit(1);
return "You have died.";
}
return $"You have taken {damage} damage. Your health is now at {hero.Health}!";
}
public override string LevelUp(IHero hero)
{
hero.Level += 1;
var level = hero.Level;
return $"Congratulations! You are now level {Level}";
}
}
}
How I load
private DbContext LogIn()
{
Console.WriteLine("Please enter your username");
string username = Console.ReadLine();
Console.WriteLine("Please enter your password");
string password = Console.ReadLine();
using var context = new HeroesDBContext(_optionsBuilder.Options);
var usercompare = new HeroesDBContext().User.Where(u => u.Username == username && u.Password == password);
if (!usercompare.Any())
{
Console.WriteLine("User not found");
WelcomeScreen();
}
CurrentHero = context.Hero.FirstOrDefault(h => h.User.Username == username);
CurrentUser = context.User.Where(u => u.Username == username && u.Password == password).FirstOrDefault();
context.SaveChanges();
Adventure.AdventureStart(CurrentUser, CurrentHero);
return context;
}
in the LogIn method you can load your weapon by eager Loading as following
CurrentHero = context.Hero.Include(h=>h.WeaponSack).FirstOrDefault(h => h.User.Username == username);
I am looking for information about that in the internet but with no success. The goal is to realize a sort of dataset of 10 subject (sub_1, sub_2... sub_10), each of them has done 3 kind of activities (walk, run, jump) for three time each (trial_1... trial_3) with relative scores. I would like to access these information like:
variable = dataset.sub_1.jump.trial_2.score;
or, at least:
variable = dataset.sub[0].task[2].trial[1].score;
So, the structure would be a tree structure. Until now I only realized a structure with "parallel fields":
struct dataset
{
public string[] sub; // 1 to 10 subjects
public string[] task; // 1 to 3 tasks
public string[] trial; // 1 to 3 trials
public int score; // the score of the above combination
}
Any idea?
This problem can be solved in many ways.
My solution has one drawback, there is no check if user exceeded Score arrays capacity.
I guess database tag has nothing to do with this question
using System;
using System.Linq;
namespace ConsoleApp
{
public abstract class Task
{
public string Name { get; set; }
public int TotalScore { get { return Score.Sum(); } }
public int[] Score { get; set; } = new int[3];
}
public class Walk : Task { }
public class Run : Task { }
public class Jump : Task { }
public class Subject
{
public Walk Walk { get; set; } = new();
public Run Run { get; set; } = new();
public Jump Jump { get; set; } = new();
public int TotalScore { get { return Walk.TotalScore + Run.TotalScore + Jump.TotalScore; }}
}
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
// Adding score to specific trials
subject.Run.Score[0] = 50;
subject.Run.Score[1] = 40;
subject.Run.Score[2] = 60;
subject.Jump.Score[0] = 40;
subject.Jump.Score[1] = 80;
subject.Jump.Score[2] = 100;
// Output score of 1. trial for Walk task
Console.WriteLine(subject.Walk.Score[0]);
// Output total score as a sum of all trials for Jump task
Console.WriteLine(subject.Jump.TotalScore);
// Output total score as a sum of all trials in all tasks
Console.WriteLine(subject.TotalScore);
// ERROR CASE: this will be exception
subject.Jump.Score[3] = 100;
}
}
}
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
public class Trial
{
public Trial(int score)
{
Score = score;
}
public int Score { get; set; }
}
public class Task
{
public List<Trial> Trials { get; } = new List<Trial>();
}
public class Subject
{
public Dictionary<string, Task> Tasks { get; } = new Dictionary<string, Task>();
public Subject()
{
Tasks.Add("walk", new Task());
Tasks.Add("run", new Task());
Tasks.Add("jump", new Task());
}
}
class Program
{
static void Main(string[] args)
{
Subject player1 = new Subject();
player1.Tasks["run"].Trials.Add(new Trial(score: 3));
Console.WriteLine(player1.Tasks["run"].Trials[0].Score);
}
}
}
Maybe a class for everything is too much, but maybe you want to add a description property for tasks one day or a timestamp for the trial. Then it's ok.
public class Subject
{
private Dictionary<string,Activity> _activities { get; }= new Dictionary<string, Activity>();
public Activity this[string activity]
{
get
{
if (!_activities.Keys.Contains(activity))
_activities[activity] = new Activity();
return _activities[activity];
}
set
{
_activities[activity] = value;
}
}
public int Score => _activities.Values.Sum(x => x.Score);
}
public class Activity
{
private Dictionary<int, Trial> _trials { get; } = new Dictionary<int, Trial>();
public Trial this[int trial]
{
get
{
if (!_trials.Keys.Contains(trial))
_trials[trial] = new Trial();
return _trials[trial];
}
set
{
_trials[trial] = value;
}
}
public int Score => _trials.Values.Sum(x => x.Score);
}
public class Trial
{
public int Score { get; set; }
}
public class Answer
{
public void DoSomething()
{
Subject Mindy = new Subject();
Mindy["curling"][1].Score = 5;
Mindy["bowling"][1].Score = 290;
Console.WriteLine(Mindy.Score);
}
}
This is what I would guess you think you need... but from your question I think you're still new to C# and might want to rethink your concept. It looks like a very database-oriented way of looking at the problem, so maybe you might want to take a look at dapper to more closely match your database.
Also, avoid using the classname Task, this can imo only cause confusion if you ever start using multithreading (System.Threading.Task is a .NET framework component)
I'm making an attempt at looping through Course objects and displaying them to the console. For some reason however my solution doesn't seem to work, can anyone detect any obvious issues that I might be the cause for this? thanks :)
class Course
{
private int v1;
private string v2;
private string v3;
private int v4;
public Course(int v1, string v2, string v3, int v4)
{
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
public int courseCode { get; set; }
public string courseName { get; set; }
public string professor { get; set; }
public int capacity { get; set; }
}
class Computation
{
public static List<Course> courses = new List<Course>();
public static void addCourse(Course c)
{
courses.Add(c);
}
public static void viewCourses()
{
foreach(var c in courses)
{
Console.WriteLine(c.courseName);
}
}
}
Main
static void Main(string[] args)
{
Course computerScience = new Course(1, "Computer Science", "Dr Shkhla", 200);
Course mathematics = new Course(2, "Mathematics", "Dr Shkhla", 200);
Course physics = new Course(3, "Physics", "Dr Shkhla", 200);
addCourse(computerScience);
addCourse(mathematics);
addCourse(physics);
viewCourses();
}
The problem is that you are never assigning anything to those properties. Also, it is a very good time to learn standard naming conventions:
public class Course
{
public Course(int code, string name, string professor, int capacity)
{
Code = code;
Name = name;
Professor = professor;
Capacity = capacity;
}
// properties should be in PascalCase
// and should not have their entity's name as prefix
public int Code { get; set; }
public string Name { get; set; }
public string Professor { get; set; }
public int Capacity { get; set; }
}
Names that are sequences (v1, v2, etc in your code) should be avoided most of the times.
Also, notice that I deleted the unused properties from the class.
Change your constructor to:
public Course(int courseCode, string courseName, string professor, int capacity)
{
this.courseCode = courseCode;
this.courseName = courseName;
this.professor = professor;
this.capacity = capacity;
}
You need to update your constructor:
public Course(int v1, string v2, string v3, int v4)
{
courseCode = v1;
courseName = v2;
professor = v3;
capacity = v4;
}
or set your properties directly:
Course computerScience = new Course
{
courseCode = 1,
courseName = "Computer Science",
professor = "Dr Shkhla",
capacity = 200
};
If you like to have an nicer console output, override your toString() function of the Course model.
public override string ToString()
{
return $"Course {courseCode}: {courseName} by {professor}. Capacity: {capacity}";
}
I'm currently trying to make a form that sends 2 class, then receives the data, uses them but want to shoot them back to the original form. Any idea on how I could?
This is when i call my second form:
var tmp = new Pjeu(P1,P2);
tmp.Show();
P are Players. Here's the class:
//---
public class Player
{
public string Name;
public int pts1;
public int pts2;
public int num;
};
And I receive the data like this:
label3.Text = P1.Name;
label5.Text=P2.Name;
I want to use P1.pts or shoot back a number to it. Is it possible the way I do?
You can use multi way:
public class Player
{
public void Pa(string p1,string p2)
{
p1 = Name;
p2 = Name;
}
public string pass1(int ps1)
{
return ps1.ToString();
}
public string pass2(int ps2)
{
return ps2.ToString();
}
public string Name { get; set; }
public int pts1 { get; set; }
public int pts2 { get; set; }
public int num { get; set; }
}
and call:
Player p = new Player();
p.Pa(Label1.Text, Label2.Text);
Label1.Text = p.pts1.ToString();
Label2.Text = p.pts2.ToString();
I want to know if there is any way to do a mathematical addition between methods? The code is as below.
From Main: (I need to the calculation but I can not do calculation between methods)
Ball.setPositionY = Ball.setPositionY + Ball.setSpeedY;
From a Class:
public class Ball
{
public int speedX { get; set; }
public int speedY { get; set; }
public int positionX { get; set; }
public int positionY { get; set; }
public Ball(int speedX, int speedY, int positionX, int positionY)
{
this.speedX = speedX;
this.speedY = speedY;
this.positionX = positionX;
this.positionY = positionY;
}
public void setSpeedX(int newSpeedX)
{
speedX = newSpeedX;
}
public void setSpeedY(int newSpeedY)
{
speedY = newSpeedY;
}
public void setPositionX(int newPositionX)
{
positionX = newPositionX;
}
public void setPositionY(int newPositionY)
{
positionY = newPositionY;
}
}
This is how you should do it:
public class Ball
{
public int SpeedX { get; set; }
public int SpeedY { get; set; }
public int PositionX { get; set; }
public int PositionY { get; set; }
public Ball(int speedX, int speedY, int positionX, int positionY)
{
this.SpeedX = speedX;
this.SpeedY = speedY;
this.PositionX = positionX;
this.PositionY = positionY;
}
}
public class Program
{
public static void Main(string[] args)
{
Ball ball1 = new Ball(1,1,1,1);
Ball ball2 = new Ball(2,2,2,2);
Ball ball3 = new Ball(3,3,3,3);
ball3.SpeedX = ball1.SpeedX + ball2.SpeedX;
}
}
How about letting the set method also return the value that was set or add a get method that gives you that same value. But...since you want that, why don't you just use the public properties on the object?
So, your method(s) can look like
public int setPositionX(int newPositionX)
{
positionX = newPositionX;
return newPositionX;
}
But, since you are creating your own getters and setters now and you already have them. Use the public properties and all should be fine.
After assigning the value, you just return the value. It will solve your problem. If you want to use methods.
For eg.
public int setSpeedX(int newSpeedX)
{
speedX = newSpeedX;
return speedX;
}
That's what properties are for; you should use the properties for that.
If you mean an addition in the functional programming sense, I can make no sense of your example.
Your methods must return value in order to add them,but public properties do what you want.
Ball.positionY =Ball.positionY + Ball.SpeedY;
Since all your methods have void return type there's no way to "add" them.
If you want to do that, change return type of your methods to int.
Edit
You can "add" methods that have int return type, but the result can't be a method.
Sample:
public int setPositionY(int newPositionY)
{
positionY = newPositionY;
return positionY;
}
public int setSpeedY(int newSpeedY)
{
speedY = newSpeedY;
return speedY;
}
positionY = setPositionY(/*new position*/) + setSpeedY(/*new speed*/);
try the below code...
namespace Foo
{
class Program
{
static void Main(string[] args)
{
Ball b = new Ball(1,2,3,4);
//b.setPositionY() = b.setSpeedY() + b.setSpeedY();
b.setPositionY(b.setSpeedX() + b.setSpeedY());
}
}
public class Ball
{
public int speedX { get; set; }
public int speedY { get; set; }
public int positionX { get; set; }
public int positionY { get; set; }
public Ball(int speedX, int speedY, int positionX, int positionY)
{
this.speedX = speedX;
this.speedY = speedY;
this.positionX = positionX;
this.positionY = positionY;
}
public int setSpeedX()
{
//speedX = newSpeedX;
return 10;
}
public int setSpeedY()
{
//speedY = newSpeedY;
return 20;
}
public int setPositionX()
{
//positionX = newPositionX;
return 1;
}
public void setPositionY(int newPositionY)
{
positionY = newPositionY;
}
}