1 /*
2  * Copyright (C) 2007 Jordi Mas i Hernàndez <jmas@softcatala.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * 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 GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 using System;
19 using Cairo;
20 
21 using gbrainy.Core.Main;
22 using gbrainy.Core.Toolkit;
23 using gbrainy.Core.Services;
24 
25 namespace gbrainy.Games.Logic
26 {
27 	public class PuzzleMissingSlice : Game
28 	{
29 		private const int total_slices = 6;
30 		private const int half_slices = total_slices / 2;
31 		private const int items_per_slice = 3;
32 		private const double radius = 0.22;
33 		private const double radian = Math.PI / 180;
34 		private const double arc_centerx = 0.2, arc_centery = 0.2;
35 		private const int possible_answers = 3;
36 		private ArrayListIndicesRandom random_indices;
37 		private int ans_pos;
38 		private int[] bad_answers;
39 		private int sum_offset;
40 
41 		private int [] slices = new int []
42 		{
43 			2, 4, 3,
44 			2, 3, 6,
45 			1, 3, 4,
46 			3, 7, 1,
47 			6, 3, 2,
48 		};
49 
50 		private int [] slices_opposite = new int []
51 		{
52 			6, 4, 5,
53 			6, 5, 2,
54 			7, 5, 4,
55 			5, 1, 7,
56 			2, 5, 6,
57 		};
58 
59 		public override string Name {
60 			get {return Translations.GetString ("Missing slice");}
61 		}
62 
63 		public override string Question {
64 			get {return String.Format (
65 				Translations.GetString ("The slices below have some kind of relation. Which is the missing slice in the circle below? Answer {0}, {1} or {2}."),
66 				Answer.GetMultiOption (0), Answer.GetMultiOption (1), Answer.GetMultiOption (2));}
67 		}
68 
69 		public override string Tip {
70 			get { return Translations.GetString ("Each slice is related to the opposite one.");}
71 		}
72 
73 		public override string Rationale {
74 			get {
75 				return String.Format (Translations.GetString ("All numbers of each slice, when added to the ones of the opposite slice, add always {0}."), sum_offset + 8);
76 			}
77 		}
78 
Initialize()79 		protected override void Initialize ()
80 		{
81 			sum_offset = random.Next (3);
82 			random_indices = new ArrayListIndicesRandom (slices.Length / items_per_slice);
83 			random_indices.Initialize ();
84 			ans_pos = random.Next (possible_answers);
85 
86 			Answer.CheckAttributes |= GameAnswerCheckAttributes.MultiOption | GameAnswerCheckAttributes.IgnoreSpaces;
87 			Answer.SetMultiOptionAnswer (ans_pos, Answer.GetFigureName (ans_pos));
88 
89 			bad_answers = new int [possible_answers * items_per_slice];
90 			for (int i = 0; i < bad_answers.Length; i++) {
91 				bad_answers[i] = 1 + random.Next (9);
92 			}
93 
94 			HorizontalContainer container = new HorizontalContainer (DrawAreaX, 0.62, 0.8, 0.3);
95 			DrawableArea drawable_area;
96 			AddWidget (container);
97 
98 			for (int i = 0; i < possible_answers; i++)
99 			{
100 				drawable_area = new DrawableArea (0.8 / 3, 0.3);
101 				drawable_area.SelectedArea = new Rectangle (0, 0, radius, 0.2);
102 				drawable_area.Data = i;
103 				drawable_area.DataEx = Answer.GetMultiOption (i);
104 				container.AddChild (drawable_area);
105 
106 				drawable_area.DrawEventHandler += delegate (object sender, DrawEventArgs e)
107 				{
108 					int n = (int) e.Data;
109 
110 					DrawSlice (e.Context, 0, 0);
111 					if (n == ans_pos) {
112 						int pos = random_indices [0];
113 						DrawSliceText (e.Context, 0, 0, 0, (sum_offset +
114 						slices [pos * items_per_slice]).ToString (),
115 						(sum_offset + slices [1 + (pos * items_per_slice)]).ToString (),
116 						(sum_offset + slices [2 + (pos * items_per_slice)]).ToString ());
117 					} else {
118 						DrawSliceText (e.Context, 0, 0, 0,
119 							bad_answers [n * items_per_slice].ToString (),
120 							bad_answers [1 + (n * items_per_slice)].ToString (),
121 							bad_answers [2 + (n * items_per_slice)].ToString ());
122 					}
123 
124 					e.Context.MoveTo (0.0, 0.25);
125 					e.Context.DrawTextCentered (radius / 2, 0.25, Answer.GetFigureName (n));
126 					e.Context.Stroke ();
127 				};
128 			}
129 		}
130 
DrawSlice(CairoContextEx gr, double x, double y)131 		private static void DrawSlice (CairoContextEx gr, double x, double y)
132 		{
133 			double degrees, x1, y1;
134 
135 			degrees = 0;
136 			gr.MoveTo (x, y);
137 			x1 = x + radius * Math.Cos (degrees);
138 			y1 = y + radius * Math.Sin (degrees);
139 			gr.LineTo (x1, y1);
140 			gr.Stroke ();
141 
142 			degrees = radian * 60;
143 			gr.MoveTo (x, y);
144 			x1 = x + radius * Math.Cos (degrees);
145 			y1 = y + radius * Math.Sin (degrees);
146 			gr.LineTo (x1, y1);
147 			gr.Stroke ();
148 
149 			gr.Arc (x, y, radius, 0, radian * 60);
150 			gr.Stroke ();
151 		}
152 
DrawSliceText(CairoContextEx gr, double x, double y, int slice, string str1, string str2, string str3)153 		static private void DrawSliceText (CairoContextEx gr, double x, double y, int slice, string str1, string str2, string str3)
154 		{
155 			double x0, y0, degrees;
156 
157 			// Number more near to the center;
158 			degrees = radian * (slice * ((360 / total_slices)) + (360 / 12));
159 			x0 = 0.35 * radius * Math.Cos (degrees);
160 			y0 = 0.35 * radius * Math.Sin (degrees);
161 			gr.DrawTextCentered (x + x0, y + y0, str1);
162 
163 			// Number opposite to the center and at the top
164 			degrees = radian * (slice * ((360 / total_slices)) + (360 / 24));
165 			x0 = 0.8 * radius * Math.Cos (degrees);
166 			y0 = 0.8 * radius * Math.Sin (degrees);
167 			gr.DrawTextCentered (x + x0, y + y0, str2);
168 
169 			// Number opposite to the center and at the bottom
170 			degrees = radian * (slice * ((360 / total_slices)) + (360 / 8));
171 			x0 = 0.8 * radius * Math.Cos (degrees);
172 			y0 = 0.8 * radius * Math.Sin (degrees);
173 			gr.DrawTextCentered (x + x0, y + y0, str3);
174 		}
175 
Draw(CairoContextEx gr, int area_width, int area_height, bool rtl)176 		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
177 		{
178 			double x = DrawAreaX + 0.2, y = DrawAreaY;
179 			double x0, y0, degrees;
180 			int pos;
181 
182 			base.Draw (gr, area_width, area_height, rtl);
183 
184 			gr.Arc (x + arc_centerx, y + arc_centery, radius, 0, 2 * Math.PI);
185 			gr.Stroke ();
186 
187 			for (int slice = 0; slice < total_slices; slice++)
188 			{
189 				degrees = radian * slice * (360 / total_slices);
190 				gr.MoveTo (x + arc_centerx, y + arc_centery);
191 				gr.LineTo (x + arc_centerx + (radius * Math.Cos (degrees)), y + arc_centery + (radius * Math.Sin (degrees)));
192 
193 				if (slice > total_slices - 1) continue;
194 
195 				if (slice == 0) {
196 					degrees = radian * (slice * ((360 / total_slices)) + (360 / 12));
197 					x0 = 0.5 * radius * Math.Cos (degrees);
198 					y0 = 0.5 * radius * Math.Sin (degrees);
199 					gr.DrawTextCentered (x + arc_centerx + x0, y + arc_centery + y0, "?");
200 					continue;
201 				}
202 
203 				if (slice < half_slices) {
204 					pos = random_indices [slice];
205 					DrawSliceText (gr, x + arc_centerx, y + arc_centery, slice, (sum_offset + slices [pos * items_per_slice]).ToString (),
206 						 (sum_offset + slices [1 + (pos * items_per_slice)]).ToString (), (sum_offset + slices [2 + (pos * items_per_slice)]).ToString ());
207 				}
208 				else {
209 					pos = random_indices [slice - half_slices];
210 					DrawSliceText (gr, x + arc_centerx, y + arc_centery, slice, slices_opposite [pos * items_per_slice].ToString (),
211 						 slices_opposite [2 + (pos * items_per_slice)].ToString (), slices_opposite [1 + (pos * items_per_slice)].ToString ());
212 				}
213 			}
214 
215 			gr.MoveTo (0.1, 0.55);
216 			gr.ShowPangoText (Translations.GetString ("Choose one of the following:"));
217 			gr.Stroke ();
218 		}
219 	}
220 }
221