1 // Brain Party
2 // Copyright (C) 2010 Paul Hudson (http://www.tuxradar.com/brainparty)
3 
4 // Brain Party is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 
18 #include "symboliclogic.h"
19 #include "Minigame.h"
20 #include <algorithm>
21 #include <cctype>
22 
BPMiniGame_SymbolicLogic(BPGame * game)23 BPMiniGame_SymbolicLogic::BPMiniGame_SymbolicLogic(BPGame* game) : BPMiniGame(game) {
24 	sfcBackground = TheGame->LoadBitmap("symboliclogic", 320, 416);
25 
26 	LastStateChange = CurrentLevel = Score = NumTries = 0;
27 	GameState = WAITING;
28 
29 	sfcText = NULL;
30 
31 	AnswerIsTrue = false;
32 
33 	TimeStarted = 0;
34 
35 	GameTitle = "Symbolic Logic";
36 	GameHelp = "I'm going to give you two statements that I'd like you to accept as truth. Based on those two facts, are my conclusions true or false?";
37 	GameHelp2 = "If you read the questions carefully, you should be OK, but remember: if the conclusion says \"A must be a B\" and you think \"A could be a B or it could not be a B; I don't know\", then clearly the conclusion is wrong!";
38 
39 	MiniGameType = PUZZLE;
40 
41 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can play the guitar", "can't play the guitar", "can play the guitar", "guitarists"));
42 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can play the piano", "can't play the piano", "can play the piano", "pianists"));
43 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can play the violin", "can't play the violin", "can play the violin", "violinists"));
44 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can speak Chinese", "can't speak Chinese", "can speak Chinese", "Chinese speakers"));
45 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can speak French", "can't speak French", "can speak French", "French speakers"));
46 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can speak Japanese", "can't speak Japanese", "can speak Japanese", "Japanese speakers"));
47 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can speak Latin", "can't speak Latin", "can speak Latin", "Latin speakers"));
48 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("can speak Spanish", "can't speak Spanish", "can speak Spanish", "Spanish speakers"));
49 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("drives a car", "can't drive a car", "drive a car", "car drivers"));
50 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("eats mashed potato", "doesn't eat mashed potato", "like mashed potato", "mashed potato eaters"));
51 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("enjoys cooking", "doesn't enjoy cooking", "enjoy cooking", "cooks"));
52 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("exercises regularly", "doesn't exercise regularly", "exercise regularly", "regular exercisers"));
53 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("goes to church", "doesn't go to church", "go to church", "churchgoers"));
54 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("has brown hair", "doesn't have brown hair", "have brown hair", "brown-haired people"));
55 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("has blue eyes", "doesn't have blue eyes", "have blue eyes", "blue-eyed people"));
56 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("has curly hair", "doesn't have curly hair", "have curly hair", "curly-haired people"));
57 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("hates computers", "doesn't hate computers", "hate computers", "computer haters"));
58 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("is very clever", "isn't very clever", "are very clever", "very clever people"));
59 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("is very popular", "isn't very popular", "are very popular", "very popular people"));
60 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes bowling", "doesn't like bowling", "like bowling", "bowlers"));
61 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes broccoli", "doesn't like broccoli", "like broccoli", "broccoli eaters"));
62 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes eating carrots", "doesn't like eating carrots", "like eating carrots", "carrot eaters"));
63 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes eating dessert", "doesn't like eating dessert", "like eating dessert", "dessert eaters"));
64 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes puzzles", "doesn't like puzzles", "like puzzles", "people who like puzzles"));
65 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("likes to sing", "doesn't like to sing", "like to sing", "singers"));
66 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("loves animals", "doesn't like animals", "like animals", "animal lovers"));
67 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("loves Shakespeare", "doesn't love Shakespeare", "love Shakespeare", "Shakespeare lovers"));
68 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a mansion", "doesn't own a mansion", "own a mansion", "mansion owners"));
69 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("plays golf", "doesn't play golf", "play golf", "golfers"));
70 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("plays Sudoku", "doesn't play Sudoku", "play Sudoku", "Sudoku players"));
71 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("plays tennis", "doesn't play tennis", "play tennis", "tennis players"));
72 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a cat", "doesn't own a cat", "own a cat", "cat owners"));
73 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a cellphone", "doesn't own a cellphone", "own a cellphone", "cellphone owners"));
74 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a dog", "doesn't own a dog", "own a dog", "dog owners"));
75 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a goat", "doesn't own a goat", "own a goat", "goat owners"));
76 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a hamster", "doesn't own a hamster", "own a hamster", "hamster owners"));
77 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a parrot", "doesn't own a parrot", "own a parrot", "parrot owners"));
78 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("owns a rabbit", "doesn't own a rabbit", "own a rabbit", "rabbit owners"));
79 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("reads books", "doesn't read books", "read books", "people who read books"));
80 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("reads newspapers", "doesn't read newspapers", "read newspapers", "newspaper readers"));
81 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("rides a bike", "doesn't ride a bike", "ride a bike", "bicyclists"));
82 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("walks to work", "doesn't walk to work", "walk to work", "people who walk to work"));
83 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("watches TV", "doesn't watch TV", "watch TV", "TV watchers"));
84 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("wears glasses", "doesn't wear glasses", "wear glasses", "people who wear glasses"));
85 	LogicItems.Add(new BPMiniGame_SymbolicLogic_Item("wrestles crocodiles", "doesn't wrestle crocodiles", "wrestle crocodiles", "crocodile wrestlers"));
86 }
87 
~BPMiniGame_SymbolicLogic()88 BPMiniGame_SymbolicLogic::~BPMiniGame_SymbolicLogic() {
89 	SAFE_DELETE(sfcBackground);
90 
91 	LogicItems.Clear();
92 	Premises.Clear();
93 
94 	SAFE_DELETE(sfcText);
95 }
96 
Start()97 void BPMiniGame_SymbolicLogic::Start() {
98 	TimeStarted = TheGame->TickCount;
99 	LevelUp();
100 }
101 
GetWeight()102 int BPMiniGame_SymbolicLogic::GetWeight() {
103 	float TimePassed = (TheGame->TickCount - TimeStarted) / 1000.0f;
104 	return MinMax(Score - round(TimePassed));
105 }
106 
Render()107 void BPMiniGame_SymbolicLogic::Render() {
108 	TheGame->DrawImage(sfcBackground, 0, 0);
109 
110 	TheGame->DrawString(sfcText, WHITE, 20, 19);
111 
112 	if (GameState == CORRECT) {
113 		RenderCorrect();
114 	} else if (GameState == WRONG) {
115 		RenderWrong();
116 	}
117 }
118 
FlattenPremise(BPMiniGame_SymbolicLogic_Premise * premise)119 const char* BPMiniGame_SymbolicLogic::FlattenPremise(BPMiniGame_SymbolicLogic_Premise* premise) {
120 	ostringstream result;
121 
122 	switch (premise->Type) {
123 		case ALL_JOB:
124 			result << "All " << premise->Job << "s " << premise->Item->PluralDesc;
125 			break;
126 
127 		case NONE_JOB:
128 			result << "No " << premise->Job << " " << premise->Item->SingularDesc;
129 			break;
130 
131 		case ALL_ITEM:
132 			result << "All " << premise->Item->Noun << " are " << premise->Job << "s";
133 			break;
134 
135 		case NONE_ITEM:
136 			result << "No " << premise->Item->Noun << " are " << premise->Job << "s";
137 			break;
138 
139 		case PERSON:
140 			if (premise->Item == NULL) {
141 				if (TheGame->StartsWithVowel(&premise->Job)) {
142 					result << premise->Text << " is an " << premise->Job;
143 				} else {
144 					result << premise->Text << " is a " << premise->Job;
145 				}
146 			} else {
147 				result << premise->Text << " " << premise->Item->SingularDesc;
148 			}
149 
150 			break;
151 	}
152 
153 	return result.str().c_str();
154 }
155 
Tick()156 void BPMiniGame_SymbolicLogic::Tick() {
157 	if (LastStateChange != -1 && LastStateChange + 500 < TheGame->TickCount) {
158 		if (NumTries >= 10 && !MarathonMode) {
159 			Success();
160 			return;
161 		} else {
162 			LevelUp();
163 		}
164 	}
165 }
166 
OnMouseDown()167 void BPMiniGame_SymbolicLogic::OnMouseDown() {
168 
169 }
170 
OnMouseMove()171 void BPMiniGame_SymbolicLogic::OnMouseMove() {
172 
173 }
174 
OnMouseUp()175 void BPMiniGame_SymbolicLogic::OnMouseUp() {
176 	switch (GameState) {
177 		case CORRECT:
178 		case WRONG:
179 			LevelUp();
180 			break;
181 
182 		case WAITING:
183 			// have we just answered the question?
184 
185 			if (TheGame->PointOverRect(TouchEvent.X, TouchEvent.Y, 11, 342, 143, 63)) {
186 				// True clicked!
187 				LastStateChange = TheGame->TickCount;
188 
189 				if (AnswerIsTrue) {
190 					TheGame->PlaySound("correct");
191 					GameState = CORRECT;
192 					Score += 50;
193 				} else {
194 					TheGame->PlaySound("wrong");
195 					GameState = WRONG;
196 					Score -= 100;
197 				}
198 			} else if (TheGame->PointOverRect(TouchEvent.X, TouchEvent.Y, 166, 342, 143, 63)) {
199 				// False clicked!
200 				LastStateChange = TheGame->TickCount;
201 
202 				if (!AnswerIsTrue) {
203 					TheGame->PlaySound("correct");
204 					GameState = CORRECT;
205 					Score += 50;
206 				} else {
207 					TheGame->PlaySound("wrong");
208 					GameState = WRONG;
209 					Score -= 50;
210 				}
211 			}
212 
213 			break;
214 	}
215 }
216 
LevelUp()217 void BPMiniGame_SymbolicLogic::LevelUp() {
218 	if (NumTries >= 10 && !MarathonMode) {
219 		return;
220 	}
221 
222 	++CurrentLevel;
223 	++NumTries;
224 	LastStateChange = -1;
225 	GameState = WAITING;
226 
227 	Premises.Clear();
228 	LogicItems.Shuffle();
229 
230 	BPMiniGame_SymbolicLogic_Premise* FirstPremise;
231 	BPMiniGame_SymbolicLogic_Premise* SecondPremise;
232 
233 	string Job;
234 	string PersonName;
235 	ostringstream NegativeConclusion;
236 	ostringstream Conclusion;
237 
238 	bool is_negative = false;
239 
240 	if (TheGame->RandomRange(0, 1) == 1) {
241 		NegativeConclusion << "not ";
242 		is_negative = true;
243 	}
244 
245 	Job = GetRandomJob();
246 	PersonName = TheGame->GetName();
247 
248 	FirstPremise = new BPMiniGame_SymbolicLogic_Premise();
249 	FirstPremise->Type = GetPremiseType();
250 	FirstPremise->Job = Job;
251 	FirstPremise->Item = LogicItems[0];
252 	Premises.Add(FirstPremise);
253 
254 	SecondPremise = new BPMiniGame_SymbolicLogic_Premise();
255 	SecondPremise->Type = PERSON;
256 	SecondPremise->Text = PersonName;
257 	switch (TheGame->RandomRange(0, 1)) {
258 		case 0:
259 			SecondPremise->Item = LogicItems[0];
260 			Premises.Add(SecondPremise);
261 
262 			if (TheGame->StartsWithVowel(&Job)) {
263 				Conclusion << "Therefore, " << PersonName << " is " << NegativeConclusion.str() << "an " << Job;
264 			} else {
265 				Conclusion << "Therefore, " << PersonName << " is " << NegativeConclusion.str() << "a " << Job;
266 			}
267 
268 			break;
269 
270 		case 1:
271 			SecondPremise->Job = Job;
272 			Premises.Add(SecondPremise);
273 
274 			if (!is_negative) {
275 				Conclusion << "Therefore, " << PersonName << " " << LogicItems[0]->SingularDesc;
276 			} else {
277 				Conclusion << "Therefore, " << PersonName << " " << LogicItems[0]->Negative;
278 			}
279 
280 			break;
281 	}
282 
283 	if (FirstPremise->Type == ALL_JOB) {
284 		if (SecondPremise->Job.size() != 0) {
285 			AnswerIsTrue = true;
286 			if (is_negative) AnswerIsTrue = !AnswerIsTrue;
287 		} else {
288 			AnswerIsTrue = false;
289 		}
290 	} else if (FirstPremise->Type == ALL_ITEM) {
291 		if (SecondPremise->Item != NULL) {
292 			AnswerIsTrue = true;
293 			if (is_negative) AnswerIsTrue = !AnswerIsTrue;
294 		} else {
295 			AnswerIsTrue = false;
296 		}
297 	} else if (FirstPremise->Type == NONE_JOB) {
298 		if (SecondPremise->Job.size() != 0) {
299 			AnswerIsTrue = false;
300 		} else {
301 			AnswerIsTrue = false;
302 		}
303 
304 		if (is_negative) AnswerIsTrue = !AnswerIsTrue;
305 	} else {
306 		if (SecondPremise->Item != NULL) {
307 			AnswerIsTrue = false;
308 		} else {
309 			AnswerIsTrue = false;
310 		}
311 
312 		if (is_negative) AnswerIsTrue = !AnswerIsTrue;
313 	}
314 
315 	string PrintMe = string();
316 
317 	for (int i = 0; i < Premises.Count; ++i) {
318 		BPMiniGame_SymbolicLogic_Premise* premise = Premises[i];
319 		string str = FlattenPremise(premise);
320 		PrintMe.append(str);
321 		PrintMe.append(". ");
322 	}
323 
324 	PrintMe.append(Conclusion.str());
325 	PrintMe.append(". ");
326 
327 	TheGame->AllocString(&sfcText, PrintMe.c_str(), LARGE, 282, 306, LEFT);
328 }
329 
GetPremiseType()330 PremiseTypes BPMiniGame_SymbolicLogic::GetPremiseType() {
331 	switch (TheGame->RandomRange(0, 3)) {
332 		case 0:
333 			return ALL_JOB;
334 		case 1:
335 			return NONE_JOB;
336 		case 2:
337 			return ALL_ITEM;
338 		default:
339 			return NONE_ITEM;
340 	}
341 }
342 
GetRandomJob()343 string BPMiniGame_SymbolicLogic::GetRandomJob() {
344 	string meh = TheGame->TestBrainJobs[TheGame->RandomRange(0, 51)];
345 	transform(meh.begin(), meh.end(), meh.begin(), (int(*)(int)) tolower);
346 	return meh;
347 }
348 
SetMarathon()349 void BPMiniGame_SymbolicLogic::SetMarathon() {
350 	MarathonMode = true;
351 }
352