Episode: 2908 Title: HPR2908: Modeling opinions in space game Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2908/hpr2908.mp3 Transcribed: 2025-10-24 13:04:30 --- This in HPR episode 2988 titled, Modeling Opinion in Space Game, and in part of the series, Haskell, it is hosted by Tuku Toroto, and in about 35 minutes long, and Karima Clean Flag, the Summer Inn, Tuku Toroto talks about Modeling Opinion. This episode of HPR is brought to you by AnanasThost.com. Get 15% discount on all shared hosting with the offer code HPR15. That's HPR15. Bitcher web hosting that's honest and fair at AnanasThost.com. Hello, you are listening to the Hacker Public Radio and this is Tutur Tottenham of Making at Space Game in Haskell. Today, we continue with people, this time with the Opinions. There is some more code around this time, but it might be a good idea to follow it, shown once I try to keep the amount of code that I'm reading aloud to the minimum though. So, Opinions. Different kinds of people get along with each other at a varying degree. And in the game, this is modeled with the Opinions code. It can range from minus 100 to 100. The 0 is neutral, minus 100 is the worst, and 100 is the best possible. And Opinions may affect to the things like trade deals or marriage proposals or declarations and such. And current system is somewhat limited. There are two things that are taken into account. Currently, there's a trade and relations. Trades are defining things about characters. You can be, for example, brave or coward or diligent or whatever. These are well-straighted. So, for example, two brave characters automatically like each other a bit better than prey than coward. And relations are relations between characters like parent and child, automatically we like each other better than just a random person. And two rivals will hate each other so much that it takes a lot of work to work over that. So, parent and child have a positive opinion of each other or that relation contributes positively to the opinion. And two rivals will have a negative opinion of each other. And to make things even complicated, all this is based on the interlevels which may lead into the incorrect results just like in the real life. So, if you don't have inter of some character, you don't get as good as good information about them than if you have the inter. And the report, there's always reports that have a whole different levels of information. And this is modeled in the report press would data. That is, that's for internal use only. Client never sees that one. And it has two things that actually three things he's struck off. Confidence level, like what level of confidence you have on this result. Then there's the opinion score, attention to minus 100 to 100. And they might be a list of opinion reasons. It tells you that why you don't like somebody or why somebody else doesn't like, why two characters that are not you don't like each other or like each other. So, this is as a reparture result. It's a numeration with three value constructors feeling level that takes opinion score as a parameter. Reason level takes that takes an opinion score and a list of opinion reasons. And details level that takes an opinion score and a list of opinion reasons. So, if you only have a gut feeling of something you you too get a score, but you don't get a list of reasons. If you have reasons level, then you have a, then you have a score and a list of reasons. And if you have detailed level, you have a better or better detailed information about this. There you have a score and it's the reasons. Two last cases look similar, but they turn into a little bit different explanation and attention into the client. That's why I'm giving them separate. Okay, and a reparture result has semi-group and monoid instances because I want it to be a monoid so that two results can be combined. So, if I have two reparture results, I can just use the diamond operator to smash them together. And the result is that the scores are added up and the opinion reasons those lists are just concatenated. And then because there's three levels, the feeling level reasons level, deep level, the A, when you combine two of those, reparture results, the confidence level of the new result is the lowest one of the two. So, if you combine two detailed level results, you're going to get a detailed level result. But if you combine feeling level and detail level, you get a feeling level result. The scores are still added up and the lists are opinion reasonable lists are concatenated. And the empty instance, sorry, empty, you need for reparture result is a detailed level without opinion score of 0 and the empty opinion reasonable list because you can combine anything with this value without that combined item changing to anything. I wrote the, I wrote the instance declaration show note, they are not particular interesting, I think, but if you if you want to have a look, they are basically they are just combining the scores together and lists together and keeping the lowest of the level. Okay, now that we have a reparture result that we can use to give track of the, what's what's the, what's the result of opinion calculation we can get, get started. The, so, so like I said, there's two cases or two sources, however you want to, however you want to think about it. And first I'm going to tackle the opinion based on its rates. So, if you have two persons and you know what rates they have, you can calculate or compute what's the, how they like each other. And here's a thing, it could be between a player character and somebody, or it would be, then the, then the results would be that how much the player character likes somebody and how much that's a mother character likes the player. Or it could be between two, two, two different characters that are not the player character. Then the, then the result will be how, how well they like each other based on the information what the player has. This is, this isn't always true, player might not have all the information available. So, in that case, it's just the, the best, the best ability, the result is calculated to the best ability. So, current system is based on comparing two lists of the rates. So, you need to, if you want to know how, how the characters like each other, you have to have all their traits as a list. So, if you have a present brave, that's a good, that gives you an opinion bonus. If you have two ambitious characters, that's right, that gives you an opinion bonus. And this doesn't work on the traits that alone cause an effect. So, if you have a character who, if I had a character in a game who would have a hypothetical trait called dislikeable, which would, of course, everybody do, dislike him regardless of their traits. This system cannot handle it. You have to have two traits that can repeat the calculation. So, that, that is something that I need to add up, at some, at some later point. So, I have a function, the basic, basic, very bottom function is a trait, their opinion. That is, given two traits, trait vibes, for example, trait and trait. And it returns, maybe, a couple of opinions go, opinion reason. So, maybe, it's returned, because it doesn't necessarily, if you have some combination of traits that don't cause bonus or malus, then it's, it doesn't necessarily does nothing. But if there's some combination of traits, for example, trait and trait, then it returns just a couple, with opinions go, let's say, five, or then, and the opinion reason of two trait characters automatically like each other. So, given two traits, it will tell how that trait, how that combination affects to the, affects to the opinions and the reason, reasoning behind of it. And in order to have a nice format for, or audata, we have a little help of function, trait score, that takes two trait types, and returns, a couple of opinions go, a list of opinion reasons. This is just a small help function, that takes the result of that previous combination. And in case of nothing, it returns empty, which is a couple way, the opinion score is zero, and the opinion reason, list is just an empty list. But if there's a, if there's a value, if the calculation produces a value, then it returns an opinion score, a list of one item. So this might look up bit silly, why do I want to do it like this? But this is because, a couple of opinions score, opinion reason isn't a monoid, you cannot combine them, but the, a couple of opinions score, list of opinion reason is a monoid. Because, couple, the both elements are monoid, is a monoid. Opinions score is a monoid, because zero is the empty element, and the addition is defined as a, that combination function, opinion reason is in the monoid, because it's a, I mean, you could, it's not that, it's not reasonable monoid, because if you combine two opinion reasons, you would get an opinion reason as a one long string, two strings has been combined together, that does not make any sense. So, but if you make, make it a list, then you can combine two lists, you just add them up. So, two, two reasons cannot be added up in a sensible way, but two lists of reasons can be added in a sensible, sensible way, you just combine the list. And, all this means that, if I use, if I'm making tuples of opinion score, list of opinion reasons, I can combine them with that, damal operator, and that will be handy, at some later point, during this episode. Okay, so, in order to calculate the score, based on the trait, we, we do it like a, there's a bit code, that there's a function trait score, that takes a list of trait type, person intel, analyst of trait type, analyst of person intel, and producer report, report, report, result. We need that, there's the first trait type is for the originator, and the person intel, intel for that person, and the second trait type and person intel is for the target, the names are kind of arbitrary in this case. So, I have two, two characters, I have list of the trait, and list of the intel, that we have available of those characters, and based on all this information, we are going to produce a report of result. Inside of the function data, if it checks that the intel contains, both intel contains trait, so we have a trait information of both of these characters, if so, we are going to return detailed level, result with a score and reasons, if we don't have traits on those two characters, then we are going to return feeling level, result with only score, and most likely in this case, the trait list will be empty anyway, and how we are going to calculate the score and reasons, this is our reading aloud, this is our open parent score, common reasons, close parent, so we are making a tuffle, and this is distracting it, automatically so we get two values, score and reasons, equals m-conquat, to the trait base, score, time and to the originator phrase, download after this target phrase, so that's a quite a bit of stuff, packed in a small space there, I'll go and try to unpack and explain that a little bit, so the trait base score is a function that expects two trait type values as parameters, so but we call it with two lists of such values, and how we are doing this is that we are putting that time or dollar between trait base score and first parameter, that means that it creates a list of functions of the first parameter comes from the originator phrase list, but second parameter hasn't been given yet, so they are waiting for that second parameter, so trait base score, time and dollar originator phrase creates a list of functions that are waiting for the second parameter, first parameter comes from that list, after this diamond after this target phrase means that we are taking that list of functions, and for each of those functions we are calling with all the parameters or with all the values coming from the target phrase, so that diamond after this applies each function to each value of the second list, and the result here is that if we have a two list, if those elements, if those lists that we have both have two elements, we are going to get four function cores, and how we are going to get a list of four results, so the trait base score will be called first, first it will be called another hundred percent of the order order is, but it does not really matter, the first element is the first element is the trait base score, chord with the first element of the borrowed list, second is the first element of the first list and second element of the later list, third one is the last second element of the first list and the first element of the second list and the fourth one is the second element of the first list and second element of the last list. So it just calls with every possible combination. So this is a list applicator that we are using here. I might have talked about this at some last point. But the end result is that we are going to trade Tesco with combination, all combination with all combination of two lists of parameters. So now we have a peak list of a report results but we are not interested on the peak list of report results. We want one list of one report result and then we are using Mconqat to that list of results. Mconqat is a general function that when given a list of monoids, you will just combine them together. So this uses the time operator that we know that when we define the semi-group for the report result and monoid for the report result. This is why we did it because now we can just call Mconqat to that long list and it will combine all those values. It will take the empty value, time and it will do the first value of the list, time and it will do the second value of the third value list until the end of the list. So let's match them all together. The result is that we have a double of opinion score list of opinion regions and then we, because we define this as an open parent score, comma regions close parent on the left side of the equal sign. We are taking the double apart and ending up with the value of score and value of regions and these we are returning from our trade score function. This is probably kind of convoluted and bad explanation but if you have a chance to look at the show notes, it might probably, I hope, make some more sense. So based on the available Inter report result of correct level is created. So if we know the threads of the port persons, we get details level and if we don't then we get the feeling of result. And this is how we get the opinion or opinion result of the based on the trade scores. Sorry to trade in the inter. So the second part of the puzzle is the opinion based on the relations. This is even more convoluted. This I'm not 100 percent happy but I couldn't figure out better later on doing this. So this is a, this is a basic somewhat similar but it's a bit more complex. So the intel here is two dimensions, the relationship visibility and level of detail. So you can have a base opinion in the choices for opinions and detail opinions. And that second dimension is opinion of two people, other than your character. So I hope that we will be a bit more clear when I explain that. So the relation score is just like, again, it's a person in the list of person in the list of relations and we are going to get a report result out of that. And we need to take account of what level of intel we have about opinions and on what detail. This is the enough function or intel. Visibility is unique relation, visibility is that existing in relation in that particular case and the score is computer present relation. So in the code, in the account, in the relation score, intel, relation equals to m-conquat. So the relative report or intel score, so that I'm going to do the visibility. So we are calling a real report function with the intel we have available about this particular case, score that we calculated depending on the relation, we have outlined the visibility that we have. This is an entity so that this can't be followed without show notes, sorry, sorry about that, but I couldn't get this clean no matter how I tried. But so the bottom line is that the real report function is the one that is doing most of the work. And for that, you are going to give a parameters of opinion in the list, opinions, a couple of opinions called list of opinion reasons, relation, visibility, result, result, result. But what it does here, it's first it tries to find matching intel of what this particular case, like depending on the what type of relation it is, is it a familiar, is it a public relation, which is known to everyone, is it a familiar relation, not only a small group of people, or is it a secret relation, known only to those two particular persons. So it tries to find a visibility that matches. And if there's no matching visibility, then you just get a feeling level, the result, if there's a, if there's a matching, matching a visibility, you can get a feeling level, a reasonable level, or a detailed level, depending on what type of information you have for that particular character. Because like I explained it earlier, if you have two characters that need a one of them is you, and you are trying to figure out how much they, what's the opinion of each other. You have to have intel of those characters, which traits is easy, because you either have that information or you don't have that information. But when you're trying to figure out how they like each other based on the three relationships they have, you have to have an intel on relationships. Of course, and that intel has a, that level that you can have an intel on, you always have an intel on public relationships, because they are public. But you might have a, you might not have an intel on the upper, the secret relations, because you know, the secret. You have to, you have to work on to get that level of information out of them. And you can have, because you have two characters, you could have a full intel on one character, and you could, you would have a thin minimum intel of the another character. And based on that info information, you can try to guess or compute what, how would they like each other. And this is based on the intel you have, this cannot take into account, but intel, those characters have about each other. For example, you might have an intel, secret intel about both characters. That will tell that they are, they dislike each other, utterly, because of some relationship they have with some thought person. But because those two characters don't have that intel about each other, they might have only a public intel about each other. They don't know about that secret relation that another character has. So the opinion of each other is different than what you, what you compute it to be. So this is, like, you cannot, you cannot know what those characters know and calculate the relationship score, opinions score based on that. You just don't, you just don't have that information. You have to go based on the information you have about those characters and make that best effort estimate. Okay, so that's why this is the convoluted and not giving correct results. So to put all of this together, we combine results of these two functions. So we have, we have an opinion result based on the traits and we have an opinion result based on the relationship, relationships. And we can combine these with the animal operator because they are just two, two opinion results which is done more than to get one result where the scores are summed up and the reason lists are connected together and confidently level is lower off the two. So that, that one monoid and semi-group instantly declared earlier that gets quite a bit of use and I found it really handy here. And when we add more factors that might affect to the system or to the opinion, it's just with the time of the results together. It should work just fine. Okay, so now that we have a very important result, we need to transfer into some information that we can return to the client. And here we have an opinion report. The opinion report is the thing that we are returning to the client. We are not returning that opinion report side because it, it, it, it is a bit too much of information. We could feel that that information with the client, but we don't want to do that. We want to return to the client only the information that they actually have access to and actually need. So we have a function report result to opinion result that they've done. Reparture result and retention of opinion result. And because opinion, opinion report is a, it, it's a number of three values. It's a base opinion report of beta, with the opinion feeling. Oh, it's an opinion, the reason report with opinion feeling and list of opinion reactions. Oh, it's detailed opinion report with opinion score list of opinion reactions. So it matches to that, to that report result by that we defined earlier with, bit, bit of changes. So if we have a, if we have a, we feeling level at report result, we are going to get a base opinion report with opinion feeling and opinion feeling is a, a number is just negative, neutral positive. So we are going to turn that score that we spend a lot of effort to calculate into just a value, is it a negative feeling, neutral feeling, positive feeling. I think the, anything below minus 15 is negative and anything above plus 15 is positive and minus 15 to be positive 15 is neutral feeling. So if you, if the character doesn't have enough intel that's going to get a, okay, I have a negative feeling or I think that car person has a positive feeling about that person. If they have a, however, if they get an opinion reason report from the computer, then they are going to get an opinion reason report. Then, to the client, here we have a, again, we have opinion feeling. So it's an, a kind of negative, neutral positive, but we have a list of reasons. So character can, can quantify if, got feeling a little bit better, like I don't like that character because they are ambitious, ambitious and I am ambitious, so they are dangerous for me. Or I bet this character likes that auto character because they are both cardiners, for example. So again, you just get that feeling, but you have a bit more information why you get that feeling. And the last one is that if you have detailed level, detailed level report, you are going to the detailed opinions report where you have actual score and the list of reasons. Here you can, here you can quantify things like this character has an opinion of 25 of that another character because of this list of reasons. And that's about, that's about what the opinions are currently. So by guys head, Robert Erburtza based on the intel, in case of place own avatar, they have full intel of their own avatar. So that's why the opinion about some other person is based, based on holy, on what we know about them. But in case we are talking to somebody else's opinion about us, or person A's opinion of person D, then we don't have, we don't have all that information, or we might have more information that those other characters have which leads to incorrect results, but that's how it goes. You know better what your yourself are thinking than what some other person is thinking. So there's a change of misjudging things. Okay, food or plants, I want to add more things that affect to the opinions, like that single thread thing, like you might have a generally dislikable character, that should be easy enough to add. It would be neat to have a history of actions. Like if you know that there's some character who has consistently been really great, you might like them slightly better because of that. Or if there's some character who is a history of destroying planets, you might dislike them quite a bit because of those history of actions they have done. Culture could be a one thing that we could affect here. You have, you are, you probably, as a character, probably doesn't like characters coming from different culture as much as members of the own culture. And age could be thrown into mix. So if you are in a, you know, maybe folks in the space, maybe some old general might naturally dislike young officers or might like them depending on what kind of traits they have that old general. Or if you have some really old general who is of opinion that nobody under, under age of 50 should be a officer of some level, some certain level, then that might affect to the opinion of the people around them. So I'm going to finish it here. Questions, comments, feedback is always welcome. Even better is if you record your own Hacker Public Radio every so, this day to reach me nowadays is either email or very much there, I'm due to but most of them that show so, hardass. You've been listening to Hacker Public Radio at Hacker Public Radio dot org. We are a community podcast network that release shows every weekday, Monday through Friday. Today's show, like all our shows, was contributed by an HPR listener like yourself. If you ever thought of recording a podcast and click on our contributing to find out how easy it really is. Hacker Public Radio was founded by the Digital Dorf Pound and the Infonomicon Computer Club and is part of the binary revolution at binwreff.com. If you have comments on today's show, please email the host directly, leave a comment on the website or record a follow-up episode yourself unless otherwise stated. Today's show is released under Creative Commons, Attribution, ShareLite, free dot org license.