Java遺傳算法之沖出迷宮
遺傳算法是模擬達(dá)爾文生物進(jìn)化論的自然選擇和遺傳學(xué)機(jī)理的生物進(jìn)化過程的計(jì)算模型,是一種通過模擬自然進(jìn)化過程搜索最優(yōu)解的方法。它能解決很多問題,比如數(shù)學(xué)方程的最大最小值,背包問題,裝箱問題等。在游戲開發(fā)中遺傳算法的應(yīng)用也十分頻繁,不少的游戲 AI 都利用遺傳算法進(jìn)行編碼。
就個(gè)人理解,遺傳算法是模擬神奇的大自然中生物“優(yōu)勝劣汰”原則指導(dǎo)下的進(jìn)化過程,好的基因有更多的機(jī)會(huì)得到繁衍,這樣一來,隨著繁衍的進(jìn)行,生物種群會(huì)朝著一個(gè)趨勢(shì)收斂。而生物繁衍過程中的基因雜交和變異會(huì)給種群提供更好的基因序列,這樣種群的繁衍趨勢(shì)將會(huì)是“長(zhǎng)江后浪推前浪,一代更比一代強(qiáng)”,而不會(huì)是只受限于祖先的最好基因。而程序可以通過模擬這種過程來獲得問題的最優(yōu)解(但不一定能得到)。要利用該過程來解決問題,受限需要構(gòu)造初始的基因組,并為對(duì)每個(gè)基因進(jìn)行適應(yīng)性分?jǐn)?shù)(衡量該基因的好壞程度)初始化,接著從初始的基因組中選出兩個(gè)父基因(根據(jù)適應(yīng)性分?jǐn)?shù),采用輪盤算法進(jìn)行選擇)進(jìn)行繁衍,基于一定的雜交率(父基因進(jìn)行雜交的概率)和變異率(子基因變異的概率),這兩個(gè)父基因會(huì)生成兩個(gè)子基因,然后將這兩個(gè)基因放入種群中,到這里繁衍一代完成,重復(fù)繁衍的過程直到種群收斂或適應(yīng)性分?jǐn)?shù)達(dá)到最大。
接下來我們就看看用遺傳算法沖出迷宮的實(shí)例。
代碼如下:
import java.awt.Color; import java.awt.Graphics; import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; @SuppressWarnings("serial") public class MazeProblem extends JFrame{ //當(dāng)前基因組 private static List<Gene> geneGroup = new ArrayList<>(); private static Random random = new Random(); private static int startX = 2; private static int startY = 0; private static int endX = 7; private static int endY = 14; //雜交率 private static final double CROSSOVER_RATE = 0.7; //變異率 private static final double MUTATION_RATE = 0.0001; //基因組初始個(gè)數(shù) private static final int POP_SIZE = 140; //基因長(zhǎng)度 private static final int CHROMO_LENGTH = 70; //最大適應(yīng)性分?jǐn)?shù)的基因 private static Gene maxGene = new Gene(CHROMO_LENGTH); //迷宮地圖 private static int[][] map = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,1,0,0,0,0,0,1,1,1,0,0,0,1}, {5,0,0,0,0,0,0,0,1,1,1,0,0,0,1}, {1,0,0,0,1,1,1,0,0,1,0,0,0,0,1}, {1,0,0,0,1,1,1,0,0,0,0,0,1,0,1}, {1,1,0,0,1,1,1,0,0,0,0,0,1,0,1}, {1,0,0,0,0,1,0,0,0,0,1,1,1,0,1}, {1,0,1,1,0,0,0,1,0,0,0,0,0,0,8}, {1,0,1,1,0,0,0,1,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}; private static int MAP_WIDTH = 15; private static int MAP_HEIGHT = 10; private List<JLabel> labels = new ArrayList<>(); public MazeProblem(){ // 初始化 setSize(700, 700); setDefaultCloseOperation(DISPOSE_ON_CLOSE); setResizable(false); getContentPane().setLayout(null); JPanel panel = new JPanel(); panel.setLayout(new GridLayout(MAP_HEIGHT,MAP_WIDTH)); panel.setBounds(10, 10, MAP_WIDTH*40, MAP_HEIGHT*40); getContentPane().add(panel); for(int i=0;i<MAP_HEIGHT;i++){ for(int j=0;j<MAP_WIDTH;j++){ JLabel label = new JLabel(); Color color = null; if(map[i][j] == 1){ color = Color.black; } if(map[i][j] == 0){ color = Color.GRAY; } if(map[i][j] == 5 || map[i][j] ==8){ color = Color.red; } label.setBackground(color); label.setOpaque(true); panel.add(label); labels.add(label); } } } @Override public void paint(Graphics g) { super.paint(g); //畫出路徑 int[] gene = maxGene.getGene(); int curX = startX; int curY = startY; for(int i=0;i<gene.length;i+=2){ //上 if(gene[i] == 0 && gene[i+1] == 0){ if(curX >=1 && map[curX-1][curY] == 0){ curX --; } } //下 else if(gene[i] == 0 && gene[i+1] == 1){ if(curX <=MAP_HEIGHT-1 && map[curX+1][curY] == 0){ curX ++; } } //左 else if(gene[i] == 1 && gene[i+1] == 0){ if(curY >=1 && map[curX][curY-1] == 0){ curY --; } } //右 else{ if(curY <= MAP_WIDTH-1 && map[curX][curY+1] == 0){ curY ++; } } labels.get(curX*MAP_WIDTH+curY).setBackground(Color.BLUE); } } public static void main(String[] args) { //初始化基因組 init(); while(maxGene.getScore() < 1){ //選擇進(jìn)行交配的兩個(gè)基因 int p1 = getParent(geneGroup); int p2 = getParent(geneGroup); //用輪盤轉(zhuǎn)動(dòng)法選擇兩個(gè)基因進(jìn)行交配,雜交和變異 mate(p1,p2); } new MazeProblem().setVisible(true); } /** * 根據(jù)路徑獲得適應(yīng)性分?jǐn)?shù) * @param path * @return */ private static double getScore(int[] gene){ double result = 0; int curX = startX; int curY = startY; for(int i=0;i<gene.length;i+=2){ //上 if(gene[i] == 0 && gene[i+1] == 0){ if(curX >=1 && map[curX-1][curY] == 0){ curX --; } } //下 else if(gene[i] == 0 && gene[i+1] == 1){ if(curX <=MAP_HEIGHT-1 && map[curX+1][curY] == 0){ curX ++; } } //左 else if(gene[i] == 1 && gene[i+1] == 0){ if(curY >=1 && map[curX][curY-1] == 0){ curY --; } } //右 else{ if(curY <= MAP_WIDTH-1 && map[curX][curY+1] == 0){ curY ++; } } } double x = Math.abs(curX - endX); double y = Math.abs(curY - endY); //如果和終點(diǎn)只有一格距離則返回1 if((x == 1&& y==0) || (x==0&&y==1)){ return 1; } //計(jì)算適應(yīng)性分?jǐn)?shù) result = 1/(x+y+1); return result; } /** * 基因初始化 */ private static void init(){ for(int i=0;i<POP_SIZE;i++){ Gene gene = new Gene(CHROMO_LENGTH); double score = getScore(gene.getGene()); if(score > maxGene.getScore()){ maxGene = gene; } gene.setScore(score); geneGroup.add(gene); } } /** * 根據(jù)適應(yīng)性分?jǐn)?shù)隨機(jī)獲得進(jìn)行交配的父類基因下標(biāo) * @param list * @return */ private static int getParent(List<Gene> list){ int result = 0; double r = random.nextDouble(); double score; double sum = 0; double totalScores = getTotalScores(geneGroup); for(int i=0;i<list.size();i++){ Gene gene = list.get(i); score = gene.getScore(); sum += score/totalScores; if(sum >= r){ result = i; return result; } } return result; } /** * 獲得全部基因組的適應(yīng)性分?jǐn)?shù)總和 * @param list * @return */ private static double getTotalScores(List<Gene> list){ double result = 0; for(int i=0;i<list.size();i++){ result += list.get(i).getScore(); } return result; } /** * 兩個(gè)基因進(jìn)行交配 * @param p1 * @param p2 */ private static void mate(int n1,int n2){ Gene p1 = geneGroup.get(n1); Gene p2 = geneGroup.get(n2); Gene c1 = new Gene(CHROMO_LENGTH); Gene c2 = new Gene(CHROMO_LENGTH); int[] gene1 = new int[CHROMO_LENGTH]; int[] gene2 = new int[CHROMO_LENGTH]; for(int i=0;i<CHROMO_LENGTH;i++){ gene1[i] = p1.getGene()[i]; gene2[i] = p2.getGene()[i]; } //先根據(jù)雜交率決定是否進(jìn)行雜交 double r = random.nextDouble(); if(r >= CROSSOVER_RATE){ //決定雜交起點(diǎn) int n = random.nextInt(CHROMO_LENGTH); for(int i=n;i<CHROMO_LENGTH;i++){ int tmp = gene1[i]; gene1[i] = gene2[i]; gene2[i] = tmp; } } //根據(jù)變異率決定是否 r = random.nextDouble(); if(r >= MUTATION_RATE){ //選擇變異位置 int n = random.nextInt(CHROMO_LENGTH); if(gene1[n] == 0){ gene1[n] = 1; } else{ gene1[n] = 0; } if(gene2[n] == 0){ gene2[n] = 1; } else{ gene2[n] = 0; } } c1.setGene(gene1); c2.setGene(gene2); double score1 = getScore(c1.getGene()); double score2 = getScore(c2.getGene()); if(score1 >maxGene.getScore()){ maxGene = c1; } if(score2 >maxGene.getScore()){ maxGene = c2; } c1.setScore(score1); c2.setScore(score2); geneGroup.add(c1); geneGroup.add(c2); } } /** * 基因 * @author ZZF * */ class Gene{ //染色體長(zhǎng)度 private int len; //基因數(shù)組 private int[] gene; //適應(yīng)性分?jǐn)?shù) private double score; public Gene(int len){ this.len = len; gene = new int[len]; Random random = new Random(); //隨機(jī)生成一個(gè)基因序列 for(int i=0;i<len;i++){ gene[i] = random.nextInt(2); } //適應(yīng)性分?jǐn)?shù)設(shè)置為0 this.score = 0; } public int getLen() { return len; } public void setLen(int len) { this.len = len; } public int[] getGene() { return gene; } public void setGene(int[] gene) { this.gene = gene; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } public void print(){ StringBuilder sb = new StringBuilder(); for(int i=0;i<gene.length;i+=2){ if(gene[i] == 0 && gene[i+1] == 0){ sb.append("上"); } //下 else if(gene[i] == 0 && gene[i+1] == 1){ sb.append("下"); } //左 else if(gene[i] == 1 && gene[i+1] == 0){ sb.append("左"); } //右 else{ sb.append("右"); } } System.out.println(sb.toString()); } }
以上就是本文關(guān)于遺傳算法沖出迷宮方法實(shí)例解析,希望對(duì)大家有所幫助。
相關(guān)文章
MybatisPlus實(shí)現(xiàn)數(shù)據(jù)權(quán)限隔離的示例詳解
Mybatis Plus對(duì)Mybatis做了無(wú)侵入的增強(qiáng),非常的好用,今天就給大家介紹它的其中一個(gè)實(shí)用功能:數(shù)據(jù)權(quán)限插件,感興趣的可以跟隨小編一起了解下2024-04-04SpringBoot3使用Jasypt加密數(shù)據(jù)庫(kù)用戶名、密碼等敏感信息
使用Jasypt(Java Simplified Encryption)進(jìn)行數(shù)據(jù)加密和解密主要涉及幾個(gè)步驟,包括引入依賴、配置加密密碼、加密敏感信息、將加密信息存儲(chǔ)到配置文件中,以下是詳細(xì)的使用說明,需要的朋友可以參考下2024-07-07詳解SSM框架下結(jié)合log4j、slf4j打印日志
本篇文章主要介紹了詳解SSM框架下結(jié)合log4j、slf4j打印日志,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11java實(shí)現(xiàn)的新浪微博分享代碼實(shí)例
這篇文章主要介紹了java實(shí)現(xiàn)的新浪微博分享代碼實(shí)例,是通過新浪API獲得授權(quán),然后接受客戶端請(qǐng)求的數(shù)據(jù),第三方應(yīng)用發(fā)送請(qǐng)求消息到微博,喚起微博分享界面,非常的實(shí)用,有相同需要的小伙伴可以參考下。2015-03-03SpringCloud?服務(wù)注冊(cè)中的nacos實(shí)現(xiàn)過程
這篇文章主要介紹了SpringCloud?服務(wù)注冊(cè)之nacos實(shí)現(xiàn)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03spring boot+jwt實(shí)現(xiàn)api的token認(rèn)證詳解
這篇文章主要給大家介紹了關(guān)于spring boot+jwt實(shí)現(xiàn)api的token認(rèn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一學(xué)習(xí)學(xué)習(xí)吧2018-12-12springboot集成mqtt超級(jí)詳細(xì)步驟
這篇文章主要介紹了springboot集成mqtt超級(jí)詳細(xì)步驟,本文分步驟結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06SpringBoot整合Elasticsearch實(shí)現(xiàn)索引和文檔的操作方法
Elasticsearch 基于 Apache Lucene 構(gòu)建,采用 Java 編寫,并使用 Lucene 構(gòu)建索引、提供搜索功能,本文分步驟通過綜合案例給大家分享SpringBoot整合Elasticsearch的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2021-05-05