-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWeirdlyConcrete.cpp
221 lines (195 loc) · 7.25 KB
/
WeirdlyConcrete.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include <set>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include <string>
#include<iostream>
#include <math.h>
#include <map>
using namespace std;
void printDict(std::map<int, int> *dict){
for(map<int, int>::const_iterator it = dict->begin(); it != dict->end(); ++it)
{
//double d = (double)(it->second.first);
std::cout << (it->first) << ": " << it->second << "\n";
}
}
void printDict(std::map<int, double> *dict){
for(map<int, double>::const_iterator it = dict->begin(); it != dict->end(); ++it)
{
//double d = (double)(it->second.first);
std::cout << (it->first) << ": " << it->second << "\n";
}
}
void printPoint(pair<int, int> pii){
cout << "(" << pii.first << ", " << pii.second << ")";
}
void printSet(set<pair<int, int> > *s){
for(set<pair<int, int> >::const_iterator it = s->begin(); it != s->end(); ++it){
printPoint(*it);
}
cout << endl;
}
int gcd(int a, int b){
//I'm new at C++, and __gcd() wasn't working.
int temp = 0;
while(a != 0){
temp = b;
b = a;
a = temp%a;
}
return b;
}
pair<int, int> farthestPoint(pair<int, int> *point, set<pair<int, int> > *others){
// By taking a given point p1, finding the point p2 that is farthest from p1, then finding p3 farthest from p2,
// we get the farthest two points, p2 and p3. This might just be approximate.
// The problem is ill-defined because it does not specify what to do if two lines have the same length (but different numbers of marbles).
// I guess it might make sense to choose the one with more marbles, but that would slow this down greatly.
pair<int, int> winner = *point;
int pointX = winner.first;
int pointY = winner.second;
float dis = 0;
pair<int, int> unpacked;
int otherX = 0;
int otherY = 0;
std::set<pair<int, int> >::iterator it = others->begin();
while (it != others->end())
{
unpacked = *it;
otherX = unpacked.first;
otherY = unpacked.second;
float newDis = sqrt((otherX - pointX)*(otherX - pointX) + (otherY - pointY)*(otherY - pointY));
if(newDis > dis){
dis = newDis;
winner = unpacked;
}
++it;
}
return winner;
}
int longestLineNum(set<pair<int, int> > *marbles){
//Given the list of all the positions of marbles, find the number that is on the line containing the most.
if(marbles->size() <= 2){
return marbles->size();
}
pair<int, int> given = *(marbles->begin());
//printPoint(given);
pair<int, int> farthestFromGiven = farthestPoint(&given, marbles);
//printPoint(farthestFromGiven);
pair<int, int> farFar = farthestPoint(&farthestFromGiven, marbles);
//printPoint(farFar);
int xDiff = ((farFar.first) - (farthestFromGiven.first));
//cout << endl << xDiff << endl;
int yDiff = ((farFar.second) - (farthestFromGiven.second));
//cout<< yDiff << endl;
int grcd = abs(gcd(xDiff, yDiff));
//cout<< grcd << endl;
int xStep = xDiff/grcd;
int yStep = yDiff/grcd;
int checkX = (farthestFromGiven.first) + xStep;
int checkY = (farthestFromGiven.second) + yStep;
int count = 2;
for(int spot = 1; spot < grcd; spot++){
count += marbles->count(pair<int, int>(checkX, checkY));
checkX += xStep;
checkY += yStep;
}
return count;
}
int runProcess(int n, int k){
//hitSet contains all of the positions the path has gone through. A square matrix might be faster, at least for smaller values.
set <pair<int, int> > hitSet;
set <pair<int, int> > marbles;
//Position
int posX = 0;
int posY = 0;
//Keeps track of how many movements since last placed marble.
int count = 0;
//One more than n*k because we want n*k movements rather than n*k positions. If you interpret the problem differently, you may want to change this.
int nk = n*k+1;
bool choiceArray[4] = {false,false,false,false};
int i;
for(i = 0; i < nk; i++){
//Keep track of the places it has been.
hitSet.insert(pair<int, int> (posX, posY));
//When count == n, a marble is placed.
++count;
if (count == n){
count = 0;
marbles.insert(pair<int, int> (posX, posY));
}
//Finds which paths are still open to it
choiceArray[0] = !(bool)hitSet.count(pair<int, int> (posX, posY+1));//up
choiceArray[1] = !(bool)hitSet.count(pair<int, int> (posX, posY-1));//down
choiceArray[2] = !(bool)hitSet.count(pair<int, int> (posX+1, posY));//right
choiceArray[3] = !(bool)hitSet.count(pair<int, int> (posX-1, posY));//left
int sumChoices = choiceArray[0] + choiceArray[1] + choiceArray[2] + choiceArray[3];
//If the path has trapped itself, it returns with -1. This is causes the avg_result and probabilities methods to retry.
if(!sumChoices){
return -1;
}
int randy = rand() % sumChoices;
//Finds which number it actually picked by skipping the ones that it could not pick.
for(int o = 0; o <= randy; o++){
randy += !choiceArray[o];
}
//Moves based on its choice
posX += (randy == 2)-(randy == 3);
posY += (randy == 0)-(randy == 1);
//Reset the array
choiceArray[0] = false;
choiceArray[1] = false;
choiceArray[2] = false;
choiceArray[3] = false;
}
//printSet(&marbles);
return longestLineNum(&marbles);
}
double avg_result(int n, int k, int repeats){
uint sum = 0;
int res;
for(int i = 0; i < repeats; i++){
//runProcess returns None when the path traps itself. I decided to interpret that as a redo.
do{
res = runProcess(n,k);
}while(res < 0);
sum += res;
}
//The arithmetic mean might not be the best way to process this information
return sum/(double)repeats;
}
//Puts the probabilities in the dictionary
void probabilities(int n, int k, uint repeats, std::map<int, double> *dict){
std::map<int, uint> intDict;
int noneCheck;
for(uint i = 0; i < repeats; i++){
do{
noneCheck = runProcess(n, k);
}while(noneCheck < 0);
//There is probably a faster way to do this, but this isn't the slow part anyways.
std::map<int, uint>::iterator it = intDict.find(noneCheck);
if(it != intDict.end()){
it->second++;
}else{
intDict.insert(pair<int, uint>(noneCheck, 1));
}
}
for(map<int, uint>::iterator it = intDict.begin(); it != intDict.end(); ++it)
{
dict->insert(std::pair<int, double>(it->first, it->second / (double)repeats));
}
}
int main(){
//Randomizes the randomizer
srand ( time(NULL) );
//Try values of n and k here.
//Find the result of a single attempt. (might return -1, meaning that it traps itself.)
cout<<runProcess(1,2)<<endl;
//Find the average result of a number of attempts. Retries if it traps itself.
cout<<avg_result(6,6,1000)<<endl;
//Find the probabilities of each outcome other than -1.
std::map<int, double> dict;
probabilities(1,3, 10000, &dict);
printDict(&dict);
return 0;
}