root/Code/oMaE/oMaE/MiniGames/FSM.cs @ 119

Revision 119, 11.2 KB (checked in by acarter, 2 years ago)

Committed in semi-stable state

Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using Microsoft.Xna.Framework;
6using Microsoft.Xna.Framework.Audio;
7using Microsoft.Xna.Framework.Content;
8using Microsoft.Xna.Framework.GamerServices;
9using Microsoft.Xna.Framework.Graphics;
10using Microsoft.Xna.Framework.Input;
11using Microsoft.Xna.Framework.Media;
12using oMaE.Widgets;
13using Serializables;
14
15namespace oMaE.MiniGames
16{
17    /// <summary>
18    /// The finite state machine minigame
19    /// </summary>
20    public class FSM : MiniGame
21    {
22        /// <summary>
23        /// User input for the state machine transitions.
24        /// </summary>
25        private class Transition : GameObject
26        {
27            /// <summary>
28            /// The color of the tile.
29            /// </summary>
30            public Color Color;
31            /// <summary>
32            /// The location o the box.
33            /// </summary>
34            public Vector2 Location;
35            /// <summary>
36            /// The selector of the next direction.
37            /// </summary>
38            public CompassSelector NextDirection;
39            /// <summary>
40            /// The selector of the next state.
41            /// </summary>
42            public DigitSelect NextState;
43            /// <summary>
44            /// The number of states.
45            /// </summary>
46            private int states;
47            /// <summary>
48            /// Creates a new transition.
49            /// </summary>
50            /// <param name="Color">The color of the tile.</param>
51            /// <param name="Location">The location of the box</param>
52            /// <param name="states">The number of states.</param>
53            public Transition(Color Color, Vector2 Location, int states)
54            {
55                this.Color = Color;
56                this.Location = Location;
57                this.states = states;
58            }
59            /// <summary>
60            /// Initializes the transition element.
61            /// </summary>
62            public override void Initialize()
63            {
64                NextDirection = new CompassSelector(new Rectangle((int)Location.X + 75, (int)Location.Y, 50, 50));
65                children.Add(NextDirection);
66                NextState = new DigitSelect(new Rectangle((int)Location.X + 150, (int)Location.Y, 50, 50), states, 0);
67                children.Add(NextState);
68                base.Initialize();
69            }
70            /// <summary>
71            /// Draws the transition element.
72            /// </summary>
73            /// <param name="screen">The screen to be drawn on.</param>
74            public override void Draw(Screen2D screen)
75            {
76                screen.FillRectangle(new Rectangle((int)Location.X, (int)Location.Y, 50, 50), Color.White);
77                screen.FillRectangle(new Rectangle((int)Location.X + 10, (int)Location.Y + 10, 30, 30), Color);
78                base.Draw();
79            }
80        }
81        /// <summary>
82        /// The timing between moves on the simulator.
83        /// </summary>
84        private static long DELAY = 3000;
85        /// <summary>
86        /// The number of states.
87        /// </summary>
88        private int states;
89        /// <summary>
90        /// The board.
91        /// </summary>
92        private string[] board;
93        /// <summary>
94        /// The start point
95        /// </summary>
96        private Point start = new Point(0, 0);
97        /// <summary>
98        /// A timer to keep track of the current time.
99        /// </summary>
100        private long timer = 0;
101        /// <summary>
102        /// The path as determined by the simulator.
103        /// </summary>
104        private List<Vector3> Path = new List<Vector3>();
105        /// <summary>
106        /// The current edge the simulator is on.
107        /// </summary>
108        private int currentEdge { get { return (int) (timer / DELAY); } }
109        /// <summary>
110        /// The percentage across the edge.
111        /// </summary>
112        private int percentAcross { get { return (int) (timer % DELAY); } }
113        /// <summary>
114        /// The colors of the squares.
115        /// </summary>
116        private Color[] colors;
117        /// <summary>
118        /// The transition table.
119        /// </summary>
120        private Transition[][] transitions;
121        /// <summary>
122        /// The height of the grid.
123        /// </summary>
124        private int height;
125        /// <summary>
126        /// The width of the grid.
127        /// </summary>
128        private int width;
129        /// <summary>
130        /// Creates a new FSM game.
131        /// </summary>
132        /// <param name="game">The serialized game.</param>
133        public FSM(FSMGame game) : base(game)
134        {
135            board = game.Board;
136            height = board.Count();
137            width = 0;
138            foreach (string line in board)
139                if (line.Length > width)
140                    width = line.Length;
141            start = new Point(game.Start[0], game.Start[1]);
142            states = game.States;
143            colors = new Color[game.Colors.Length];
144            for (int i = 0; i < colors.Length; ++i)
145                colors[i] = new Color(game.Colors[i][0], game.Colors[i][1], game.Colors[i][2]);
146        }
147        /// <summary>
148        /// Initializes the game.
149        /// </summary>
150        public override void Initialize()
151        {
152            transitions = new Transition[states][];
153            for(int i = 0; i < states; ++i)
154            {
155                transitions[i] = new Transition[colors.Length];
156                for (int j = 0; j < colors.Length; ++j)
157                {
158                    transitions[i][j] = new Transition(colors[j], new Vector2(100 + 250 * i, 100 + 75 * j), states);
159                    children.Add(transitions[i][j]);
160                }
161            }
162            Path.Add(new Vector3(start.X, start.Y, 0));
163            base.Initialize();
164        }
165        /// <summary>
166        /// Updates the game.
167        /// </summary>
168        /// <param name="gameState">The current game state.</param>
169        public override void Update(GameState gameState)
170        {
171            timer += gameState.EllapsedMilliseconds;
172            if (timer >= (Path.Count - 1) * DELAY)
173            {
174                timer = (Path.Count - 1) * DELAY;
175                timer = DELAY * Path.FindIndex(o => o == Path[currentEdge]);
176            }
177            base.Update(gameState);
178        }
179        /// <summary>
180        /// Determines if the puzzle is solved.
181        /// </summary>
182        public override bool Correct
183        {
184            get
185            {
186                Path = new List<Vector3>();
187                Vector3 loc = new Vector3(start.X, start.Y, 0);
188                timer = 0;
189                while (true)
190                {
191                    Path.Add(loc);
192                    if (loc.Y < 0 || loc.Y >= board.Length || loc.X < 0 || loc.X >= board[(int)loc.Y].Length)
193                        return false;
194                    switch (board[(int)loc.Y][(int)loc.X])
195                    {
196                        case '!':
197                            return true;
198                        case 'X':
199                            return false;
200                        default:
201                            int val = board[(int)loc.Y][(int)loc.X] - '0';
202                            switch (transitions[(int)loc.Z][val].NextDirection.Value)
203                            {
204                                case CompassSelector.Direction.NORTH:
205                                    loc = new Vector3(loc.X, loc.Y - 1, transitions[(int)loc.Z][val].NextState.Value);
206                                    break;
207                                case CompassSelector.Direction.SOUTH:
208                                    loc = new Vector3(loc.X, loc.Y + 1, transitions[(int)loc.Z][val].NextState.Value);
209                                    break;
210                                case CompassSelector.Direction.EAST:
211                                    loc = new Vector3(loc.X + 1, loc.Y, transitions[(int)loc.Z][val].NextState.Value);
212                                    break;
213                                case CompassSelector.Direction.WEST:
214                                    loc = new Vector3(loc.X - 1, loc.Y, transitions[(int)loc.Z][val].NextState.Value);
215                                    break;
216                            }
217                            break;
218                    }
219                    if (Path.Contains(loc))
220                    {
221                        Path.Add(loc);
222                        return false;
223                    }
224                }
225            }
226        }
227        /// <summary>
228        /// Draws the puzzle on the screen
229        /// </summary>
230        /// <param name="screen">The screen to be drawn to.</param>
231        public override void Draw(Screen2D screen)
232        {
233            // Draws the interesting information.
234            for (int i = 0; i < states; ++i)
235                screen.DrawText(String.Format("State {0}", i), new Vector2(225 + 250 * i, 50), TextHorizontal.CENTERED, TextVertical.TOP, Color.White);
236            // Draws the board.
237            screen.FillRectangle(new Rectangle(100, 300, 25 * (width + 2), 25 * (height + 2)), Color.Black);
238            for (int i = 0; i < board.Length; ++i)
239            {
240                for (int j = 0; j < board[i].Length; ++j)
241                {
242                    Color square = Color.Black;
243                    switch (board[i][j])
244                    {
245                        case '0':
246                            square = colors[0];
247                            break;
248                        case '1':
249                            square = colors[1];
250                            break;
251                        case '2':
252                            square = colors[2];
253                            break;
254                        case '!':
255                            square = Color.White;
256                            break;
257                        default:
258                            square = Color.Black;
259                            break;
260                    }
261                    screen.FillRectangle(new Rectangle(125 + 25 * j, 325 + 25 * i, 25, 25), square);
262                }
263            }
264            screen.DrawText("0", new Vector2(137.5f + 25 * start.X, 337.5f + 25 * start.Y), TextHorizontal.CENTERED, TextVertical.CENTERED, Color.Gray);
265            if (percentAcross != 0)
266            {
267                Vector2 loc = new Vector2(137.5f + 25 * (percentAcross * Path[currentEdge+1].X + Path[currentEdge].X * (DELAY - percentAcross)) / DELAY,
268                                337.5f + 25 * (percentAcross * Path[currentEdge+1].Y + Path[currentEdge].Y * (DELAY - percentAcross)) / DELAY);
269                screen.DrawText(Path[currentEdge].Z.ToString(), loc, TextHorizontal.CENTERED, TextVertical.CENTERED, Color.White);
270            }
271            else
272            {
273                screen.DrawText(Path[currentEdge].Z.ToString(),
274                        new Vector2(137.5f + 25 * Path[currentEdge].X, 337.5f + 25 * Path[currentEdge].Y),
275                        TextHorizontal.CENTERED, TextVertical.CENTERED, Color.White);
276            }
277            base.Draw(screen);
278        }
279    }
280}
Note: See TracBrowser for help on using the browser.