/ppcp/units/unit2/src/AntisocialRobots/MainWindow.xaml.cs
C# | 299 lines | 208 code | 34 blank | 57 comment | 52 complexity | 70b2c38bc0b88ba03f4f59cb754039fd MD5 | raw file
- //--------------------------------------------------------------------------
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // File: MainWindow.xaml.cs
- //
- //--------------------------------------------------------------------------
-
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Shapes;
- using System.Windows.Threading;
-
- namespace AntisocialRobots
- {
- /// <summary>Interaction logic for MainWindow.xaml</summary>
- public partial class MainWindow : Window
- {
- int ROOM_SIZE = 200;
- int NEW_ROOM_SIZE = 0;
- RobotSimulation _robotSim;
- List<Ellipse> _robotVis;
-
- /// <summary>
- /// The color of the next robot to be created. To cycle the colors, we use this
- /// algorithm: one of R, G, and B is zero; the other two cycle from 240 down to 10 and 10
- /// up to 240.
- /// </summary>
- Color _nextColor = Color.FromRgb(240, 10, 0);
-
- /// <summary>
- /// Calculates frames per second, by measuring the time required to display FramesPerSample
- /// frames.
- /// </summary>
- Stopwatch _framesPerSecondStopwatch = new Stopwatch();
-
- /// <summary>The number of frames included in one frames per second measurement.</summary>
- const int FramesPerSample = 10;
-
- /// <summary>Initializes an instance of this class.</summary>
- public MainWindow()
- {
- InitializeComponent();
-
- // Initializes robot state
- Action clearState = () => {
- if (NEW_ROOM_SIZE != 0)
- {
- ROOM_SIZE = NEW_ROOM_SIZE;
- NEW_ROOM_SIZE = 0;
- }
- _robotSim = new RobotSimulation(ROOM_SIZE);
- _robotVis = new List<Ellipse>();
- Room.Children.Clear();
- };
- clearState();
-
- // When F5 is pressed, reset state
- KeyDown += (_, e) => { if (e.Key == Key.F5) clearState(); };
- // or when button pressed
- RestartButton.Click += (_, e) => { clearState(); };
-
- // Render loop, started when the window loads
- Action recomputeAndRedraw = null;
- recomputeAndRedraw = delegate {
- Dispatcher.BeginInvoke((Action)delegate {
- // handle the case where the user changed the room size
- // but there are no robots in the room
- if (_robotSim.Robots.Count == 0 &&
- NEW_ROOM_SIZE != 0 &&
- NEW_ROOM_SIZE != ROOM_SIZE)
- clearState();
- if (!_robotSim.FoundBug)
- {
- PerformSimulationStep();
- }
- recomputeAndRedraw();
- }, DispatcherPriority.Background);
- };
- Loaded += delegate {
- _framesPerSecondStopwatch.Start();
- recomputeAndRedraw();
- };
-
- comboBox1.SelectedItem = room200;
- }
-
- /// <summary>
- /// Called when the size of the RoomParent (the control containing the canvas that
- /// displays the robots) changes.
- /// </summary>
- private void RoomParent_SizeChanged(object sender, SizeChangedEventArgs e)
- {
- // Set size to the width/height of the largest square that fits within
- // RoomParent (the control containing the canvas that holds robots)
- double size = Math.Min(RoomParent.ActualWidth, RoomParent.ActualHeight);
-
- // Room is set to be 1.0 units wide x 1.0 units high -- apply a scaling
- // transform so that it fills RoomParent
- RoomScaleTransform.ScaleX = size;
- RoomScaleTransform.ScaleY = size;
-
- // Center Room within the RoomParent
- double marginX = (RoomParent.ActualWidth - size) / 2;
- double marginY = (RoomParent.ActualHeight - size) / 2;
- Room.Margin = new Thickness(marginX, marginY, 0, 0);
- }
-
- /// <summary>Called when the user clicks on the canvas containing the robots.</summary>
- private void Room_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- if (!_robotSim.FoundBug)
- CreateRobot(MousePositionToRoomPoint(e));
- }
-
- /// <summary>
- /// Called when the users moves the mouse, or holds the mouse button, over the canvas
- /// containing the robots.
- /// </summary>
- private void Room_MouseMove(object sender, MouseEventArgs e)
- {
- if (!_robotSim.FoundBug && e.MouseDevice.LeftButton == MouseButtonState.Pressed)
- CreateRobot(MousePositionToRoomPoint(e));
- }
-
- /// <summary>Creates a robot, which is placed at a given location with the room.</summary>
- /// <param name="pt">Where the robot should be placed, in RoomPoint coordinates.</param>
- void CreateRobot(RoomPoint pt)
- {
- Robot robot = _robotSim.CreateRobot(pt);
- if (robot == null)
- return;
-
- var ellipse =
- new Ellipse() {
- Width = 1.0 / ROOM_SIZE,
- Height = 1.0 / ROOM_SIZE,
- HorizontalAlignment = HorizontalAlignment.Left,
- VerticalAlignment = VerticalAlignment.Top,
- Fill = new SolidColorBrush(_nextColor)
- };
-
- _robotVis.Add(ellipse);
- // Add the robot to Room
- Room.Children.Add(ellipse);
-
- // Set the position of the robot within Room
- SetRobotElementPosition(ellipse, pt);
-
- // Advance _nextColor to the next color to use
- MoveNextColor();
- }
-
- /// <summary>Advances to the next color in the rotation.</summary>
- private void MoveNextColor()
- {
- if (_nextColor.B == 0)
- {
- _nextColor.R = (byte)Math.Max((int)_nextColor.R - 10, 0);
- _nextColor.G = (byte)Math.Max((int)_nextColor.G + 10, 0);
- if (_nextColor.R == 0)
- {
- _nextColor.G = 240;
- _nextColor.B = 10;
- }
- }
- else if (_nextColor.G > 0)
- {
- _nextColor.G = (byte)Math.Max((int)_nextColor.G - 10, 0);
- _nextColor.B = (byte)Math.Max((int)_nextColor.B + 10, 0);
- if (_nextColor.G == 0)
- {
- _nextColor.B = 240;
- _nextColor.R = 10;
- }
- }
- else
- {
- _nextColor.B = (byte)Math.Max((int)_nextColor.B - 10, 0);
- _nextColor.R = (byte)Math.Max((int)_nextColor.R + 10, 0);
- if (_nextColor.B == 0)
- {
- _nextColor.R = 240;
- _nextColor.G = 10;
- }
- }
- }
-
- /// <summary>Sets the position of the Robot.Element for a given robot to a given point.</summary>
- /// <param name="robot">The robot.</param>
- /// <param name="pt">The location in RoomPoint coordinates.</param>
- void SetRobotElementPosition(Ellipse e, RoomPoint pt)
- {
- Canvas.SetLeft(e, ((double)pt.X) / ROOM_SIZE);
- Canvas.SetTop(e, ((double)pt.Y) / ROOM_SIZE);
- }
-
- /// <summary>Converts a mouse position to a RoomPoint.</summary>
- /// <param name="e">The event arguments containing the mouse position.</param>
- RoomPoint MousePositionToRoomPoint(MouseEventArgs e)
- {
- Point pt = e.GetPosition(Room);
- var rmPt = new RoomPoint((int)(pt.X * ROOM_SIZE), (int)(pt.Y * ROOM_SIZE));
-
- // If pt.x/y == 1.0f, than we'll get an invalid RoomPoint
- if (rmPt.X == ROOM_SIZE) rmPt.X--;
- if (rmPt.Y == ROOM_SIZE) rmPt.Y--;
-
- return rmPt;
- }
-
- /// <summary>Performs one step of the simulation.</summary>
- void PerformSimulationStep()
- {
- // Calculate a new position for each robot, update _roomCells and each
- // Robot.Location with that information
- if (naiveparallel.IsChecked.Value)
- {
- if (chkLock.IsChecked.Value)
- _robotSim.UpdateMode = RobotSimulation.FrameUpdateMode.Parallel_WithFineGrainedLocks1;
- else
- _robotSim.UpdateMode = RobotSimulation.FrameUpdateMode.ParallelNoLocks;
- }
- else if (stripedparallel.IsChecked.Value)
- {
- _robotSim.UpdateMode = RobotSimulation.FrameUpdateMode.StrippedParallel;
- }
- else
- { // sequential
- _robotSim.UpdateMode = RobotSimulation.FrameUpdateMode.Sequential;
- }
- _robotSim.PerformFrameUpdate();
-
- #region BugDiagnosis
- if (chkCompare.IsChecked.Value && !_robotSim.FoundBug && _robotSim.CheckInvariant())
- {
- var r1 = _robotSim.Robot1;
- var r2 = _robotSim.Robot2;
- var conflictLocation = _robotSim.ConflictLocation;
-
- // show an error
- MessageBox.Show(
- "robot " + r1.Id + "'s location is (" + r1.Location.X + "," + r1.Location.Y + ") but robot " +
- r2.Id + " occupies that location. Click OK to see the conflicting robots in the previous frame."
- );
-
- var conflictCell = new Rectangle() {
- Width = 1.0 / ROOM_SIZE,
- Height = 1.0 / ROOM_SIZE,
- Fill = new LinearGradientBrush(
- Colors.Red, Colors.Gray, new Point(0, 0), new Point(1, 1))
- };
-
- Room.Children.Add(conflictCell);
- Canvas.SetLeft(conflictCell, ((double)conflictLocation.X) / ROOM_SIZE);
- Canvas.SetTop(conflictCell, ((double)conflictLocation.Y) / ROOM_SIZE);
- _robotSim.RestoreRoom();
- }
- #endregion
-
- // update the on-screen position of all robots
- var ellipses = _robotVis.GetEnumerator();
- foreach (Robot robot in _robotSim.Robots)
- {
- ellipses.MoveNext();
- SetRobotElementPosition(ellipses.Current, robot.Location);
- }
-
- // Update statistics
- if ((_robotSim.FrameIdx % FramesPerSample) == 0)
- {
- double fps = (1000 / (double)_framesPerSecondStopwatch.ElapsedMilliseconds) * FramesPerSample;
- txtStatus.Text = String.Format("{0} robots, {1:n1} fps", _robotSim.Robots.Count, fps);
- _framesPerSecondStopwatch.Restart();
- }
- }
-
- private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (comboBox1.SelectedItem == room10)
- NEW_ROOM_SIZE = 10;
- else if (comboBox1.SelectedItem == room20)
- NEW_ROOM_SIZE = 20;
- else if (comboBox1.SelectedItem == room50)
- NEW_ROOM_SIZE = 50;
- else if (comboBox1.SelectedItem == room100)
- NEW_ROOM_SIZE = 100;
- else if (comboBox1.SelectedItem == room200)
- NEW_ROOM_SIZE = 200;
- }
-
- }
- }