aboutsummaryrefslogtreecommitdiffstats
path: root/src/NameGame.cc
diff options
context:
space:
mode:
authorAiden Woodruff <woodra@rpi.edu>2025-11-14 11:36:02 -0500
committerAiden Woodruff <woodra@rpi.edu>2025-11-14 11:36:02 -0500
commit81b45c03ed83658f80b32a46d9f51e298fa8e2f1 (patch)
tree31a33cdeb8ef832c41e2d237dd321716ec583276 /src/NameGame.cc
parentc4b6d2dad64b8136b99fa7358ec141d4a46ff4e9 (diff)
downloadtipping-points-81b45c03ed83658f80b32a46d9f51e298fa8e2f1.tar.gz
tipping-points-81b45c03ed83658f80b32a46d9f51e298fa8e2f1.tar.bz2
tipping-points-81b45c03ed83658f80b32a46d9f51e298fa8e2f1.zip
created encapsulated NameGame class
- src/CMakeLists.txt: add NameGame.cc. - src/NameGame.cc: move best_move, update_memory, run round, round into this class and file. - move begin/end for TVec here. - add initGraph and initMemory for changing sizes. - src/NameGame.h: add class declaration. - main.cc: move all functions out of here. - use one object and re initialize memory for different committed minority sizes. Signed-off-by: Aiden Woodruff <woodra@rpi.edu>
Diffstat (limited to 'src/NameGame.cc')
-rw-r--r--src/NameGame.cc130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/NameGame.cc b/src/NameGame.cc
new file mode 100644
index 0000000..8ea3dcf
--- /dev/null
+++ b/src/NameGame.cc
@@ -0,0 +1,130 @@
1#include <iostream>
2#include <map>
3#include <stdexcept>
4#include <vector>
5
6#include "NameGame.h"
7
8template<typename TVal, typename TSizeTy>
9auto begin(const TVec<TVal, TSizeTy>& v) -> decltype(v.BegI()) {
10 return v.BegI();
11}
12
13template<typename TVal, typename TSizeTy>
14auto end(const TVec<TVal, TSizeTy>& v) -> decltype(v.EndI()) {
15 return v.EndI();
16}
17
18namespace tp {
19
20NameGame::NameGame(int group_size, int cm_size, int memory) :
21 gsize(group_size), cmsize(cm_size), memlen(memory),
22 rng(std::random_device{}()), dist(0, group_size - 1),
23 graph(group_size, group_size * group_size)
24{
25 if (group_size <= 0)
26 throw std::invalid_argument("NameGame invalid group_size");
27 if (cm_size < 0)
28 throw std::invalid_argument("NameGame invalid cm_size");
29 if (cm_size > group_size)
30 throw std::invalid_argument("NameGame cm_size > group_size");
31 if (memory <= 0)
32 throw std::invalid_argument("NameGame memory <= 0");
33 initGraph();
34}
35
36void NameGame::setCMsize(int cm_size) {
37 if (cm_size <= 0 || cm_size > gsize)
38 throw std::invalid_argument("NameGame::setCMsize invalid cm_size");
39 cmsize = cm_size;
40}
41
42void NameGame::initGraph() {
43 // Generate complete graph.
44 for (int i = 0; i < gsize; ++i) graph.AddNode(i, {false, {}});
45 for (int i = 0; i < gsize; ++i)
46 for (int j = 0; j < gsize; ++j)
47 if (i != j) graph.AddEdge(i, j);
48 initMemory();
49}
50
51void NameGame::initMemory() {
52 std::vector<int> ids(gsize);
53 std::iota(ids.begin(), ids.end(), 0);
54 // Set committed minority.
55 for (int i = 0; i < cmsize; ++i) {
56 int r = dist(rng) % ids.size();
57 int rId = ids[r];
58 auto& rDat = graph.GetNDat(rId);
59 rDat.Val1 = true;
60 rDat.Val2.Clr();
61 rDat.Val2.Add(2);
62 ids.erase(ids.begin() + r);
63 }
64 // Establish norm (fully memory of strategy 1) for remaining nodes.
65 for (int id : ids) {
66 auto& d = graph.GetNDat(id);
67 d.Val1 = false;
68 d.Val2.Clr();
69 while (d.Val2.Len() < memlen) d.Val2.Add(1);
70 }
71}
72
73void NameGame::run(int rounds) {
74 if (rounds < 0) throw std::invalid_argument("NameGame::run rounds < 0");
75 for (int i = 0; i < rounds; ++i) runRound();
76 // Track all plays and plays by non-CM.
77 // Report average plays.
78}
79
80void NameGame::runRound() {
81 // Select random speaker and hearer.
82 auto speaker = graph.GetNI(dist(rng));
83 auto hearer = graph.GetNI(
84 speaker.GetNbrNId(dist(rng) % speaker.GetDeg())
85 );
86
87 // Speaker chooses best strategy.
88 int s_strategy = best_move(speaker.GetId());
89 std::cout << "speaker (" << speaker.GetId() << " "
90 << std::boolalpha << speaker().Val1
91 << ") chose: " << s_strategy << std::endl;
92
93 // Listener updates memory.
94 update_memory(hearer.GetId(), s_strategy);
95
96 // Listener chooses best strategy.
97 int h_strategy = best_move(hearer.GetId());
98 std::cout << "hearer (" << hearer.GetId() << " "
99 << std::boolalpha << hearer().Val1
100 << ") chose: " << h_strategy << std::endl;
101
102 // Speaker updates memory.
103 update_memory(speaker.GetId(), s_strategy);
104}
105
106int NameGame::best_move(int nId) const {
107 const auto& mem = graph.GetNDat(nId).Val2;
108 std::map<int, int> votes;
109 for (const auto& v : mem) {
110 if (votes.count(v)) votes[v] += 1;
111 else votes[v] = 1;
112 }
113 std::map<int, float> fractions;
114 for (auto kv : votes) fractions[kv.first] = kv.second * 1./mem.Len();
115 // Simple majority vote:
116 for (auto kv : fractions)
117 if (kv.second >= 1./mem.Len()) return kv.first;
118 return 0;
119}
120
121void NameGame::update_memory(int nId, int strategy) {
122 auto d = graph.GetNDat(nId);
123 if (!d.Val1) {
124 auto& mem = d.Val2;
125 mem.Ins(0, strategy);
126 mem.Trunc(memlen);
127 }
128}
129
130} // namespace tp