/// <summary> /// 블록 내의 모퉁이에 적의 발생 위치를 랜덤하게 생성한다. /// </summary> /// <param name="block">대상 블록</param> public void CreateSpawnPointAtCornnerAtRandom(ChipType[,] block) { // 플로어 수를 카운트. int candidate = 0; // 스폰 포인트가 될 수 있는 플로어 수. for (int bh = 1; bh < block.GetLength(0); ++bh) { for (int bw = 1; bw < block.GetLength(1); ++bw) { if (block[bh, bw] != ChipType.Floor || !IsCornner(block, bh, bw)) continue; ++candidate; } } if (candidate == 0) return; // 플로어를 랜덤 선택. double r = random.NextDouble(); double total = 0.0; for (int bh = 1; bh < block.GetLength(0); ++bh) { for (int bw = 1; bw < block.GetLength(1); ++bw) { if (block[bh, bw] != ChipType.Floor || !IsCornner(block, bh, bw)) continue; total += 1.0/candidate; if (r < total) { block[bh, bw] = ChipType.Spawn; return; } } } }
/// <summary> /// 지정한 블록 간의 거리( )를 구한다. /// </summary> /// <param name="from_fh">블록 위치</param> /// <param name="from_fw">블록 위치</param> /// <param name="to_fh">블록 위치</param> /// <param name="to_fw">블록 위치</param> /// <returns>거리</returns> public int GetDistanceBetweenTwoBlock(ChipType[,][,] field, int from_fh, int from_fw, int to_fh, int to_fw) { // 일단 미로를 무시한 거리를 반환. // return Math.Abs(from_fh - to_fh) + Math.Abs(from_fw - to_fw); var h = field.GetLength(0); var w = field.GetLength(1); int[,] doorInfo = new int[h, w]; for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { var d = 0; var b = field[i, j]; var bh = b.GetLength(0); var bw = b.GetLength(1); var bhc = (bh / 2) % 2 == 0 ? bh/2-1 : bh/2; var bwc = (bw / 2) % 2 == 0 ? bw/2+1 : bw/2; if (b[bhc, 0] == ChipType.Door) d |= Direction.Left; if (b[bhc, bw-1] == ChipType.Door) d |= Direction.Right; if (b[0, bwc] == ChipType.Door) d |= Direction.Top; if (b[bh-1, bwc] == ChipType.Door) d |= Direction.Bottom; doorInfo[i, j] = d; } } // DFS var distance = int.MaxValue; var closed = new bool[h, w]; var open = new Queue<KeyValuePair<int, int>>(); var d_buffer = new Queue<int>(); open.Enqueue(new KeyValuePair<int,int>(from_fh, from_fw)); d_buffer.Enqueue(0); Func<int, int, bool> RangeTest = (i, j) => { if (i < 0 || j < 0 || i >= h || j >= w) return false; return true; }; while (open.Count != 0) { var pos = open.Dequeue(); var i = pos.Key; var j = pos.Value; var d = d_buffer.Dequeue(); if (closed[i, j]) continue; if ((i == to_fh && j == to_fw) && distance > d) { distance = d; continue; } if (HasTargetDoor(doorInfo[i, j], Direction.Top) && RangeTest(i-1, j)) { open.Enqueue(new KeyValuePair<int, int>(i-1, j)); d_buffer.Enqueue(d+1); } if (HasTargetDoor(doorInfo[i, j], Direction.Bottom) && RangeTest(i+1, j)) { open.Enqueue(new KeyValuePair<int, int>(i+1, j)); d_buffer.Enqueue(d+1); } if (HasTargetDoor(doorInfo[i, j], Direction.Left) && RangeTest(i, j-1)) { open.Enqueue(new KeyValuePair<int, int>(i, j-1)); d_buffer.Enqueue(d+1); } if (HasTargetDoor(doorInfo[i, j], Direction.Right) && RangeTest(i, j+1)) { open.Enqueue(new KeyValuePair<int, int>(i, j+1)); d_buffer.Enqueue(d+1); } closed[i, j] = true; } return distance; }
public void DebugPrint(ChipType[,] block) { for (int h = 0; h < block.GetLength(0); ++h) { for (int w = 0; w < block.GetLength(1); ++w) { switch (block[h, w]) { case ChipType.Wall: Console.Write("@"); break; case ChipType.Floor: Console.Write(" "); break; case ChipType.BottomKey: Console.Write("b"); break; case ChipType.TopKey: Console.Write("t"); break; case ChipType.RightKey: Console.Write("r"); break; case ChipType.LeftKey: Console.Write("l"); break; case ChipType.Door: Console.Write("d"); break; case ChipType.BossKey: Console.Write("B"); break; default: throw new Exception("그런 블록은 없어요"); } } Console.WriteLine(string.Empty); } }
private void CreateKey(ref ChipType[,] block, int door) { // 플로어 수 카운트 int nofFloor = 0; for (int h = 1; h < block.GetLength(0)-1; ++h) { for (int w = 1; w < block.GetLength(1)-1; ++w) { if (block[h, w] == ChipType.Floor) ++nofFloor; } } // 열쇠 설치 for (int i = 0; i < 4; ++i) { ChipType key; if (i == 0) { key = ChipType.RightKey; if ((door & Direction.Right) == 0) continue; } else if (i == 1) { key = ChipType.LeftKey; if ((door & Direction.Left) == 0) continue; } else if (i == 2) { key = ChipType.BottomKey; if ((door & Direction.Bottom) == 0) continue; } else { key = ChipType.TopKey; if ((door & Direction.Top) == 0) continue; } double total = 0.0; double p = random.NextDouble(); for (int h = 1; h < block.GetLength(0)-1; ++h) { for (int w = 1; w < block.GetLength(1)-1; ++w) { total += 1.0 / nofFloor; if (block[h,w] != ChipType.Floor || p > total) continue; block[h, w] = key; --nofFloor; h = block.GetLength(0); break; } } } }
private void CreateDoor(ref ChipType[,] block, int door, bool is_room) { int hd = 0; int wd = 0; if (((block.GetLength(0)-2) / 2) % 2 == 1) hd = 1; if (((block.GetLength(1)-2) / 2) % 2 == 1) wd = 1; ChipType doorChip = ChipType.Door; if ((door & Direction.Left) != 0) { if(is_room) { block[block.GetLength(0)/2-hd, 0] = ChipType.Wall; block[block.GetLength(0)/2-hd, 1] = doorChip; } else { block[block.GetLength(0)/2-hd, 0] = doorChip; block[block.GetLength(0)/2-hd, 1] = ChipType.Floor; } } if ((door & Direction.Right) != 0) { if(is_room) { block[block.GetLength(0)/2-hd, block.GetLength(1)-1] = ChipType.Wall; block[block.GetLength(0)/2-hd, block.GetLength(1)-2] = doorChip; } else { block[block.GetLength(0)/2-hd, block.GetLength(1)-1] = doorChip; block[block.GetLength(0)/2-hd, block.GetLength(1)-2] = ChipType.Floor; } } if ((door & Direction.Top) != 0) { if(is_room) { block[0, block.GetLength(1)/2+wd] = ChipType.Wall; block[1, block.GetLength(1)/2+wd] = doorChip; } else { block[0, block.GetLength(1)/2+wd] = doorChip; block[1, block.GetLength(1)/2+wd] = ChipType.Floor; } } if ((door & Direction.Bottom) != 0) { if(is_room) { block[block.GetLength(0)-1, block.GetLength(1)/2+wd] = ChipType.Wall; block[block.GetLength(0)-2, block.GetLength(1)/2+wd] = doorChip; } else { block[block.GetLength(0)-1, block.GetLength(1)/2+wd] = doorChip; block[block.GetLength(0)-2, block.GetLength(1)/2+wd] = ChipType.Floor; } } }
/// <summary> /// Block을 만든다. /// </summary> /// <param name="emptyBlock"></param> /// <returns></returns> private void CreateWall(ref ChipType[,] emptyBlock) { int height = emptyBlock.GetLength(0); int width = emptyBlock.GetLength(1); for (int h = 2; h < height-1; h+=2) { for (int w = 2; w < width-1; w+=2) { int randMax = 3; var next = random.Next(randMax); if (next == 0) // 오른쪽 방향 emptyBlock[h,w+1] = ChipType.Wall; else if (next == 1) // 왼쪽 방향 emptyBlock[h,w-1] = ChipType.Wall; else if (next == 2) // 아래 방향 emptyBlock[h+1,w] = ChipType.Wall; } } }
private void CreateDoor(ref ChipType[,] block, int door) { int hd = 0; int wd = 0; if (((block.GetLength(0)-2) / 2) % 2 == 1) hd = 1; if (((block.GetLength(1)-2) / 2) % 2 == 1) wd = 1; if ((door & Direction.Left) != 0) { block[block.GetLength(0)/2-hd, 0] = ChipType.Door; block[block.GetLength(0)/2-hd, 1] = ChipType.Floor; } if ((door & Direction.Right) != 0) { block[block.GetLength(0)/2-hd, block.GetLength(1)-1] = ChipType.Door; block[block.GetLength(0)/2-hd, block.GetLength(1)-2] = ChipType.Floor; } if ((door & Direction.Top) != 0) { block[0, block.GetLength(1)/2+wd] = ChipType.Door; block[1, block.GetLength(1)/2+wd] = ChipType.Floor; } if ((door & Direction.Bottom) != 0) { block[block.GetLength(0)-1, block.GetLength(1)/2+wd] = ChipType.Door; block[block.GetLength(0)-2, block.GetLength(1)/2+wd] = ChipType.Floor; } }