I am currently developing a program that is using tab same like Google Chrome Tabs,
The tab is working fine, no problem.
But I come into a condition that I can drag the tab even out of monitor screen (left and right edge).
The Question is, how can I restrict the tab dragged into the edge of the screen??
So the tab will not go pass through the screen. Basically it is only about aesthetic purpose..
Be reminded that I have made research from the google and this website but still can't figure it out how to do it..
Here is a piece of the codes.
private bool draggingWindow;
private Size finalSize;
private double overlap;
private double leftMargin;
private double rightMargin;
private double maxTabWidth;
private double minTabWidth;
private double defaultMeasureHeight;
private double currentTabWidth;
private int captureGuard;
private int originalIndex;
private int slideIndex;
private List<double> slideIntervals;
private ChromeTabItem draggedTab;
private Point downPoint;
private ChromeTabControl parent;
public Rect addButtonRect;
private Size addButtonSize;
public Button addButton;
private bool modifyLeftOffset, modifyTopOffset;
private Point origCursorLocation;
private double origHorizOffset, origVertOffset;
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
try
{
base.OnPreviewMouseMove(e);
if (this.addButtonRect.Contains(e.GetPosition(this)) && this.addButton.Background != Brushes.White && this.addButton.Background != Brushes.DarkGray)
{
this.addButton.Background = Brushes.White;
this.InvalidateVisual();
}
else if (!this.addButtonRect.Contains(e.GetPosition(this)) && this.addButton.Background != null)
{
this.addButton.Background = null;
this.InvalidateVisual();
}
if (this.draggedTab == null || this.draggingWindow) { return; }
Point nowPoint = e.GetPosition(this);
this.addButton.Visibility = Visibility.Hidden;
double newHorizontalOffset;
if (this.modifyLeftOffset)
newHorizontalOffset = this.origHorizOffset + (nowPoint.X - this.origCursorLocation.X);
else
newHorizontalOffset = this.origHorizOffset - (nowPoint.X - this.origCursorLocation.X);
Thickness margin = new Thickness(nowPoint.X - this.downPoint.X, 0, this.downPoint.X - nowPoint.X, 0);
this.draggedTab.Margin = margin;
Rect elemRect = this.CalculateDragElementRect(newHorizontalOffset, 1);
bool leftAlign = elemRect.Left < 0;
bool rightAlign = elemRect.Right > this.ActualWidth;
if (leftAlign)
newHorizontalOffset = modifyLeftOffset ? 0 : this.ActualWidth - elemRect.Width;
else if (rightAlign)
newHorizontalOffset = modifyLeftOffset ? this.ActualWidth - elemRect.Width : 0;
if (this.modifyLeftOffset)
Canvas.SetLeft(this.draggedTab, newHorizontalOffset);
else
Canvas.SetRight(this.draggedTab, newHorizontalOffset);
base.OnPreviewMouseMove( e );
if (margin.Left != 0)
{
int guardValue = Interlocked.Increment(ref this.captureGuard);
if (guardValue == 1)
{
this.originalIndex = this.draggedTab.Index;
this.slideIndex = this.originalIndex + 1;
this.slideIntervals = new List<double>();
this.slideIntervals.Add(double.NegativeInfinity);
for (int i = 1; i <= this.Children.Count; i += 1)
{
var diff = i - this.slideIndex;
var sign = diff == 0 ? 0 : diff / Math.Abs(diff);
var bound = Math.Min(1, Math.Abs(diff)) * ((sign * this.currentTabWidth / 3) + ((Math.Abs(diff) < 2) ? 0 : (diff - sign) * (this.currentTabWidth - this.overlap)));
this.slideIntervals.Add(bound);
}
this.slideIntervals.Add(double.PositiveInfinity);
this.CaptureMouse();
}
else
{
int changed = 0;
if (this.slideIntervals != null)
{
if (margin.Left < this.slideIntervals[this.slideIndex - 1])
{
SwapSlideInterval(this.slideIndex - 1);
this.slideIndex -= 1;
changed = 1;
}
else if (margin.Left > this.slideIntervals[this.slideIndex + 1])
{
SwapSlideInterval(this.slideIndex + 1);
this.slideIndex += 1;
changed = -1;
}
}
if (changed != 0)
{
var rightedOriginalIndex = this.originalIndex + 1;
var diff = 1;
if (changed > 0 && this.slideIndex >= rightedOriginalIndex)
{
changed = 0;
diff = 0;
}
else if (changed < 0 && this.slideIndex <= rightedOriginalIndex)
{
changed = 0;
diff = 2;
}
ChromeTabItem shiftedTab = this.Children[this.slideIndex - diff] as ChromeTabItem;
if (shiftedTab != this.draggedTab)
{
StickyReanimate(shiftedTab, changed * (this.currentTabWidth - this.overlap), .13);
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Any response and attention is really appreciated..
Thank you
Related
the problem i'm facing right now is that i don't know how to check on the opponent's move which ships it sinks so i can display a message saying "Your ____ has sunk".
this is the code i have written
namespace Naval
{
public partial class Form2 : Form
{
const int Size_grid = 10;
const int picturebox = 50;
PictureBox[,] playerBoard = new PictureBox[Size_grid, Size_grid];
PictureBox[,] opponentBoard = new PictureBox[Size_grid, Size_grid];
int[,] playerShips = new int[Size_grid, Size_grid];
int[,] opponentShips = new int[Size_grid, Size_grid];
int[] Lengths = new int[] { 5, 4, 3, 2 };
//string[] Names = new string[] { "Αεροπλανοφόρο", "Αντιτορπιλικό", "Πολεμικό", "Υποβρύχιο" };
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox playerPictureBox = new PictureBox();
playerPictureBox.Size = new Size(picturebox, picturebox);
playerPictureBox.Location = new Point(col * (picturebox + 10) + 185, row * (picturebox + 10) + 245);
playerPictureBox.Click += PictureBox_Click;
playerPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
playerPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(playerPictureBox);
playerBoard[row, col] = playerPictureBox;
}
}
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox opponentPictureBox = new PictureBox();
opponentPictureBox.Size = new Size(picturebox, picturebox);
opponentPictureBox.Location = new Point(col * (picturebox + 10) + 1145, row * (picturebox + 10) + 245);
opponentPictureBox.Click += PictureBox_Click;
opponentPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
opponentPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(opponentPictureBox);
opponentBoard[row, col] = opponentPictureBox;
}
}
PlacePlayerShips(playerShips, Lengths);
PlaceOpponentShips(opponentShips, Lengths);
}
private void PictureBox_Click(object sender, EventArgs e)
{
PictureBox pictureBox = (PictureBox)sender;
int row = (pictureBox.Location.Y - 245) / (picturebox + 10);
int col = (pictureBox.Location.X - 1145) / (picturebox + 10);
if (pictureBox.Location.X >= 1145 && pictureBox.ImageLocation == null) // opponent board
{
if (row >= 0 && row < opponentShips.GetLength(0) && col >= 0 && col < opponentShips.GetLength(1))
{
if (opponentShips[row, col] > 0)
{
pictureBox.ImageLocation = "x.png";
}
else
{
pictureBox.ImageLocation = "-.png";
}
ComputerMove();
}
}
}
private void ComputerMove()
{
Random random = new Random();
int row = random.Next(Size_grid);
int col = random.Next(Size_grid);
while (playerBoard[row, col].ImageLocation != null)
{
row = random.Next(Size_grid);
col = random.Next(Size_grid);
}
if (playerShips[row, col] > 0)
{
playerBoard[row, col].ImageLocation = "x.png";
}
else
{
playerBoard[row, col].ImageLocation = "-.png";
}
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
private void PlacePlayerShips(int[,] playerShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row, col + i] = 1;
playerBoard[row, col + i].BackColor = Color.LightBlue;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row + i, col] = 1;
playerBoard[row + i, col].BackColor = Color.LightBlue;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void PlaceOpponentShips(int[,] opponentShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
;
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row, col + i] = 1;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row + i, col] = 1;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void label1_Click(object sender, EventArgs e)
{
}
int time = 0;
private void timer1_Tick(object sender, EventArgs e)
{
time++;
label42.Text= time.ToString();
}
private void timer2_Tick(object sender, EventArgs e)
{
label44.Text = " ";
timer2.Enabled = false;
}
}
}
i tried adding a switch with choices 1-4 but it didn't work i've also tried having a int[] ship Hits = new int[] {0,0,0,0} and just adding 1 every time a ship was hit but that didn't go as planned because i didn't know how to bind each item of the array to a ship . and i think that's about it
One approach that you might find helpful would be to bundle up all the information about a Ship into a class. This is an abstraction that could make it easier for displaying ship names when they are sunk. At the same time, use inheritance so that a Ship is still a PictureBox with all the functionality that implies.
Ship minimal class example
Member properties tell us what we need know about a ship. Use enum values to make the intent perfectly clear.
class Ship : PictureBox
{
#region P R O P E R T I E S
[Description("Type")]
public τύπος τύπος
{
get => _τύπος;
set
{
if (!Equals(_τύπος, value))
{
_τύπος = value;
switch (_τύπος)
{
case τύπος.Αεροπλανοφόρο: Image = Image.FromFile(Path.Combine(_imageDir, "aircraft-carrier.png")); break;
case τύπος.Αντιτορπιλικό: Image = Image.FromFile(Path.Combine(_imageDir, "destroyer.png")); break;
case τύπος.Πολεμικό: Image = Image.FromFile(Path.Combine(_imageDir, "military.png")); break;
case τύπος.Υποβρύχιο: Image = Image.FromFile(Path.Combine(_imageDir, "submarine.png")); break;
}
}
}
}
τύπος _τύπος = 0;
public bool Sunk { get; set; }
[Description("Flag")]
public σημαία σημαία
{
get => _σημαία;
set
{
_σημαία = value;
onUpdateColor();
}
}
σημαία _σημαία = σημαία.Player;
#endregion P R O P E R T I E S
private void onUpdateColor()
{
var color =
Sunk ? Color.Red :
σημαία.Equals(σημαία.Player) ?
Color.Navy :
Color.DarkOliveGreen;
for (int x = 0; x < Image.Width; x++) for (int y = 0; y < Image.Height; y++)
{
Bitmap bitmap = (Bitmap)Image;
if (bitmap.GetPixel(x, y).R < 0x80)
{
bitmap.SetPixel(x, y, color);
}
}
Refresh();
}
public Point[] Hits { get; set; } = new Point[0];
public override string ToString() =>
$"{σημαία} {τύπος} # {((TableLayoutPanel)Parent)?.GetCellPosition(this)}";
private readonly static string _imageDir =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
}
Where enum values are:
enum Direction
{
Horizontal,
Vertical,
}
enum τύπος
{
[Description("Aircraft Carrier")]
Αεροπλανοφόρο = 5,
[Description("Destroyer")]
Αντιτορπιλικό = 4,
[Description("Military")]
Πολεμικό = 3,
[Description("Submarine")]
Υποβρύχιο = 2,
}
/// <summary>
/// Flag
/// </summary>
enum σημαία
{
Player,
Opponent,
}
Displaying ships names when they are sunk
When the inherited Ship version of PictureBox is clicked the information is now available.
private void onAnyShipClick(object sender, EventArgs e)
{
if (sender is Ship ship)
{
MessageBox.Show(ship.ToString());
}
}
Images credit: Robuart
Used under license.
I'm trying to give the letters in my richtextbox different colors for my subnet calculator, but the richtextbox doesn't change the colors until the 26th letter.
How it looks:
int iValueSm = trackBarSmMask.Value;
rtbScroll.Text = "";
rtbScroll.SelectionStart = rtbScroll.TextLength;
rtbScroll.SelectionLength = 0;
for (int i = 1; i <= iValueSm; i++)
{
rtbScroll.SelectionColor = Color.Blue;
rtbScroll.AppendText("N");
if (i%8==0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
for (int i = iValueSm+1; i <= 32; i++)
{
rtbScroll.SelectionColor = Color.Red;
rtbScroll.AppendText("H");
if (i % 8 == 0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
labelAmountNetID.Text = "/" + iValueSm.ToString();
Well, can be a lot of approaches to deal with this problem but here is one suggestion:
// Track bar definitions...
private void SetTrackBarVals()
{
trackBar1.Minimum = 0;
trackBar1.Maximum = 31;
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
var counter = 0;
var dotsCounter = 0;
rtbScroll.Text = "";
int iValueSm = trackBar1.Value + 1; // +1 because we start counting from 0
for (int i = 1; i <= 32; i++)
{
if (counter > 0 && counter % 8 == 0)
{
// new octet
rtbScroll.AppendText(".");
dotsCounter++;
}
if (i > iValueSm)
{
// It is red
rtbScroll.AppendText("H");
rtbScroll.SelectionStart = (i - 1) + dotsCounter;
rtbScroll.SelectionLength = 1 ;
rtbScroll.SelectionColor = Color.Red;
}
else
{
rtbScroll.AppendText("N");
}
counter++;
}
}
Anytime you set the .Text() property, you RESET all formatting back to black and white.
Here is how I'd write it using SelectedText:
private void Form1_Load(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_ValueChanged(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_Scroll(object sender, EventArgs e)
{
updateRTB();
}
private void updateRTB()
{
rtbScroll.Text = "";
rtbScroll.SelectionStart = 0;
rtbScroll.SelectionLength = 0;
int iValueSm = trackBarSmMask.Value;
labelAmountNetID.Text = "/" + iValueSm.ToString();
for (int i = 1; i <= 32; i++)
{
rtbScroll.SelectionColor = (i <= iValueSm) ? Color.Blue : Color.Red;
rtbScroll.SelectedText = (i <= iValueSm) ? "N" : "H";
if (i % 8 == 0 && i != 32)
{
rtbScroll.SelectionColor = Color.Black;
rtbScroll.SelectedText = ".";
}
}
}
The disadvantage of the code below is that it calculates the RSI for all prices at once. What if I have to add a new price? It's going to recalculate everything just because one additional price in the array. It will take longer than if I backup AverageGain/AverageLoss.
public class RSI
{
private readonly int _period;
public RSI(int period)
{
_period = period;
}
public decimal[] Calculate(decimal[] prices)
{
var rsi = new decimal[prices.Length];
decimal gain = 0m;
decimal loss = 0m;
rsi[0] = 0m;
for (int i = 1; i <= _period; ++i)
{
var diff = prices[i] - prices[i - 1];
if (diff >= 0)
{
gain += diff;
}
else
{
loss -= diff;
}
}
decimal avrg = gain / _period;
decimal avrl = loss / _period;
decimal rs = gain / loss;
rsi[_period] = 100m - (100m / (1m + rs));
for (int i = _period + 1; i < prices.Length; ++i)
{
var diff = prices[i] - prices[i - 1];
if (diff >= 0)
{
avrg = ((avrg * (_period - 1)) + diff) / _period;
avrl = (avrl * (_period - 1)) / _period;
}
else
{
avrl = ((avrl * (_period - 1)) - diff) / _period;
avrg = (avrg * (_period - 1)) / _period;
}
rs = avrg / avrl;
rsi[i] = 100m - (100m / (1m + rs));
}
return rsi;
}
}
My idea is to make something that remembers the previous input and calculate the RSI based on it, just like this one. Right now, this code is not working because _period is not involved at all. Those people in that github made it, but I'm still struggling to do it because of all these inherited classes/interfaces. I don't want to implement all of the interfaces/abstract classes. The one I extracted below are enough for me.
// Trying to achieve this:
var candles = _client.GetKlines(bot.Symbol, KlineInterval.OneHour).Data.ToList();
RelativeStrengthIndex rsi = new RelativeStrengthIndex(12);
for (int i = 0; i < candles.Count - 1; i++)
{
var result = rsi.ComputeNextValue(new InputData(candles[i].Close));
Console.WriteLine($"RSI(12) = {result}");
}
// New candle data
var newResult = rsi.ComputeNextValue(new InputData(0.01256m));
Console.WriteLine($"RSI(12) = {newResult}");
public abstract class Indicator
{
public abstract decimal ComputeNextValue(InputData input);
public abstract void Reset();
}
public class InputData
{
public decimal Value { get; private set; }
public InputData(decimal value)
{
Value = value;
}
}
public class RelativeStrengthIndex : Indicator
{
private int _period;
private InputData _previousInput;
public decimal AverageGain { get; private set; }
public decimal AverageLoss { get; private set; }
public RelativeStrengthIndex(int period)
{
_period = period;
}
public override decimal ComputeNextValue(InputData input)
{
if (_previousInput != null && input.Value >= _previousInput.Value)
{
AverageGain = input.Value - _previousInput.Value;
AverageLoss = 0m;
}
else if (_previousInput != null && input.Value < _previousInput.Value)
{
AverageGain = 0m;
AverageLoss = _previousInput.Value - input.Value;
}
_previousInput = input;
if (AverageLoss == 0m)
{
return 100m;
}
var rs = AverageGain / AverageLoss;
return 100m - (100m / (1 + rs));
}
public override void Reset()
{
_previousInput = default;
}
}
I did it myself. If you have any suggestions/improvements, please note them in the comments.
public class RelativeStrengthIndex : Indicator
{
private readonly int _period;
private InputData _previousInput;
private int _index;
private decimal _gain;
private decimal _loss;
private decimal _averageGain;
private decimal _averageLoss;
public RelativeStrengthIndex(int period)
{
_period = period;
_index = 0;
_gain = 0;
_loss = 0;
_averageGain = 0;
_averageLoss = 0;
}
public override decimal ComputeNextValue(InputData input)
{
// Formula: https://stackoverflow.com/questions/38481354/rsi-vs-wilders-rsi-calculation-problems?rq=1
_index++;
if (_previousInput != null)
{
var diff = input.Value - _previousInput.Value;
_previousInput = input;
if (_index <= _period)
{
if (diff >= 0)
{
_totalGain += diff;
}
else
{
_totalLoss -= diff;
}
}
if (_index < _period)
{
return 0;
}
else if (_index == _period)
{
_averageGain = _totalGain / _period;
_averageLoss = _totalLoss / _period;
decimal rs = _averageGain / _averageLoss;
return 100 - (100 / (1 + rs));
}
else // if (_index >= _period + 1)
{
if (diff >= 0)
{
_averageGain = ((_averageGain * (_period - 1)) + diff) / _period;
_averageLoss = (_averageLoss * (_period - 1)) / _period;
}
else
{
_averageGain = (_averageGain * (_period - 1)) / _period;
_averageLoss = ((_averageLoss * (_period - 1)) - diff) / _period;
}
decimal rs = _averageGain / _averageLoss;
return 100 - (100 / (1 + rs));
}
}
_previousInput = input;
return 0;
}
public override void Reset()
{
_previousInput = null;
_index = 0;
_gain = 0;
_loss = 0;
_averageGain = 0;
_averageLoss = 0;
}
}
I am trying to implement minimax in my C# code for tictactoe. For some reason, when the depth = 1 and I debug it to check to see all of the values returned from different paths; I see crazy values like -1000, -5000, -1000, etc! How is this possible? What is happening? This is my full code,
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Minimax_TicTacToe
{
public partial class Main : Form
{
//Definition constants
private const int EMPTY = 0;
private const int PLAYER = 1;
private const int COMPUTER = 2;
private const int PLAYER_WON = 0;
private const int COMPUTER_WON = 1;
private const int DRAW = 2;
private const int GAME = 3;
private const int OVER = 4;
//Internals
private int turns = 0;
private int turn = PLAYER;
private String player_mark = "X";
private String computer_mark = "O";
//Grid
private byte[] grid = {
0, 0, 0,
0, 0, 0,
0, 0, 0
};
public Main()
{
InitializeComponent();
}
private void Main_Load(object sender, EventArgs e)
{
}
/*
private int Minimax(byte[] ngrid, int depth = 0, int score = 0)
{
if (depth == 0)
{
return Minimax(new byte[] { grid[0], grid[1], grid[2],
grid[3], grid[4], grid[5],
grid[6], grid[7], grid[8] },
depth + 1);
}
else
{
int status = GameStatus(ngrid);
if (status == PLAYER_WON) return -1;
else if (status == COMPUTER_WON) return 1;
else if (status == DRAW) return 0;
int i;
for (i = 0; i < grid.Length; i++)
{
if (ngrid[i] == 0)
{
byte[] board = new byte[] {
ngrid[0], ngrid[1], ngrid[2],
ngrid[3], ngrid[4], ngrid[5],
ngrid[6], ngrid[7], ngrid[8]
};
board[i] = (depth % 2 == 0) ? (byte)PLAYER : (byte)COMPUTER;
score = Minimax(board, depth + 1);
if (score == 1 && depth == 1) return i;
if (score == 1) return 1;
}
}
return 0;
}
}*/
private int Minimax(byte[] ngrid, int depth = 0)
{
if (depth == 0)
{
return Minimax(new byte[] { grid[0], grid[1], grid[2],
grid[3], grid[4], grid[5],
grid[6], grid[7], grid[8] },
depth + 1);
}
else
{
int status = GameStatus(ngrid);
if (status == PLAYER_WON) return -1;
else if (status == COMPUTER_WON) return 1;
else if (status == DRAW) return 0;
int i;
int score = 0;
List<Carrier> carry = new List<Carrier>();
for (i = 0; i < grid.Length; i++)
{
if (ngrid[i] == 0)
{
byte[] board = new byte[] {
ngrid[0], ngrid[1], ngrid[2],
ngrid[3], ngrid[4], ngrid[5],
ngrid[6], ngrid[7], ngrid[8]
};
board[i] = (depth % 2 == 0) ? (byte)PLAYER : (byte)COMPUTER;
score += Minimax(board, depth + 1);
if (depth == 1)
{
Carrier c = new Carrier();
c.offset = i;
c.score = score;
carry.Add(c);
}
}
}
if (depth == 1)
{
MessageBox.Show("");
}
return score;
}
}
private void ComputersTurn()
{
turn = COMPUTER;
turns++;
int status = GameStatus(grid);
switch (status)
{
case GAME:
int offset = Minimax(grid);
grid[offset] = COMPUTER;
turn = PLAYER;
UpdateBoard();
break;
}
switch (GameStatus(grid))
{
case PLAYER_WON:
turn = COMPUTER;
MessageBox.Show("You win!");
break;
case COMPUTER_WON:
turn = COMPUTER;
MessageBox.Show("You lost!");
break;
case DRAW:
turn = COMPUTER;
MessageBox.Show("DRAW!");
break;
}
}
private void UpdateBoard()
{
int n = 0;
grid0.Text = (grid[n] != 0) ? ( (grid[n] == PLAYER ? player_mark : computer_mark) ) : "";
n++;
grid1.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid2.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid3.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid4.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid5.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid6.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid7.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid8.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
}
private int GameStatus(byte[] pgrid)
{
for (int i = 0; i < 3; i++)
{
if (pgrid[i * 3] == pgrid[i * 3 + 1] && pgrid[i * 3] == pgrid[i * 3 + 2] && pgrid[i * 3] != 0)
return SelectWinner(pgrid[i * 3]);
if (pgrid[i] == pgrid[i + 3] && pgrid[i] == pgrid[i + 6] && pgrid[i] != 0)
return SelectWinner(pgrid[i]);
}
if (pgrid[0] == pgrid[4] && pgrid[0] == pgrid[8] && pgrid[0] != 0)
return SelectWinner(pgrid[0]);
if (pgrid[2] == pgrid[4] && pgrid[2] == pgrid[6] && pgrid[2] != 0)
return SelectWinner(pgrid[2]);
if (turns == 4)
return DRAW;
return GAME;
}
private int SelectWinner(byte item)
{
if (item == PLAYER)
return PLAYER_WON;
else if (item == COMPUTER)
return COMPUTER_WON;
throw new Exception("SELECTION ERROR");
}
private void grid0_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[0] = PLAYER;
grid0.Text = player_mark;
ComputersTurn();
}
private void grid1_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[1] = PLAYER;
grid1.Text = player_mark;
ComputersTurn();
}
private void grid2_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[2] = PLAYER;
grid2.Text = player_mark;
ComputersTurn();
}
private void grid3_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[3] = PLAYER;
grid3.Text = player_mark;
ComputersTurn();
}
private void grid4_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[4] = PLAYER;
grid4.Text = player_mark;
ComputersTurn();
}
private void grid5_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[5] = PLAYER;
grid5.Text = player_mark;
ComputersTurn();
}
private void grid6_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[6] = PLAYER;
grid6.Text = player_mark;
ComputersTurn();
}
private void grid7_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[7] = PLAYER;
grid7.Text = player_mark;
ComputersTurn();
}
private void grid8_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[8] = PLAYER;
grid8.Text = player_mark;
ComputersTurn();
}
}
class Carrier
{
public int score;
public int offset;
}
}
The one thing that jumps out at me is this piece:
score += Minimax(...
I think you'll want your minimax to select the move with the best score and return that score, not the sum of the scores for all possible moves from that position.
Is it possible to display fractions in a NumericUpDown or a DomainUpDown?
I know there are some fonts that have various fraction characters, but I would like to keep my form using Microsoft Sans Serif uniformly.
What do you mean by upto one-tenth.
I have a sample code for you, try if it works for you
nupdwn.Minimum = -10;
nupdwn.Maximum = 10;
nupdwn.Increment = 0.25;
nupdwn.DecimalPlaces = 2;
Microsoft Sans Serif does support fractional characters:
I will try to program a derived NumericUpDown to show fractional values. If it succeeds, i will share the code here...
Here is my Sample-Code for a FractionalUpDown.
Be sure to set DecimalPlaces to your needs.
With Mode, you can choose the formatting of the value:
EMode.Decimal => 2,500.
EMode.Fractional => ⁵⁄₂
EMode.FractionalMixed => 2 ¹⁄₂
EMode.FractionalASCII => 5/2
EMode.FractionalMixedASCII => 2 1/2
Code:
public class FractionalUpDown: NumericUpDown {
//Hide Hexadecimal
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool Hexadecimal {
get { return false; }
set { base.Hexadecimal = false; }
}
private EMode mode;
[DefaultValue(EMode.Fractional)]
public EMode Mode {
get { return mode; }
set {
if (value != mode) {
mode = value;
UpdateEditText();
}
}
}
public enum EMode {
Fractional,
FractionalMixed,
FractionalASCII,
FractionalMixedASCII,
Decimal
}
public FractionalUpDown() {
}
protected override void UpdateEditText() {
if (Mode == EMode.Decimal) {
base.UpdateEditText();
return;
}
double accuracy = Math.Pow(10.0, -(DecimalPlaces + 1));
if (accuracy > 0.1) accuracy = 0.1;
this.Text = FractionToString(DoubleToFraction((double)Value, accuracy), Mode);
}
public struct Fraction {
public Fraction(int n, int d) {
N = n;
D = d;
}
public int N { get; private set; }
public int D { get; private set; }
}
private static readonly char[] numbers = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
private static readonly char[] numerators = new char[10] { '⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹' };
private static readonly char[] denumerators = new char[10] { '₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉' };
protected string FractionToString(Fraction frac, EMode mode) {
int full = 0;
int n = frac.N;
string result = string.Empty;
bool mixed = mode == EMode.FractionalMixed ||
mode == EMode.FractionalMixedASCII;
bool useFractionalChars = mode == EMode.Fractional ||
mode == EMode.FractionalMixed;
if (mixed && Math.Abs(frac.N) >= frac.D) {
full = frac.N / frac.D;
n = Math.Abs(frac.N % frac.D);
if (full != 0) result = full.ToString();
else if (n == 0) return "0";
}
if (n != 0) {
string fracNtext = n.ToString();
string fracDtext = frac.D.ToString();
if (useFractionalChars) {
for (int i = 0; i < 10; i++) fracNtext = fracNtext.Replace(numbers[i], numerators[i]);
for (int i = 0; i < 10; i++) fracDtext = fracDtext.Replace(numbers[i], denumerators[i]);
} else {
if (full != 0) result += " ";
}
result += fracNtext + '⁄' + fracDtext;
} else {
//Fractional Part == 0/?
if (full == 0) {
if (mixed == true) {
return "0";
} else {
if (useFractionalChars) {
return numerators[0].ToString() + '⁄' + denumerators[1].ToString();
} else {
return numbers[0].ToString() + '⁄' + numbers[1].ToString();
}
}
}
}
return result;
}
//Source: https://stackoverflow.com/questions/5124743/algorithm-for-simplifying-decimal-to-fractions/32903747#32903747
protected Fraction DoubleToFraction(double value, double accuracy) {
if (accuracy <= 0.0 || accuracy >= 1.0) {
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
}
int sign = Math.Sign(value);
if (sign == -1) {
value = Math.Abs(value);
}
// Accuracy is the maximum relative error; convert to absolute maxError
double maxError = sign == 0 ? accuracy : value * accuracy;
int n = (int)Math.Floor(value);
value -= n;
if (value < maxError) {
return new Fraction(sign * n, 1);
}
if (1 - maxError < value) {
return new Fraction(sign * (n + 1), 1);
}
// The lower fraction is 0/1
int lower_n = 0;
int lower_d = 1;
// The upper fraction is 1/1
int upper_n = 1;
int upper_d = 1;
while (true) {
// The middle fraction is (lower_n + upper_n) / (lower_d + upper_d)
int middle_n = lower_n + upper_n;
int middle_d = lower_d + upper_d;
if (middle_d * (value + maxError) < middle_n) {
// real + error < middle : middle is our new upper
Seek(ref upper_n, ref upper_d, lower_n, lower_d, (un, ud) => (lower_d + ud) * (value + maxError) < (lower_n + un));
upper_n = middle_n;
upper_d = middle_d;
} else if (middle_n < (value - maxError) * middle_d) {
// middle < real - error : middle is our new lower
Seek(ref lower_n, ref lower_d, upper_n, upper_d, (ln, ld) => (ln + upper_n) < (value - maxError) * (ld + upper_d));
lower_n = middle_n;
lower_d = middle_d;
} else {
// Middle is our best fraction
return new Fraction((n * middle_d + middle_n) * sign, middle_d);
}
}
}
/// <summary>
/// Binary seek for the value where f() becomes false.
/// Source: https://stackoverflow.com/questions/5124743/algorithm-for-simplifying-decimal-to-fractions/32903747#32903747
/// </summary>
protected void Seek(ref int a, ref int b, int ainc, int binc, Func<int, int, bool> f) {
a += ainc;
b += binc;
if (f(a, b)) {
int weight = 1;
do {
weight *= 2;
a += ainc * weight;
b += binc * weight;
}
while (f(a, b));
do {
weight /= 2;
int adec = ainc * weight;
int bdec = binc * weight;
if (!f(a - adec, b - bdec)) {
a -= adec;
b -= bdec;
}
}
while (weight > 1);
}
}
}