using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data.MoveVectorData.Interfaces; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; namespace HeuristicLab.Data.MoveVectorData { [Item("StackingArea", "Represents multiple stacks of containers.")] [StorableClass] public class StackingArea : Item, IEnumerable, IStringConvertibleMatrix, IStringConvertibleArray { private const int maximumToStringLength = 100; public static new Image StaticItemImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.Class; } } [Storable] protected Stack[] array; #region Parameters [Storable] protected List elementNames; public virtual IEnumerable ElementNames { get { return this.elementNames; } set { if (ReadOnly) throw new NotSupportedException("ElementNames cannot be set. ValueTypeArray is read-only."); if (value == null || !value.Any()) elementNames = new List(); else if (value.Count() > Size) throw new ArgumentException("The number of element names must not exceed the array length."); else elementNames = new List(value); OnElementNamesChanged(); } } [Storable] protected List rowNames; public IEnumerable RowNames { get { return this.rowNames; } set { if (ReadOnly) throw new NotSupportedException("RowNames cannot be set. ValueTypeArray is read-only."); if (value == null || !value.Any()) rowNames = new List(); else if (value.Count() > Size) throw new ArgumentException("The number of row names must not exceed the array length."); else rowNames = new List(value); OnRowNamesChanged(); } } public virtual int Size { get { return array.Length; } protected set { if (ReadOnly) throw new NotSupportedException("Size cannot be set. StringArray is read-only."); if (value != Size) { Array.Resize(ref array, value); while (elementNames.Count > value) elementNames.RemoveAt(elementNames.Count - 1); OnElementNamesChanged(); OnReset(); } } } public virtual int MaxHeight { get { return this.Max(x => x.Length); } set { array = new Stack[Size]; for (int i = 0; i < array.Length; i++) { array[i] = new Stack(i, value); array[i].ItemChanged += StackingArea_ItemChanged; } readOnly = false; elementNames = new List(); rowNames = new List(); } } public virtual int Capacity { get { return array.Sum(stack => stack.Length); } } #endregion #region ReadOnly [Storable] protected bool readOnly; public virtual bool ReadOnly { get { return readOnly; } } public virtual StackingArea AsReadOnly() { StackingArea readOnlyStringArray = (StackingArea)this.Clone(); readOnlyStringArray.readOnly = true; return readOnlyStringArray; } #endregion #region Cloning [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (elementNames == null) { elementNames = new List(); } if (rowNames == null) { rowNames = new List(); } } [StorableConstructor] protected StackingArea(bool deserializing) : base(deserializing) { } protected StackingArea(StackingArea original, Cloner cloner) : base(original, cloner) { //this.array = (Stack[])original.array.Clone(); this.array = new Stack[original.Size]; for (int i = 0; i < array.Length; i++) { array[i] = (Stack)original.array[i].Clone(); } this.readOnly = original.readOnly; this.elementNames = new List(original.elementNames); this.rowNames = new List(original.rowNames); } public override IDeepCloneable Clone(Cloner cloner) { return new StackingArea(this, cloner); } #endregion public StackingArea() : this(0) { } public StackingArea(int size) { array = new Stack[size]; readOnly = false; elementNames = new List(); rowNames = new List(); } public StackingArea(int size, int maxHeight) : this(size) { for (int i = 0; i < array.Length; i++) { array[i] = new Stack(i, maxHeight); array[i].ItemChanged += StackingArea_ItemChanged; } } public StackingArea(Stack[] elements) : this(elements.Length) { for (int i = 0; i < array.Length; i++) { array[i] = elements[i]; } } public void Clear() { foreach(var stack in array) { stack.Clear(); } } public void Randomize(double fillRate, int seed) { if (fillRate > 1 || fillRate < 0) { throw new ArgumentOutOfRangeException("Fill Rate must be between 0 and 1, but is " + fillRate); } Random random = new Random(seed); Clear(); int containerCount = Convert.ToInt32(Capacity * fillRate); var range = new List(containerCount + 1); for(int i = 0; i < containerCount; i++) { range.Add(i + 1); } range.Shuffle(random); for(int i = 0; i < containerCount; i++) { Stack stack; do { var stackNr = random.Next(0, Size); stack = array[stackNr]; } while (stack.CurrentHeight >= stack.Length); stack.Push(range[i]); } } public override string ToString() { if (array.Length == 0) return "[]"; StringBuilder sb = new StringBuilder(); sb.Append("["); sb.Append(array[0]); for (int i = 1; i < array.Length; i++) { sb.Append(";").Append(array[i]); if (sb.Length > maximumToStringLength) { sb.Append("..."); break; } } sb.Append("]"); return sb.ToString(); } public virtual IEnumerator GetEnumerator() { return array.Cast().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public static int ApplyMoves(ref StackingArea startArea, ref Stack inputStack, MoveVector moves, out int realMoves) { int quality = 0; int nrMoves = 0; foreach (IMove move in moves) { int real = 0; quality = quality + move.Apply(ref startArea, ref inputStack, out real); nrMoves = nrMoves + real; } realMoves = nrMoves; return quality; } public static int ApplyMoves(ref StackingArea startArea, MoveVector moves, out int realMoves) { Stack inputStack = null; return ApplyMoves(ref startArea, ref inputStack, moves, out realMoves); } public virtual bool Validate(string value, out string errorMessage) { if (value == null) //TODO { errorMessage = "Invalid Value (string must not be null)"; return false; } else { errorMessage = string.Empty; return true; } } public virtual Stack this[int index] { get { return array[index]; } set { if (ReadOnly) throw new NotSupportedException("Item cannot be set. StringArray is read-only."); if (value != array[index]) { if (value != null) { array[index] = value; OnItemChanged(index); } } } } public virtual int this[int row, int stack] { get { return array[stack][row]; } set { if (ReadOnly) throw new NotSupportedException("Item cannot be set. StringArray is read-only."); array[stack][row] = value; OnItemInStackChanged(row, stack); } } public virtual string GetValue(int index) { return this[index].ToString(); } public virtual string GetValue(int row, int stack) { return this[row, stack].ToString(); } public virtual bool SetValue(string value, int index) { if (value != null && value.StartsWith("[") && value.EndsWith("]")) { string[] strings = value.Substring(1, value.Length - 2).Split(';'); for (int i = 0; i < Size; i++) { int result; if (Int32.TryParse(strings[i], out result)) { this[index][i] = result; } else { return false; } } return true; } else { return false; } } public virtual bool SetValue(string value, int row, int stack) { int result; if (value != null && Int32.TryParse(value, out result)) { this[row, stack] = result; return true; } return false; } #region Events private void StackingArea_ItemChanged(object sender, EventArgs e) { Stack s = (Stack)sender; OnItemInStackChanged(e.Value, s.Id); } public event EventHandler ElementNamesChanged; protected virtual void OnElementNamesChanged() { EventHandler handler = ElementNamesChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler RowNamesChanged; protected virtual void OnRowNamesChanged() { EventHandler handler = RowNamesChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler> ItemChanged; protected virtual void OnItemChanged(int index) { if (ItemChanged != null) ItemChanged(this, new EventArgs(index)); if (index < maximumToStringLength) OnToStringChanged(); } public event EventHandler> ItemInStackChanged; protected virtual void OnItemInStackChanged(int row, int stack) { if (ItemInStackChanged != null) ItemInStackChanged(this, new EventArgs(row, stack)); if (stack < maximumToStringLength && row < maximumToStringLength) OnToStringChanged(); } public event EventHandler Reset; protected virtual void OnReset() { if (Reset != null) Reset(this, EventArgs.Empty); OnToStringChanged(); } public event EventHandler ColumnsChanged; protected virtual void OnColumnsChanged() { if (ColumnsChanged != null) ColumnsChanged(this, EventArgs.Empty); throw new NotImplementedException(); } public event EventHandler RowsChanged; protected virtual void OnRowsChanged() { if (RowsChanged != null) RowsChanged(this, EventArgs.Empty); throw new NotImplementedException(); } public event EventHandler ColumnNamesChanged; protected virtual void OnColumnNamesChanged() { if (ColumnNamesChanged != null) ColumnNamesChanged(this, EventArgs.Empty); throw new NotImplementedException(); } public event EventHandler SortableViewChanged; public event EventHandler ResizableChanged; protected virtual void OnSortableViewChanged() { if (SortableViewChanged != null) SortableViewChanged(this, EventArgs.Empty); throw new NotImplementedException(); } #endregion #region IStringConvertibleMatrix Members event EventHandler> IStringConvertibleMatrix.ItemChanged { add { ItemInStackChanged += value; } remove { ItemInStackChanged -= value; } } int IStringConvertibleMatrix.Rows { get { return MaxHeight; } set { MaxHeight = value; } } int IStringConvertibleMatrix.Columns { get { return Size; } set { Size = value; } } public IEnumerable ColumnNames { get { return ElementNames; } set { ElementNames = value; } } public bool SortableView { get { return false; } set { throw new NotImplementedException(); } } bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) { return Validate(value, out errorMessage); } string IStringConvertibleMatrix.GetValue(int rowIndex, int columIndex) { return GetValue(rowIndex, columIndex); } bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) { return SetValue(value, rowIndex, columnIndex); } #endregion #region IStringConvertibleArray Members int IValueTypeArray.Length { get { return Size; } set { Size = value; } } bool IValueTypeArray.Resizable { get { return false; } set { } } IValueTypeArray IValueTypeArray.AsReadOnly() { throw new NotImplementedException(); } bool IStringConvertibleArray.Validate(string value, out string errorMessage) { return Validate(value, out errorMessage); } string IStringConvertibleArray.GetValue(int index) { return GetValue(index); } bool IStringConvertibleArray.SetValue(string value, int index) { return SetValue(value, index); } #endregion } static class ListExtentions { public static void Shuffle(this IList list, Random random) { int n = list.Count; while (n > 1) { n--; int k = random.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } } } }