using HSchool.Ai; using HSchool.Ai.Tests; using HSchool.Content; using HSchool.People; namespace HSchool.Ai.Tests; public class TalkCirclesTests { [Fact] public void BoundToLesson_BlocksChatLeisure() { var (catalog, map, walks) = World(); var corridor = map.Rooms.First(room => room.Def == "Corridor").Id; var decision = DecisionPlanner.Decide( catalog, map, walks, new ActorState( corridor, corridor, false, false, true, false, false, true, corridor, Needs(), Intent.None, Talk: new TalkPlannerContext("p1", new Dictionary(), new Dictionary(), null, false, true, catalog.BehaviorRules)), (_, _) => 0); Assert.NotEqual(TalkActions.Chat, decision.StartAction); Assert.NotEqual(TalkActions.StaffChat, decision.StartAction); } [Fact] public void Student_DoesNotPickStaffChat() { var (catalog, map, walks) = World(); var teachersRoom = map.Rooms.First(room => room.Def == "TeachersRoom").Id; var decision = DecisionPlanner.Decide( catalog, map, walks, new ActorState( teachersRoom, teachersRoom, false, false, true, false, false, false, teachersRoom, Needs(social: 0.2f), Intent.None, Talk: new TalkPlannerContext("p1", new Dictionary(), new Dictionary(), null, false, true, catalog.BehaviorRules)), (_, _) => 0); Assert.NotEqual(TalkActions.StaffChat, decision.StartAction); } [Fact] public void PhoneChat_NotOfferedWithoutPhone() { var (catalog, map, walks) = World(); var corridor = map.Rooms.First(room => room.Def == "Corridor").Id; var decision = DecisionPlanner.Decide( catalog, map, walks, Actor(corridor, hasPhone: false), (_, _) => 0); Assert.NotEqual(TalkActions.PhoneChat, decision.StartAction); } [Fact] public void HasPhone_DetectsBagPhone() { Assert.False(TalkCircles.HasPhone([])); Assert.True(TalkCircles.HasPhone([new InventoryItem("Phone", "Black", 1f, ItemLocations.Bag)])); } [Fact] public void NoSharedLanguage_WeakensOpinionShift() { var (catalog, _, _) = World(); var rules = catalog.BehaviorRules!; var topic = catalog.Topics["TopicStudy"]; var from = Person("a", ["RussianLanguage"]); var to = Person("b", ["English"]); var withLanguage = TalkCircles.OpinionDelta(from, to, topic, 50f, sharedLanguage: true, TalkActions.Chat, ApparelIssue.None, rules, catalog); var without = TalkCircles.OpinionDelta(from, to, topic, 50f, sharedLanguage: false, TalkActions.Chat, ApparelIssue.None, rules, catalog); Assert.True(withLanguage > without); Assert.True(without <= 1); } [Fact] public void HighCommunication_MovesOpinionMoreThanLow_OnSameTopic() { var (catalog, _, _) = World(); var rules = catalog.BehaviorRules!; var topic = catalog.Topics["TopicSport"]; var from = Person("a", ["RussianLanguage"]); var to = Person("b", ["RussianLanguage"]); var high = TalkCircles.OpinionDelta(from, to, topic, 80f, true, TalkActions.Chat, ApparelIssue.None, rules, catalog); var low = TalkCircles.OpinionDelta(from, to, topic, 20f, true, TalkActions.Chat, ApparelIssue.None, rules, catalog); Assert.True(high > low); } [Fact] public void Enemies_AreNotRankedAsInvitees() { var (catalog, _, _) = World(); var opinions = new Dictionary(StringComparer.Ordinal) { ["b"] = 50, ["c"] = -50, }; var initiator = Person("a", []) with { Opinions = opinions }; var ranked = TalkCircles.RankInvitees( initiator, [ new TalkCircles.Candidate("b", "c1", true, false, false), new TalkCircles.Candidate("c", "c1", true, false, false), ], catalog.BehaviorRules); Assert.Equal(["b"], ranked); } private static ActorState Actor(string node, bool hasPhone) { var (catalog, _, _) = World(); return new ActorState( node, node, false, false, true, false, false, false, node, Needs(social: 0.2f), Intent.None, Talk: new TalkPlannerContext("p1", new Dictionary(), new Dictionary(), null, hasPhone, true, catalog.BehaviorRules)); } private static Dictionary Needs(float social = 1f) => new(StringComparer.Ordinal) { ["Social"] = social, ["Hunger"] = 1f, ["Sleep"] = 1f, ["Toilet"] = 1f, }; private static (DefCatalog Catalog, MapLayout Map, WalkGraph Walks) World() { var (catalog, map) = Fixtures.Vanilla(); return (catalog, map, WalkGraph.Build(catalog, map)); } private static Person Person(string id, string[] languages) { var skills = languages.ToDictionary(skill => skill, _ => 60, StringComparer.Ordinal); skills["Communication"] = 50; var cases = new CaseTable { Nom = "A", Gen = "A", Dat = "A", Acc = "A", Ins = "A", Pre = "A", }; return new Person { Id = id, FamilyId = "f1", Female = false, BirthDate = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc), Name = new PersonName("A", "B", "C", cases, cases, cases), IsStudent = true, IsStaff = false, IsParent = false, Numbers = new Dictionary(StringComparer.Ordinal), Choices = new Dictionary(StringComparer.Ordinal), Skills = skills, Traits = [], Needs = new Dictionary(StringComparer.Ordinal), Opinions = new Dictionary(StringComparer.Ordinal), }; } }