今天算法课学了个采用递归思想的n皇后算法,闲来无事,用unity简单做个可视化,顺便巩固一下自己先前学习的程序纹理。记录一下自己踩过的坑
(纯粹是为了把学过的知识进行一个综合练习,实用价值不大。。生成这么多程序纹理巨耗性能)
首先是核心的算法部分,在书本的基础上简单做了些修改
Queen.cs
using System.Collections.Generic; using System.Linq; using System.Text; public class Queen { static int[] q = new int[10];//当前在运算的数组列表 static List<int[]> QueenList = new List<int[]>();//存储结果的列表 //其他unity脚本获取该结果列表的唯一接口 public static List<int[]> GetQueenList(int n) { QueenSolution(1, n); return QueenList; } //给结果列表赋值 每次一趟递归运算完得到新的皇后排位会调用一次 static void Disposulation(int n) { int[] array = new int[n+1]; for (int i = 1; i <= n; i++) { array[i] = q[i]; } QueenList.Add(array); } private static bool Place(int i, int j) { if (i == 1) return true; int k = 1; while (k < i) { //n皇后的一个核心判断条件 可以自己脑补一下 if ((q[k] == j) || (System.Math.Abs(q[k] - j) == System.Math.Abs(i - k))) return false; k++; } return true; } //递归部分 递归挺烧脑的 private static void QueenSolution(int i, int n) { if (i > n) { Disposulation(n); } else { for (int j = 1; j <= n; j++) { if (Place(i, j)) { q[i] = j; QueenSolution(i + 1, n); } } } } }
这里自己有踩到一个坑,在定义List的时候忘记了,List是用来存放引用类型的数据了,直接就把q数组拿来存进去了,导致后面结果输出都一样,调试调了好久。。
程序纹理也是通过脚本代码来实现的
ProceduralTextureGeneration.cs
using UnityEngine; using System.Collections; using System.Collections.Generic; public class ProceduralTextureGeneration : MonoBehaviour { //public Material material = null; #region Material properties [SerializeField] private int m_Matrix = 5;//n皇后 n=几 [SerializeField] private int m_textureWidth = 512; [SerializeField] private Color m_backgroundColor = Color.white; [SerializeField] private Color m_circleColor = Color.black; [SerializeField] private Color m_queenColor = Color.yellow; [SerializeField] private float m_blurFactor = 2.0f; //使用list存对象后出现了不销毁的问题 ? //List<GameObject> objList = new List<GameObject>(); //预制体 public GameObject preObj; //预制shader public Shader shader; //Queen算法得到的结果 List<int[]> queenList = new List<int[]>(); //记录obj移动的大小 取值是Queen数量能存放的最小矩阵的一个大小 int width; #endregion private Texture2D m_generatedTexture = null; // Use this for initialization void Start() { queenList = Queen.GetQueenList(m_Matrix); int count = queenList.Count; width = (int)Mathf.Ceil(Mathf.Sqrt(count));//计算这个存放矩阵的大小 int w = 0, h = 0; for (int i = 0; i < count; i++) { h = i / width; //计算纵向平移大小 w = i % width;//计算水平平移大小 GameObject obj = Instantiate(preObj, transform); //移动物体 obj.transform.Translate(new Vector3(w, -h, 0)); //生成赋给meshRenderer组件中的material的新材质 Renderer renderer = obj.GetComponent<Renderer>(); Material mat = new Material(shader); mat.hideFlags = HideFlags.DontSave; m_generatedTexture = _GenerateProceduralTexture(queenList[i]); //生成程序纹理 _UpdateMaterial(mat); renderer.material = mat; } } private void _UpdateMaterial(Material material) { //设置纹理至 _MainTex if (material != null) { material.SetTexture("_MainTex", m_generatedTexture); } } private Color _MixColor(Color color0, Color color1, float mixFactor) { Color mixColor = Color.white; mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor); mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor); mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor); mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor); return mixColor; } //生成程序纹理 private Texture2D _GenerateProceduralTexture(int[] q) { Texture2D proceduralTexture = new Texture2D(m_textureWidth, m_textureWidth); // The interval between circles float circleInterval = m_textureWidth / (m_Matrix+1); // The radius of circles float radius = circleInterval / 3f; // The blur factor float edgeBlur = 1.0f / m_blurFactor; for (int w = 0; w < m_textureWidth; w++) { for (int h = 0; h < m_textureWidth; h++) { // Initalize the pixel with background color Color pixel = m_backgroundColor; // Draw circles one by one for (int i = 0; i < m_Matrix; i++) { for (int j = 0; j < m_Matrix; j++) { // Compute the center of current circle Vector2 circleCenter = new Vector2(circleInterval * (i + 1), circleInterval * (j + 1)); // Compute the distance between the pixel and the center float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius; Color color = m_circleColor; if (q[i + 1] == j + 1) color = m_queenColor; // Blur the edge of the circle color = _MixColor(color, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur)); // Mix the current color with the previous color pixel = _MixColor(pixel, color, color.a); } } proceduralTexture.SetPixel(w, h, pixel); } } proceduralTexture.Apply(); return proceduralTexture; } }
在start中直接调取了Queen中的算法结果,直接依次生成预制体,然后对其材质进行新建和赋值纹理
最后效果如下: