Skip to content

Instantly share code, notes, and snippets.

@swawa-yu
Forked from keidaroo/automaticgenerator.cs
Last active November 24, 2018 09:37
Show Gist options
  • Save swawa-yu/ed658257389b3d06d78d2e7e669f0d07 to your computer and use it in GitHub Desktop.
Save swawa-yu/ed658257389b3d06d78d2e7e669f0d07 to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
/*RULE
|0 -> nothing | 1 -> wall | 2 -> goal | 3 -> answer|
|0 -> 下 | 1 -> 右 | 2 -> 上 | 3 -> 左|
map
-> x
↓ |0,0|1,0|
y |1,0|1,1|
upx ->指定した方向に動くブロック
downx -> 指定した方向と逆に動くブロック
*/
[DefaultExecutionOrder(-3)]
public class automaticgenerator : MonoBehaviour {
//------------------変数-------------------------//
//SWAco:mapの要素へのアクセスは[x,y]で書いてます。元のソースコードはは[y,x]でした(?)。変更しきれてないとこがあるかもしれません
public MapChip[, ] map; //x座標、y座標  初期化は別のところで
public Cube up, down;
public Cube startUp, startDown;
public int atLeastWallNum;
public int edgeLength; //一辺の長
public int rotateNumLimit;
//-------------------------------------------------//
// Use this for initialization
public bool isCompeteMode;
public bool isTutorialMode;
public string mapCode;
struct Cube {
public int X, Y;
public Type type;
public enum Type {
Up,
Down
}
public void Move(int add, Direction dir) {
if (type == Type.Down)add *= -1;
switch (dir) {
case Direction.Down:
Y += add;
break;
case Direction.Right:
X += add;
break;
case Direction.Up:
Y -= add;
break;
case Direction.Left:
X -= add;
break;
}
}
}
struct PairWithDirection {
public int x, y, beforeDirection, count;
public string beforePos;
};
//mapの要素をintからenumにしました。一応暗黙の型変換ははたらくはずです
enum MapChip {
Nothing,
Wall,
Goal,
Answer
}
//方向もintからenumにしました。一応暗黙の型変換ははたらくはずです
enum Direction {
Down = 0,
Right,
Up,
Left
}
//SWAco:読んでません ここいじらないとバグでそうなのはしってるんですけど、、
PairWithDirection moveToWall(int dir, PairWithDirection now) {
int[] xy = { 0, 1, 0, -1, 0 };
while (true) {
if (map[now.y + xy[dir + 1], now.x + xy[dir]] != MapChip.Wall) {
now.x += xy[dir];
now.y += xy[dir + 1];
} else {
return now;
}
}
}
int conv(PairWithDirection toRed, PairWithDirection toBlue) {
string visCheck = '1' + toRed.x.ToString().PadLeft(2, '0') + toRed.y.ToString().PadLeft(2, '0') + toBlue.x.ToString().PadLeft(2, '0') + toBlue.y.ToString().PadLeft(2, '0');
return int.Parse(visCheck);
}
public Dictionary<int, int> vis = new Dictionary<int, int>();
//SWAco:読んでません
int CountToGoal(PairWithDirection startBlue, PairWithDirection startRed) {
var blueQueue = new Queue<PairWithDirection>();
var redQueue = new Queue<PairWithDirection>();
blueQueue.Enqueue(startBlue);
redQueue.Enqueue(startRed);
int finalCnt = -1;
while (blueQueue.Count > 0) {
PairWithDirection blue = blueQueue.Dequeue();
PairWithDirection red = redQueue.Dequeue();
if (map[blue.y, blue.x] == MapChip.Goal && map[red.y, red.x] == MapChip.Goal) {
finalCnt = blue.count;
break;
}
for (int toDirection = 0; toDirection < 4; toDirection++) {
if (red.beforeDirection == toDirection)continue;
var toRed = moveToWall(toDirection, red);
var toBlue = moveToWall((toDirection + 2) % 4, blue);
string visCheck = '1' + toRed.x.ToString().PadLeft(2, '0') + toRed.y.ToString().PadLeft(2, '0') + toBlue.x.ToString().PadLeft(2, '0') + toBlue.y.ToString().PadLeft(2, '0');
if (vis.ContainsKey(int.Parse(visCheck)))continue;
vis.Add(int.Parse(visCheck), conv(red, blue));
visCheck = '1' + toBlue.x.ToString().PadLeft(2, '0') + toBlue.y.ToString().PadLeft(2, '0') + toRed.x.ToString().PadLeft(2, '0') + toRed.y.ToString().PadLeft(2, '0');
vis.Add(int.Parse(visCheck), conv(blue, red));
toRed.beforeDirection = toBlue.beforeDirection = (toDirection + 2) % 4;
toRed.count = toBlue.count = toRed.count + 1;
blueQueue.Enqueue(toBlue);
redQueue.Enqueue(toRed);
}
}
return finalCnt;
}
void InitParams(int upX, int upY, int downX, int downY, int atleastwallnum, int edgelength, int rotatenumlimit) {
up.X = upX;
up.Y = upY;
up.type = Cube.Type.Up;
down.X = downX;
down.Y = downY;
down.type = Cube.Type.Down;
atLeastWallNum = atleastwallnum;
edgeLength = edgelength;
rotateNumLimit = udrotatenumlimit;
map == new MapChip[edgelength, edgelength];
}
void InitMap() {
for (int i = 0; i <= edgeLength; i++) {
for (int j = 0; j <= edgeLength; j++) {
map[i, j] = MapChip.Nothing;
}
}
map[down.X, down.Y] = MapChip.Answer;
map[up.X, up.Y] = MapChip.Answer;
//初期のブロックの位置の上下にブロックを置く
for (int i = 0; i < 3; i++) {
map[up.X - 1 + i, up.Y - 1] = MapChip.Wall;
map[down.X - 1 + i, down.Y + 1] = MapChip.Wall;
}
for (int i = 0; i <= edgeLength; i++) {
map[0, i] = MapChip.Wall;
map[i, 0] = MapChip.Wall;
map[edgeLength, i] = MapChip.Wall;
map[i, edgeLength] = MapChip.Wall;
}
}
//rangeが適切か(適切なら同時にAnswerで塗ります)
bool IsAppropriate(Cube cube, int range, Direction direction) {
if (range % 2 == 1)return false; //もし距離が奇数なら
//range先とその左右のマスに正解の道はないか
{
int add = (range + 1) * (cube.type == Cube.Type.Up ? 1 : -1);
for (int i = 0; i < 3; i++) {
switch (dir) {
case Direction.Down:
if (map[cube.X - 1 + i, cube.Y + add] == MapChip.Answer)return false;
break;
case Direction.Right:
if (map[cube.X + add, cube.Y - 1 + i] == MapChip.Answer)return false;
break;
case Direction.Up:
if (map[cube.X - 1 + i, cube.Y - add] == MapChip.Answer)return false;
break;
case Direction.Left:
if (map[cube.X - add, cube.Y - 1 + i] == MapChip.Answer)return false;
break;
}
}
}
//isSafeToConfirm
{
int x = cube.X, y = cube.Y;
int movex, movey;
switch (dir) {
case Direction.Down:
movex = 0;
movey = 1;
break;
case Direction.Right:
movex = 1;
movey = 0;
break;
case Direction.Up:
movex = 0;
movey = -1;
break;
case Direction.Left:
movex = -1;
movey = 0;
break;
}
if (type == Type.Down) {
movex *= -1;
movey *= -1;
}
//range進んで壁に当たらないか
for (int i = 0; i < range; i++, x += movex, y += movey) {
if (map[x + movex, y + movey] == MapChip.Wall)return false;
}
//元の場所まで戻りながらその道を答えの道に設定する
for (int i = 0; i < range; i++, x -= movex, y -= movey) {
map[x, y] = MapChip.Answer;
}
}
return true;
}
//SWAco:あいかわらず9990の正解が来るまでループするアルゴリズムのままです。どんなアルゴリズムにするかは任せます
void MakeWall(Cube cube, Direction direction) {
int add = cube.type == Cube.Type.Up ? 1 : -1; //もういっこ向こう側の列をいじるので
int range;
switch (direction) {
case Direction.Down:
//rangeを決定
for (int i = 1; i <= 9990 && !IsAppropriate(cube, range, direction); i++) {
range = Random.Range(0, edgeLength - 1 - cube.Y); //壁を作る一歩手前まで
}
cube.Move(range, direction);
for (int i = 0; i < 3; i++)map[cube.X - 1 + i, cube.Y + add] = MapChip.Wall; //三マス塗る!
break;
case Direction.Right:
for (int i = 1; i <= 9990 && !IsAppropriate(cube, range, direction); i++) {
range = Random.Range(0, edgeLength - 1 - cube.Y);
}
cube.Move(range, direction);
for (int i = 0; i < 3; i++)map[cube.X + add, cube.Y - 1 + i] = MapChip.Wall;
break;
case Direction.Up:
for (int i = 1; i <= 9990 && !IsAppropriate(cube, range, direction); i++) {
range = Random.Range(0, edgeLength - 1 - cube.Y);
}
cube.Move(range, direction);
for (int i = 0; i < 3; i++)map[cube.X - 1 + i, cube.Y - add] = MapChip.Wall;
break;
case Direction.Left:
for (int i = 1; i <= 9990 && !IsAppropriate(cube, range, direction); i++) {
range = Random.Range(0, edgeLength - 1 - cube.Y);
}
cube.Move(range, direction);
for (int i = 0; i < 3; i++)map[cube.X - add, cube.Y - 1 + i] = MapChip.Wall;
break;
}
}
//SWAco:マップ生成と直接関わりのなさそうなところは読んでません
void Awake() {
Application.targetFrameRate = 60; //60FPSに設定
if (isCompeteMode || isTutorialMode) {
map = GetComponent<codevisualizer>().Lockoff(mapCode);
Debug.Log(map[0, 0]);
return;
}
int difficulty = GameObject.Find("pointsText").GetComponent<data>().difficulty;
if (difficulty == 0)InitParams(7, 3, 5, 5, 10, 10, 10);
if (difficulty == 1)InitParams(9, 7, 7, 9, 40, 16, 40);
if (difficulty == 2)InitParams(13, 11, 11, 13, 80, 24, 114514);
if (difficulty == 3)InitParams(11, 9, 9, 11, 60, 20, 114514);
startDown = down;
startUp = up;
InitMap();
Direction direction;
Direction previousDirection = Direction.Down;
for (int rotateNum = 0; rotateNum < rotateNumLimit; rotateNum++) {
direction = (previousDirection + 1) % 4; //前の方向から90度回転
if (Random.Range(0, 2))direction = (direction + 2) % 4; //50%の確率でさらに方向を180度変える
MakeWall(up, direction);
MakeWall(down, direction);
previousDirection = direction;
}
string scenename = SceneManager.GetActiveScene().name;
if (up.X == startUp.X && up.Y == startUp.Y) { SceneManager.LoadScene(scenename); }
if (up.X == startDown.X && up.Y == startDown.Y) { SceneManager.LoadScene(scenename); }
if (down.X == startUp.X && down.Y == startUp.Y) { SceneManager.LoadScene(scenename); }
if (down.X == startDown.X && down.Y == startDown.Y) { SceneManager.LoadScene(scenename); }
int pikuto = 0;
for (int i = 1; i < edgeLength; i++) {
for (int j = 1; j < edgeLength; j++) {
if (map[i, j] == MapChip.Wall)pikuto++;
}
}
if (pikuto < atLeastWallNum) { SceneManager.LoadScene(scenename); }
map[up.X, up.Y] = MapChip.Goal;
map[down.X, down.Y] = MapChip.Goal;
PairWithDirection a = new PairWithDirection(), b = new PairWithDirection();
a.x = startUp.X;
a.y = startUp.Y;
b.x = startDown.X;
b.y = startDown.Y;
b.beforeDirection = -1;
int countGoal = CountToGoal(a, b);
Debug.Log(countGoal);
if (difficulty == 0 && countGoal <= 1)SceneManager.LoadScene(scenename);
else if (difficulty == 1 && countGoal <= 3)SceneManager.LoadScene(scenename);
else if (difficulty == 3 && countGoal <= 4)SceneManager.LoadScene(scenename);
else if (difficulty == 2 && countGoal <= 4)SceneManager.LoadScene(scenename);
var movetheball = GameObject.Find("playerObjectUp").GetComponent<movePlayer>();
movetheball.goaldownX = down.X;
movetheball.goaldownY = down.Y;
movetheball.goalupX = up.X;
movetheball.goalupY = up.Y;
if (SceneManager.GetActiveScene().name == "bot") {
GameObject.Find("pointsText").GetComponent<data>().botGameClear();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment