diff options
| author | Aiden Woodruff <woodra@rpi.edu> | 2025-11-14 11:36:02 -0500 |
|---|---|---|
| committer | Aiden Woodruff <woodra@rpi.edu> | 2025-11-14 11:36:02 -0500 |
| commit | 81b45c03ed83658f80b32a46d9f51e298fa8e2f1 (patch) | |
| tree | 31a33cdeb8ef832c41e2d237dd321716ec583276 /src/NameGame.cc | |
| parent | c4b6d2dad64b8136b99fa7358ec141d4a46ff4e9 (diff) | |
| download | tipping-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.cc | 130 |
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 | |||
| 8 | template<typename TVal, typename TSizeTy> | ||
| 9 | auto begin(const TVec<TVal, TSizeTy>& v) -> decltype(v.BegI()) { | ||
| 10 | return v.BegI(); | ||
| 11 | } | ||
| 12 | |||
| 13 | template<typename TVal, typename TSizeTy> | ||
| 14 | auto end(const TVec<TVal, TSizeTy>& v) -> decltype(v.EndI()) { | ||
| 15 | return v.EndI(); | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace tp { | ||
| 19 | |||
| 20 | NameGame::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 | |||
| 36 | void 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 | |||
| 42 | void 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 | |||
| 51 | void 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 | |||
| 73 | void 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 | |||
| 80 | void 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 | |||
| 106 | int 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 | |||
| 121 | void 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 | ||
