/// <summary> /// 現在のルームに新しいアイテムを配置できるかを確認し、配置できる場合には現在のルームに新しいアイテムを配置したルームを返却する。 /// </summary> /// <param name="newDisposition">配置するアイテムの情報</param> /// <param name="addedRoom">アイテムが追加されたルーム</param> /// <returns>アイテムが追加された場合はtrue、追加できなかった場合はfalse</returns> /// <remarks> /// このメソッドがtrueを返却した場合にも現在のルームは変更されない。 /// 現在のルームに新しいアイテムが追加されたルームが作成され、addedRoomに返却される。 /// </remarks> public bool TryAddItem(ItemDisposition newDisposition, out Room addedRoom) { var addPoint = newDisposition.Location; var newItem = newDisposition.Item; var newFreeFloorList = new List <Point>(FreeFloors); var occupationPoints = newItem.Occupation.ToRoomCoordination(addPoint); foreach (var p in occupationPoints) { if (!newFreeFloorList.Remove(p)) { addedRoom = none; return(false); } } var newFreeFloors = newFreeFloorList.ToArray(); var newWidth = Width; var newHeight = Height; var newDispositions = new ItemDisposition[Dispositions.Length + 1]; Dispositions.CopyTo(newDispositions, 0); newDispositions[newDispositions.Length - 1] = newDisposition; var newFloorSummary = (int?[, ])FloorSummary.Clone(); foreach (var p in occupationPoints) { newFloorSummary[p.X, p.Y] = newItem.ID; } addedRoom = new Room(newWidth, newHeight, newDispositions, newFreeFloors, newFloorSummary); return(true); }
public Task FindRoomCoordinationAsync(Room startRoom, RoomItem[] items, IRoomReviewer[] reviewers, Action <Room> roomReceiver, Action <Room> halfwayReceiver, CancellationToken cancel) { //var taskCount = Math.Max(1, Environment.ProcessorCount - 1); var taskCount = Math.Max(1, Environment.ProcessorCount); var popCount = 10; var wait = TimeSpan.FromMilliseconds(100); var stack = new ConcurrentStack <Tuple <Room, RoomItem[]> >(); stack.Push(Tuple.Create(startRoom, items)); var waitingCount = 0; return(Task.Run(() => { var workers = new Task[taskCount]; for (int i = 0; i < workers.Length; i++) { workers[i] = Task.Factory.StartNew(() => { var buffer = new Tuple <Room, RoomItem[]> [popCount]; var waiting = false; int counter = 0; Tuple <Room, RoomItem[]>[] newRooms = null; while (true) { cancel.ThrowIfCancellationRequested(); var itemCount = stack.TryPopRange(buffer); if (itemCount > 0) { if (waiting) { Interlocked.Decrement(ref waitingCount); waiting = false; } counter++; if (counter % 100 == 0) { counter = 0; halfwayReceiver(buffer[0].Item1); } if (newRooms == null) { var newRoomsLength = (buffer[0].Item1.Width + 2) * (buffer[0].Item1.Height + 2) * 2; newRooms = new Tuple <Room, RoomItem[]> [newRoomsLength]; } for (var i = 0; i < itemCount; i++) { var roomItemPair = buffer[i]; var room = roomItemPair.Item1; var items = roomItemPair.Item2; if ((items.Length == 0)) { roomReceiver(room); } else { var item = items[0]; var flippedItem = item.Flip(); var newItems = items[1..^ 0]; var newRoomsCount = 0; for (var y = room.Height; y >= -1; y--) { for (var x = room.Width; x >= -1; x--) { var p = new Point(x, y); var disposition = new ItemDisposition(p, item); Room newRoom; if (room.TryAddItem(disposition, out newRoom)) { if (newRoom.IsAcceptableWith(reviewers)) { newRooms[newRoomsCount] = Tuple.Create(newRoom, newItems); newRoomsCount++; } } var disposition2 = new ItemDisposition(p, flippedItem); Room newRoom2; if (room.TryAddItem(disposition2, out newRoom2)) { if (newRoom2.IsAcceptableWith(reviewers)) { newRooms[newRoomsCount] = Tuple.Create(newRoom2, newItems); newRoomsCount++; } } } } if (newRoomsCount > 0) { stack.PushRange(newRooms, 0, newRoomsCount); } } } }