void Update() { engineOutputRPMText.text = "Engine RPM: " + EngineHelpers.SpeedToRPM(engine.EngineSpeed).ToString("0"); transmissionInputRPMText.text = "In RPM: " + EngineHelpers.SpeedToRPM(engine.TransmissionInputSpeed).ToString("0"); transmissionOutputRPMText.text = "Out RPM: " + EngineHelpers.SpeedToRPM(engine.GetTransmissionOutputSpeed()).ToString("0"); torqueText.text = "Torque: " + engine.EngineTorque; clutchText.text = "Clutch: " + engine.ClutchAmount; gearText.text = "" + (engine.CurrentGear + 1); Vector3 p = engineOutputVisual.transform.localPosition; p.z = Mathf.Lerp(engineOutputClutchMinZ, engineOutputClutchMaxZ, engine.ClutchAmount); engineOutputVisual.transform.localPosition = p; UpdateEngineOutputVisuals(); UpdateTransmissionInputVisuals(); UpdateTransmissionOutputVisuals(); slipWarningIcon.SetActive(engine.ClutchAmount > 0f && !engine.ClutchLocked); lockIcon.SetActive(engine.ClutchLocked); }
public void GetNumericOptionType(string option, string key, double?expected) { var actualVal = EngineHelpers.GetNumericOptionType(option, key); Assert.AreEqual(expected, actualVal); }
public void GetStringDefault(string option, string expected) { var actual = EngineHelpers.GetStringDefault(option); Assert.AreEqual(expected, actual); }
public void GetNumericDefault(string option, double?expected) { var actual = EngineHelpers.GetNumericDefault(option); Assert.AreEqual(expected, actual); }
public void GetType(string options, OptionType expectedType) { var actualType = EngineHelpers.GetOptionType(options); Assert.AreEqual(expectedType, actualType); }
/// <summary> /// Inverts the Y axis and moves to index base A and 1 instead of 0,0. /// </summary> /// <param name="p"></param> /// <returns></returns> private string DecodePosition(Point p) { return(EngineHelpers.DecodePosition((int)p.X, (int)p.Y, BoardEdgeSize)); }
/// <summary> /// Adds rows and columns to the grid based on the BoardEdgeSize property, /// and then populates the grid with GamePiece instances. /// </summary> private void CreateBoard() { //return; var edgesize = BoardEdgeSize; if (edgesize == 0 || _gameBorder == null || _gridContainer == null) { return; } _pieces = new Dictionary <string, GamePiece>(); for (int i = _gridContainer.Children.Count - 1; i >= 0; i--) { var e = _gridContainer.Children[i]; if (!(e is Grid || e is Border)) { _gridContainer.Children.Remove(e); } } //_gridContainer.Children.Clear(); _gridContainer.ColumnDefinitions.Clear(); _gridContainer.RowDefinitions.Clear(); // Add left and top column and row. _gridContainer.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) }); _gridContainer.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) }); // Add columns and rows for pieces. for (int i = 0; i < edgesize * 2; i++) { _gridContainer.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); _gridContainer.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); } // Add right and bottom column and row. _gridContainer.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) }); _gridContainer.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) }); // Put grids in the right place. Grid.SetColumnSpan(_gameBorder, edgesize * 2); Grid.SetRowSpan(_gameBorder, edgesize * 2); Grid.SetColumnSpan(_messageDisplay, edgesize * 2); Grid.SetRowSpan(_messageDisplay, edgesize * 2); double lineThickness = edgesize == 9 ? 2.2 : (edgesize == 13 ? 1.8 : 1.5); // Add row labels and lines. for (int row = 0; row < edgesize; row++) { // Create row labels. if (ShowHeaders) { var tb = CreateTextBlock((edgesize - row).ToString()); tb.HorizontalAlignment = HorizontalAlignment.Right; tb.VerticalAlignment = VerticalAlignment.Center; tb.SetValue(Grid.RowSpanProperty, 2); tb.SetValue(Grid.RowProperty, (row * 2) + 1); _gridContainer.Children.Add(tb); tb = CreateTextBlock((edgesize - row).ToString()); tb.HorizontalAlignment = HorizontalAlignment.Left; tb.VerticalAlignment = VerticalAlignment.Center; tb.SetValue(Grid.ColumnProperty, (edgesize * 2) + 1); tb.SetValue(Grid.RowSpanProperty, 2); tb.SetValue(Grid.RowProperty, (row * 2) + 1); _gridContainer.Children.Add(tb); } // Create horizontal line. var line = new Line { StrokeThickness = lineThickness - .5, Stroke = LineBrush, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Center, X1 = -5, X2 = short.MaxValue, }; line.SetValue(Grid.ColumnProperty, 2); line.SetValue(Grid.ColumnSpanProperty, (edgesize * 2) - 2); line.SetValue(Grid.RowProperty, (row * 2) + 1); line.SetValue(Grid.RowSpanProperty, 2); _gridContainer.Children.Add(line); } // Add dots switch (edgesize) { case 9: AddDot(2, 2); AddDot(6, 2); AddDot(4, 4); AddDot(2, 6); AddDot(6, 6); break; case 13: AddDot(3, 3); AddDot(6, 3); AddDot(9, 3); AddDot(3, 6); AddDot(6, 6); AddDot(9, 6); AddDot(3, 9); AddDot(6, 9); AddDot(9, 9); break; case 19: AddDot(3, 3); AddDot(9, 3); AddDot(15, 3); AddDot(3, 9); AddDot(9, 9); AddDot(15, 9); AddDot(3, 15); AddDot(9, 15); AddDot(15, 15); break; } // Add column labels and lines. for (int col = 0; col < edgesize; col++) { // Create column labels. if (ShowHeaders) { var letter = EngineHelpers.GetColumnLetter(col); var tb = CreateTextBlock(letter); tb.HorizontalAlignment = HorizontalAlignment.Center; tb.SetValue(Grid.ColumnSpanProperty, 2); tb.SetValue(Grid.ColumnProperty, (col * 2) + 1); _gridContainer.Children.Add(tb); tb = CreateTextBlock(letter); tb.HorizontalAlignment = HorizontalAlignment.Center; tb.SetValue(Grid.RowProperty, (edgesize * 2) + 1); tb.SetValue(Grid.ColumnSpanProperty, 2); tb.SetValue(Grid.ColumnProperty, (col * 2) + 1); _gridContainer.Children.Add(tb); } // Create vertical line. var line = new Line { StrokeThickness = lineThickness, Stroke = LineBrush, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, Y1 = -5, Y2 = short.MaxValue, }; line.SetValue(Grid.RowProperty, 2); line.SetValue(Grid.RowSpanProperty, (edgesize * 2) - 2); line.SetValue(Grid.ColumnProperty, (col * 2) + 1); line.SetValue(Grid.ColumnSpanProperty, 2); _gridContainer.Children.Add(line); } // Smaller boards allow more space between pieces. _circleMargin = edgesize == 9 ? 6 : (edgesize == 13 ? 4 : 3); for (int row = 0; row < edgesize; row++) { for (int column = 0; column < edgesize; column++) { // Create piece (every other row/column) and set its column, row, colspan, and rowspan. var gamePiece = new GamePiece(EngineHelpers.DecodePosition(column, row, edgesize), _circleMargin, null, GoColor.Black, false, false, false); gamePiece.SetValue(Grid.ColumnProperty, (column * 2) + 1); gamePiece.SetValue(Grid.ColumnSpanProperty, 2); gamePiece.SetValue(Grid.RowProperty, (row * 2) + 1); gamePiece.SetValue(Grid.RowSpanProperty, 2); gamePiece.Click += GamePieceOnClick; _pieces[DecodePosition(new Point(column, row))] = gamePiece; _gridContainer.Children.Add(gamePiece); } } //_gameBorder.Visibility = Visibility.Visible; AttemptLinkToPieces(); }
protected static async Task DisplayErrorCode(GoResultCode code) { var msg = EngineHelpers.GetResultCodeFriendlyMessage(code); await DisplayMessage("Whoops", msg); }
private void ContinueGameFromState(GoGameState state) { // Player1 is always black, Player2 is always white. Player1 = new PlayerViewModel(state.Player1, GoColor.Black); Player2 = new PlayerViewModel(state.Player2, GoColor.White); _players = new[] { Player1, Player2 }; WhoseTurn = state.WhoseTurn == GoColor.Black ? 0 : 1; OnPropertyChanged(nameof(WhoseTurn)); CurrentTurnColor = _players[_whoseTurn].Color; SetState(state.Status, state.WinMargin); // Note that setting BoardEdgeSize triggers the board control to generate. BoardEdgeSize = state.Size; // Build a temporary dictionary with ALL the piece states in it, all set to // contain an empty PieceState initially. var tmpPieces = new Dictionary <string, PieceStateViewModel>(); for (int x = 0; x < state.Size; x++) { for (int y = 0; y < state.Size; y++) { var position = EngineHelpers.DecodePosition(x, y, state.Size); tmpPieces.Add(position, new PieceStateViewModel(position, null, null, false, false, false)); } } // This actually updates the UI. Note that we can't add anything to Pieces after // this point because Pieces is a Dictionary, which can't be observed by the GameBoard // control. From here forward, we simply update individual pieces inside Pieces; we // don't add or remove from it. Pieces = tmpPieces; int blackPrisoners = 0; int whitePrisoners = 0; // Save history. History = new ObservableCollection <GoMoveHistoryItem>(); foreach (var h in state.GoMoveHistory) { History.Insert(0, h); if (h.Move.Color == GoColor.Black) { blackPrisoners += h.Result.CapturedStones.Split(' ').Count(x => x != String.Empty); } else { whitePrisoners += h.Result.CapturedStones.Split(' ').Count(x => x != String.Empty); } } Player1.Prisoners = Player1.Color == GoColor.Black ? blackPrisoners : whitePrisoners; Player2.Prisoners = Player2.Color == GoColor.Black ? blackPrisoners : whitePrisoners; // Set piece states for all the existing white and black pieces. SetPieces(state.BlackPositions, GoColor.Black); SetPieces(state.WhitePositions, GoColor.White); var latestNormalPiece = GetLatestNormalMovePieceFromHistory(); if (latestNormalPiece != null) { latestNormalPiece.IsNewPiece = true; } // Correct Sequence value. //FixSequenceValuesForColor(state, GoColor.Black); //FixSequenceValuesForColor(state, GoColor.White); RaiseAllPiecesChanged(); RaiseCommandsChanged(); }
private GoAreaResponse CalculateAreaValues(string dead) { var rval = new GoAreaResponse(GoResultCode.Success); // Split into arrays, and work out dead/undead white and black subsets. var deads = dead.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var blacks = _state.BlackPositions.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); rval.BlackDead = deads.Where(d => blacks.Any(b => b == d)).ToList(); var nonDeadBlacks = blacks.Where(b => deads.All(p => p != b)).Select(p => p.EncodePosition(_state.Size)).ToArray(); var whites = _state.WhitePositions.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); rval.WhiteDead = deads.Where(d => whites.Any(w => w == d)).ToList(); var nonDeadWhites = whites.Where(w => deads.All(p => p != w)).Select(p => p.EncodePosition(_state.Size)).ToArray(); // Build game grid based on _state.BlackPositions and _state.WhitePositions, // excluding any dead stones. var grid = new GoColor?[_state.Size, _state.Size]; foreach (var p in nonDeadWhites) { grid[p.X, p.Y] = GoColor.White; } foreach (var p in nonDeadBlacks) { grid[p.X, p.Y] = GoColor.Black; } // For each held position, determine the number of neighboring liberties // that are empty and don't eventually touch a different color. rval.BlackArea = GetContiguousAreaForHeldPoints(GoColor.Black, nonDeadBlacks); rval.WhiteArea = GetContiguousAreaForHeldPoints(GoColor.White, nonDeadWhites); // Local functions are cool. List <string> GetContiguousAreaForHeldPoints(GoColor color, Point[] heldPoints) { var result = new List <string>(_state.Size ^ 2); foreach (var held in heldPoints) { foreach (var p in GetNeighborPositions(held)) { // If is a liberty (no color), traverse it. if (grid[p.X, p.Y] == null) { Debug.Assert(grid[held.X, held.Y].HasValue, "grid[held.X, held.Y].HasValue"); var liberties = new List <Point>(_state.Size ^ 2); if (!AllNeighborsAreLibertiesOrColor(p, color, liberties)) { continue; } foreach (var l in liberties) { var s = EngineHelpers.DecodePosition(l.X, l.Y, _state.Size); if (!result.Contains(s)) { result.Add(s); } } } } // Add held point (which is alive) because we want // area not just territory. var heldDecoded = EngineHelpers.DecodePosition(held.X, held.Y, _state.Size); if (!result.Contains(heldDecoded)) { result.Add(heldDecoded); } } return(result); } // Local functions are cool. bool AllNeighborsAreLibertiesOrColor(Point point, GoColor color, List <Point> visited) { visited.Add(point); // Traverse through not already visited neighbors. foreach (var neighbor in GetNeighborPositions(point)) { if (visited.Contains(neighbor)) { continue; } var neighborColor = grid[neighbor.X, neighbor.Y]; // If neighbors is a liberty (no color), traverse it. if (neighborColor == null) { // Self-recursive call. if (!AllNeighborsAreLibertiesOrColor(neighbor, color, visited)) { // A neighbor was opposite color, abort up the chain. return(false); } } else if (neighborColor == OppositeColor(color)) { // Neighbor is opposite color, abort all the way up the chain. return(false); } // Neighbor is same color, this is a boundary, don't traverse it // but continue to next neighbor. } return(true); } // Local functions are cool. // Iterates over the neighbors. Using yield // allows caller to abort without iterating // all neighboring points. References // _state.Size to determine edges of the board. IEnumerable <Point> GetNeighborPositions(Point p) { // has a left if (p.X > 0) { yield return(new Point(p.X - 1, p.Y)); } // has a right if (p.X < _state.Size - 1) { yield return(new Point(p.X + 1, p.Y)); } // has an upper if (p.Y > 0) { yield return(new Point(p.X, p.Y - 1)); } // has a lower if (p.Y < _state.Size - 1) { yield return(new Point(p.X, p.Y + 1)); } } return(rval); }