iOS 廣度優(yōu)先搜索算法 實(shí)現(xiàn)掃雷自動(dòng)‘翻牌’功能

這個(gè)算法自己在學(xué)習(xí)iOS開發(fā)做的一個(gè)掃雷游戲,并且已經(jīng)上了AppStore 屁使,但是之后一直在忙沒顧得上優(yōu)化配猫,如果大家發(fā)現(xiàn)什么bug或者可以優(yōu)化的地方,希望各位看官不吝賜教多多反饋交流砂豌。下面進(jìn)入正題,實(shí)現(xiàn)這個(gè)功能需要自定義5個(gè)類啥刻,說明如下:

1.單個(gè)格子模型類奸鸯,用于記錄格子的坐標(biāo)、遍歷狀態(tài)等狀態(tài)可帽;
2.圖的模型類,用于記錄行列數(shù)量和當(dāng)前翻開的狀態(tài)窗怒;
3.基于數(shù)組的隊(duì)列類映跟,廣搜算法中要使用的隊(duì)列,先進(jìn)先出扬虚;(如果改為椗叮可以實(shí)現(xiàn)深度優(yōu)先搜索)
4.計(jì)算周邊點(diǎn)的工具類,只有一個(gè)方法實(shí)現(xiàn)根據(jù)某點(diǎn)獲取其周邊所有的點(diǎn)辜昵,并返回一個(gè)數(shù)組荸镊;
5.最重要的廣度優(yōu)先搜索算法類

定義一個(gè)格子模型

#import <Foundation/Foundation.h>
/// 點(diǎn)的坐標(biāo)
typedef struct {
    int  x;
    int  y;
}ItemIndex;

@interface QSItem : NSObject <NSCoding>
/**是否是雷*/
@property(nonatomic,assign,getter=isMine)BOOL mine;
/**是否已經(jīng)打開*/
@property(nonatomic,assign,getter=isOpened)BOOL opened;
/**周邊雷數(shù)量*/
@property(nonatomic,assign) NSInteger arroundMineNumber;
/**是否遍歷過*/
@property(nonatomic,assign,getter=isTraveled)BOOL traveled;
/**是否標(biāo)記為雷*/
@property(nonatomic,assign,getter=isSignMine)BOOL signMine;
/**在地圖中的坐標(biāo)*/
@property(nonatomic,assign)ItemIndex indexInGraph;
@end
#import "QSItem.h"

@implementation QSItem

- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    if (self) {
        [aDecoder decodeBoolForKey:@"mine"];
        [aDecoder decodeBoolForKey:@"opened"];
        [aDecoder decodeBoolForKey:@"traveled"];
        [aDecoder decodeBoolForKey:@"signMine"];
        [aDecoder decodeIntegerForKey:@"arroundMineNumber"];
        [aDecoder decodeValueOfObjCType:@encode(ItemIndex) at:&_indexInGraph];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeBool:self.mine forKey:@"mine"];
    [aCoder encodeBool:self.opened forKey:@"opened"];
    [aCoder encodeBool:self.traveled forKey:@"traveled"];
    [aCoder encodeBool:self.signMine forKey:@"signMine"];
    [aCoder encodeInteger:self.arroundMineNumber forKey:@"arroundMineNumber"];
    [aCoder encodeValueOfObjCType:@encode(ItemIndex) at:&_indexInGraph];
}


@end

定義一個(gè)圖的模型

#import <Foundation/Foundation.h>

@interface QSGraph : NSObject<NSCoding>
/**地圖數(shù)組*/
@property(nonatomic,strong) NSArray *itemArray;
/**地圖寬度*/
@property(nonatomic,assign) NSInteger width;
/**地圖高度*/
@property(nonatomic,assign) NSInteger heigth;
/**總雷數(shù)*/
@property(nonatomic,assign) NSUInteger totalMinesNumber;
/**已打開的總數(shù)*/
@property(nonatomic,assign) NSInteger totalOpenedNumber;

@end
#import "QSGraph.h"

@implementation QSGraph

- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    if (self) {
        [aDecoder decodeObjectForKey:@"itemArray"];
        [aDecoder decodeIntegerForKey:@"totalMinesNumber"];
        [aDecoder decodeIntegerForKey:@"width"];
        [aDecoder decodeIntegerForKey:@"heigth"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.itemArray forKey:@"itemArray"];
    [aCoder encodeInteger:self.totalMinesNumber forKey:@"totalMinesNumber"];
    [aCoder encodeInteger:self.width forKey:@"width"];
    [aCoder encodeInteger:self.heigth forKey:@"heigth"];
}

//重寫width,height方法,最小為3,小于則返回-1
- (void)setWidth:(NSInteger)width
{
    if (width >= 3) {
        _width = width;
    }else
    {
        _width = -1;
    }
}

- (void)setHeigth:(NSInteger)heigth
{
    if (heigth >= 3) {
        _heigth = heigth;
    }else
    {
        _heigth = -1;
    }
}

@end

定義一個(gè)獲取周邊8個(gè)點(diǎn)的工具類

#import <Foundation/Foundation.h>
#import "QSGraph.h"
#import "QSItem.h"

@interface QSAroundMines : NSObject
/**根據(jù)數(shù)組判斷周邊 對(duì)象*/
+ (NSArray *)getAroundMinesArrayByItem:(QSItem *)item graph:(QSGraph *)graph;
@end
#import "QSAroundMines.h"

@implementation QSAroundMines

+ (NSArray *)getAroundMinesArrayByItem:(QSItem *)item graph:(QSGraph *)graph
{
    //可變數(shù)組
    NSMutableArray *mutableArray = [NSMutableArray array];
    //獲取x,y坐標(biāo)
    int x = item.indexInGraph.x;
    int y = item.indexInGraph.y;
    //循環(huán)判斷周邊點(diǎn),跳過邊界和自身
    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            //過濾自身和越界
            if(
               (i == 0 && j == 0)                    //跳過本身
               || (x == 0 && i == -1)                //跳過-1行
               || (y == 0 && j == -1)                //跳過-1列
               || ((y == graph.width - 1) && j == 1) //跳過+1列
               || ((x == graph.heigth - 1) && i == 1)//跳過+1行
               ) continue;
            //沒有越界則將周邊item加入到數(shù)組中
            NSInteger index = (x + i) * graph.width + y + j;
            QSItem *aroundItem = graph.itemArray[index];
            [mutableArray addObject:aroundItem];
        }
    }
    return mutableArray;
}

@end

定義一個(gè)隊(duì)列類

#import <Foundation/Foundation.h>
#import "QSItem.h"

@interface QSQueue : NSObject
/**隊(duì)列長(zhǎng)度*/
@property(nonatomic,assign)NSUInteger count;
/// 單例生成一個(gè)queue對(duì)象
+ (QSQueue *) sharedQueue;
/**插入隊(duì)尾元素*/
- (void)insertValueAtTailOfQueue:(QSItem*)item;
/**彈出隊(duì)頭元素*/
- (QSItem *)getValueOfHeaderOfQueue;
@end
#import "QSQueue.h"

@interface QSQueue ()
//隊(duì)列內(nèi)置數(shù)組
@property(nonatomic,strong) NSMutableArray *array;
@end

@implementation QSQueue

+ (QSQueue *)sharedQueue
{
    static QSQueue *queue = nil;
    if (queue == nil) {
        queue = [[QSQueue alloc] init];
    }
    return queue;
}

//懶加載數(shù)組
- (NSMutableArray *)array
{
    if (!_array) {
        _array = [NSMutableArray array];
    }
    return _array;
}
/// 隊(duì)列長(zhǎng)度
-(NSUInteger)count
{
    return self.array.count;
}
/// 插入一個(gè)元素
- (void)insertValueAtTailOfQueue:(QSItem *)item
{
    [self.array addObject:item];
    //判斷插入的元素是否在隊(duì)列中已存在,如果存在則刪除,不存在則插入
    for (QSItem *itemInArray in self.array) {
        if (itemInArray != self.array.lastObject) {
            if (item == itemInArray) {
                [self.array removeObject:item];
            }
        }
    }
}
/// 彈出一個(gè)元素
- (QSItem *)getValueOfHeaderOfQueue
{
    QSItem *item = self.array.firstObject;
        [self.array removeObjectAtIndex:0];
    return item;
}

@end

BFS核心算法

+ (void)bfsFunction:(QSGraph *)graph value:(QSItem *)item
{
    //初始化一個(gè)隊(duì)列
    QSQueue *queue = [QSQueue sharedQueue];
    //第一步:將結(jié)點(diǎn)加入到隊(duì)列中
    [queue insertValueAtTailOfQueue:item];
    while (queue.count != 0) {
        //從隊(duì)列頭彈出一個(gè)元素
        QSItem *itemInQueue = [queue getValueOfHeaderOfQueue];
        //獲取彈出元素周邊結(jié)點(diǎn)數(shù)組(無自身,不越界)
        NSArray *array = [QSAroundMines getAroundMinesArrayByItem:itemInQueue graph:graph];
        for (QSItem *itemInArray in array) {
            //遍歷過 或 雷 或 打開了 則跳過
            if (itemInArray.isTraveled == YES || itemInArray.isMine == YES || itemInArray.isOpened == YES){
                continue;
            }
            //周邊雷數(shù)為0則加入隊(duì)列
            if (itemInArray.arroundMineNumber == 0) {
                itemInArray.opened = YES;
                itemInArray.traveled = YES;
                [queue insertValueAtTailOfQueue:itemInArray];
            }
            //周邊雷數(shù)不為0,不加入隊(duì)列,但設(shè)置為遍歷過,并打開
            else{
                itemInArray.opened = YES;
                itemInArray.traveled = YES;
            }
        }//for
    }//while
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市堪置,隨后出現(xiàn)的幾起案子躬存,更是在濱河造成了極大的恐慌,老刑警劉巖舀锨,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岭洲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坎匿,警方通過查閱死者的電腦和手機(jī)盾剩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來替蔬,“玉大人告私,你說我怎么就攤上這事〕星牛” “怎么了驻粟?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)快毛。 經(jīng)常有香客問我格嗅,道長(zhǎng)番挺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任屯掖,我火速辦了婚禮玄柏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贴铜。我一直安慰自己粪摘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布绍坝。 她就那樣靜靜地躺著徘意,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轩褐。 梳的紋絲不亂的頭發(fā)上椎咧,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音把介,去河邊找鬼勤讽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拗踢,可吹牛的內(nèi)容都是我干的脚牍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼巢墅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼诸狭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起君纫,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤驯遇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后庵芭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妹懒,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年双吆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了眨唬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡好乐,死狀恐怖匾竿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔚万,我是刑警寧澤岭妖,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響昵慌,放射性物質(zhì)發(fā)生泄漏假夺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一斋攀、第九天 我趴在偏房一處隱蔽的房頂上張望已卷。 院中可真熱鬧,春花似錦淳蔼、人聲如沸侧蘸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讳癌。三九已至,卻和暖如春存皂,著一層夾襖步出監(jiān)牢的瞬間晌坤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工旦袋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泡仗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓猜憎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親搔课。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胰柑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容