使用cocos2d 2.1制作一条河游戏(4): 主要的游戏逻辑BaseLayer设计[通俗易懂]

使用cocos2d 2.1制作一条河游戏(4): 主要的游戏逻辑BaseLayer设计

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

前段时间一直忙着。没有时间更新博客。今天,仍然需要一段时间才能实现对游戏的一小部分,最后打动他。

BaseLayer.h:

#import <GameKit/GameKit.h>
#import "cocos2d.h"

#import "AppDelegate.h"
#import "PersonSprite.h"
#import "PriestSprite.h"
#import "DevilSprite.h"
#import "BoatSprite.h"
#import "BankSprite.h"

@interface BaseLayer : CCLayer <MoveSpriteDelegate>

@property (strong,nonatomic) BankSprite* rightBank;
@property (strong,nonatomic) BankSprite* leftBank;

@property (strong,nonatomic) BoatSprite* boat;

@property (assign,nonatomic) int time;      //set the timer

+(CCScene *) scene;

@end


记得在(2)讲PersonSprite的时候讲过,我们须要BaseLayer来取代PersonSprite来移动图层上的精灵。

因此我们在BaseLayer头文件定义的时候就须要遵守MoveSpriteDelegate协议了。(忘记了的能够翻回文章(2)看一下详细细节)看看BaseLayer的类成员。

一共同拥有两个河岸和一条船,另一个整数记录剩余时间。因为BaseLayer并不须要开放变量给其它类使用。所以这些河岸对象和船的定义放在头文件中还是实现文件中的匿名类别区域里面关系都不大。

我把这几个类成员放在这里是想将整个游戏的框架表示得清晰一些。严格地来说,放在.m文件的扩展类别区域更为安全。

有人可能会问:“为什么不把6个过河的人也定义在头文件中呢?”事实上我觉得这样做也是能够的。仅仅是由于考虑到BaseLayer对人和船、河岸的处理是不一样的:对于人来说,BaseLayer是通过代理的形式操作人的。即当玩家点击某个人的时候,事件从该人相应的PersonSprite对象開始传递,而PersonSprite通过delegate的形式交由BaseLayer来实现。在delegate參数传递的过程中,BaseLayer是知道哪个人产生了事件的(能够类比一下UIButton,当点击button产生事件的时候,Controller接收到事件时是能够知道由哪个button被按下导致触发了事件的)。

故对于BaseLayer来说。须要使用到PersonSprite的情况仅仅有:1. 对PersonSprite的初始化; 2. 调用托付函数moveSprite。所以并不须要把PersonSprite也作为成员变量;而对于船来说,由于其是由BaseLayer直接操纵的(控制船的移动),故在BaseLayer中会有多个函数使用到BoatSprite的对象。因此将BoatSprite设置为BaseLayer的成员变量更为方便。BankSprite同理。

来到.m文件,首先看一下静态变量以及扩展类别的声明:

#import "BaseLayer.h"
#import "PublicArg.h"
#import  "SimpleAudioEngine.h"
#include "AI.h"

static NSString *PRIEST_IMAGE_NAME = @"priest.png";
static NSString *DEVIL_IMAGE_NAME =  @"devil.png";
static NSString *BOAT_IMAGE_NAME = @"boat.png";
static NSString *BACKGROUND_IMAGE_NAME = @"background.jpg";
static NSString *WATER_IMAGE_NAME = @"water.png";

static NSString *BG_MUSIC = @"background.mp3";
static NSString *CLICK_EFF = @"click.mp3";
static NSString *FAIL_EFF = @"fail.mp3";
static NSString *PERSON_EFF = @"person.mp3";
static NSString *WATER_EFF = @"water.wav";
static NSString *WIN_EFF = @"win.mp3";

static int timeLimit = 200;         //set the time limit

@interface BaseLayer()

@property (strong,nonatomic) AppController *delegate;

//list the items here because the title would be changed
@property CCMenuItem *beginItem;
@property CCMenuItem *helpItem;
@property CCMenuItem *pauseItem;
@property CCMenuItem *resumeItem;
@property CCMenuItem *endItem;
@property CCMenuItem *transitItem;
@property CCLabelTTF *timeShow;

@property CCMenu *goMenu;
@property CCMenu *systemMenu;

@property CCSprite *water;

@end

静态变量中设置的都是图片的地址以及倒计时的总时长。而类别扩展中我定义了一些button成员变量。这些就是游戏中的菜单。

因为点击不同选项的时候有可能造成其它选项的转台变化(如点击暂停的时候,helpbutton应该是不可用的),所以我将这些button都放到成员变量中统一管理。注意到最后另一个water的sprite对象,这个是画面中在船上面的水图层,用来遮挡船的下沿。让效果更逼真一些。

看看几个初始化函数:

+(CCScene *) scene
{
	CCScene *scene = [CCScene node];
	BaseLayer *layer = [BaseLayer node];
	
	[scene addChild: layer];

	return scene;
}

//initialize instance
-(id) init
{
	if( (self=[super init]) ) {
        
        //initiate the game state
        _delegate = [[UIApplication sharedApplication] delegate];
        _delegate.gameState = BeforeGame;
        _delegate.screenSize = [[CCDirector sharedDirector] winSize];
        
        //initiate the public arguments
        [PublicArg sharedArg];
        
        //set the background image which is also a sprite
        CCSprite *background = [CCSprite spriteWithFile:BACKGROUND_IMAGE_NAME];
        [background setScale:0.5f];
        [background setPosition:ccp(_delegate.screenSize.width/2, _delegate.screenSize.height/2)];
        [self addChild:background];
        [self initMenu];
        
        //preload the background music & effects
        //[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:BG_MUSIC];
        //[[SimpleAudioEngine sharedEngine] preloadEffect:CLICK_EFF];
        //[[SimpleAudioEngine sharedEngine] preloadEffect:FAIL_EFF];
        //[[SimpleAudioEngine sharedEngine] preloadEffect:PERSON_EFF];
        //[[SimpleAudioEngine sharedEngine] preloadEffect:WATER_EFF];
        //[[SimpleAudioEngine sharedEngine] preloadEffect:WIN_EFF];
	}
	return self;
}

-(void)initSprites
{
    //set the 2 banks & 6 persons
    _rightBank = [[BankSprite alloc] initWithSide:Right];    //start place
    _leftBank = [[BankSprite alloc]initWithSide:Left];       //end place
    
    _rightBank.tag = 101;
    _leftBank.tag = 100;
    
    [self addChild:_rightBank];
    [self addChild:_leftBank];
    
    for(int i = 0;i<3;++i)
    {
        PriestSprite *temp_priest = [PriestSprite initPriestWithFile:PRIEST_IMAGE_NAME withNumber:i];
        DevilSprite *temp_devil = [DevilSprite initDevilWithFile:DEVIL_IMAGE_NAME withNumber:i];
        
        temp_priest.delegate = self;
        temp_devil.delegate = self;
        
        temp_priest.tag = i;
        temp_devil.tag = i + 3;
        
        [self addChild:temp_priest];
        [self addChild:temp_devil];
    }
   
    //set the boat
    _boat = [BoatSprite initBoatWithFile:BOAT_IMAGE_NAME];
    [self addChild:_boat];
    
    //set the water
    _water = [CCSprite spriteWithFile:WATER_IMAGE_NAME];
    [_water setScale:0.5];
    [_water setPosition:ccp(_delegate.screenSize.width/2-40, _delegate.screenSize.height/2)];
    [self addChild:_water];
}

-(void)initMenu
{
    //set the menu list
    [CCMenuItemFont setFontSize:28];
    
    _beginItem = [CCMenuItemFont itemWithString:@"Start" target:self selector:@selector(beginGame)];
    _helpItem = [CCMenuItemFont itemWithString:@"Help" target:self selector:@selector(help)];
    _pauseItem = [CCMenuItemFont itemWithString:@"Pause" target:self selector:@selector(pauseGame)];
    _resumeItem = [CCMenuItemFont itemWithString:@"Resume" target:self selector:@selector(resumeGame)];
    _endItem = [CCMenuItemFont itemWithString:@"End" target:self selector:@selector(endGame)];
    
    _systemMenu = [CCMenu menuWithItems:_beginItem, _pauseItem, _resumeItem, _endItem, _helpItem, nil];
    [_systemMenu alignItemsHorizontallyWithPadding:45.0];
    [_systemMenu setPosition:ccp( _delegate.screenSize.width/2 , _delegate.screenSize.height/2 + 100)];
    [self addChild:_systemMenu];
    
    _transitItem = [CCMenuItemFont itemWithString:@"Go" target:self selector:@selector(transit)];
    [_transitItem setColor:ccc3(0, 0, 0)];
    [_transitItem setVisible:NO];
    
    _goMenu = [CCMenu menuWithItems:_transitItem, nil];
    [_goMenu setPosition:ccp( _delegate.screenSize.width/2 , _delegate.screenSize.height/2 +10)];
    [self addChild:_goMenu];
    
    //set the items
    [_resumeItem setIsEnabled:NO];
    [_endItem setIsEnabled:NO];
    [_pauseItem setIsEnabled:NO];
    [_helpItem setIsEnabled:NO];
    
    //set the time shower
    _timeShow = [[CCLabelTTF alloc] init];
    [_timeShow setFontName:@"Marker Felt"];
    [_timeShow setPosition:ccp(_delegate.screenSize.width/2, _delegate.screenSize.height/2 + 50)];
    [_timeShow setFontSize:24.0f];
    [self addChild:_timeShow];
}

顺带打开AppDelegate.h:

#import <UIKit/UIKit.h>
#import "cocos2d.h"

typedef enum
{
    Left = 100,Right = 101,BOAT = 102
} Side;

//list out the game state
typedef enum
{
    BeforeGame,     //state: before game start
    InGame,         //state: game running
    BlockGame,      //state: boat is moving the nothing can be done
    PauseGame,      //state: game pause
    EndGame         //state: game end
} GameState;

// Added only for iOS 6 support
@interface MyNavigationController : UINavigationController <CCDirectorDelegate>
@end

@interface AppController : NSObject <UIApplicationDelegate>
{
	UIWindow *window_;
	MyNavigationController *navController_;

	CCDirectorIOS	*__unsafe_unretained director_;							// weak ref
}

@property (nonatomic, strong) UIWindow *window;
@property (readonly) MyNavigationController *navController;
@property (unsafe_unretained, readonly) CCDirectorIOS *director;

@property (assign,nonatomic) CGSize screenSize;         //the screen size
@property (assign,nonatomic) GameState gameState;       //game state

@end

Scene函数是BaseLayer的初始化函数:首先建立一个新的场景。然后向场景中增加BaseLayer布景。大多数Layer都有Scene这个函数,这个是由系统自己主动生成的。在init函数中,初始化了delegate变量。

delegate是AppDelegate的单例。

在AppDelegate的头文件里,我们能够知道它记录了游戏的状态和屏幕大小。由于这些是与游戏总体有关的变量,所以放在了全局的AppDelegate中,并在BaseLayer中使用delegate对其进行引用。之后创建了一个background对象并增加到布景中。同一时候初始化菜单以及计时器。在initSprite方法中,我们初始化了6个人而且分别以tag值0到5记录他们。

这是为后面将其放在岸上的指定位置做准备的。

接下来看看代理方法moveSprite的实现:

#pragma mark MoveSprite Delegate
-(void)moveSprite:(PersonSprite *)sprite
{
    if (_delegate.gameState != InGame)
        return;
    
    //[[SimpleAudioEngine sharedEngine]playEffect:PERSON_EFF];
    
    PublicArg *arg = [PublicArg sharedArg];
    
    switch (sprite.personSide) {
        case Left: case Right:     //person is on the left
        {
            //when person and boat are at different side
            if ( (sprite.personSide == Left && _boat.boatSide == Right) ||
                (sprite.personSide == Right && _boat.boatSide == Left))
                return;
            
        
            //go on the boat
            switch (_boat.priestNumber + _boat.devilNumber ) {
                case 0:
                {
                    [sprite setPosition:ccp(_boat.position.x-20, _boat.position.y+25)];
                    [_boat.personList addObject:sprite];
                    break;
                }
                case 1:
                {
                    [_boat.personList addObject:sprite];
                    PersonSprite *temp = [_boat.personList objectAtIndex:0];
                    [sprite setPosition:ccp(2 * _boat.position.x - temp.position.x, _boat.position.y+25)];
                    break;
                }
                case 2:  return;
            }

            if ([sprite isKindOfClass:[PriestSprite class]])
            {
                _boat.priestNumber++;
                BankSprite * temp_bamk = (BankSprite *)[self getChildByTag:sprite.personSide];
                temp_bamk.priestNumber --;
            }
            
            else if ([sprite isKindOfClass:[DevilSprite class]])
            {
                _boat.devilNumber++;
                BankSprite * temp_bamk = (BankSprite *)[self getChildByTag:sprite.personSide];
                temp_bamk.devilNumber --;
            }
            
            [sprite setPersonSide:BOAT];

            break;
        }
            
        case BOAT:      //person is on the boat
        {
            if ([sprite isKindOfClass:[PriestSprite class]])
            {
                if (_boat.boatSide == Left)
                {
                    [sprite setPosition:ccp(arg.priest_begin_left.x + sprite.number * arg.person_interval, arg.priest_begin_left.y )];
                    [sprite setPersonSide:Left];
                    _leftBank.priestNumber ++;
                }
                else if (_boat.boatSide == Right)
                {
                  [sprite setPosition:ccp(arg.priest_begin_right.x + sprite.number * arg.person_interval, arg.priest_begin_right.y )];
                  [sprite setPersonSide:Right];
                  _rightBank.priestNumber ++;

                }
                _boat.priestNumber--;
            }
            else if ([sprite isKindOfClass:[DevilSprite class]])
            {
                if (_boat.boatSide == Left)
                {
                    [sprite setPosition:ccp(arg.devil_begin_left.x + sprite.number * arg.person_interval, arg.devil_begin_left.y )];
                    [sprite setPersonSide:Left];
                    _leftBank.devilNumber++;
                }
                else if (_boat.boatSide == Right)
                {
                    [sprite setPosition:ccp(arg.devil_begin_right.x + sprite.number * arg.person_interval, arg.devil_begin_right.y )];
                    [sprite setPersonSide:Right];
                    _rightBank.devilNumber ++;
                }
                _boat.devilNumber--;
            }
            
            [_boat.personList removeObject:sprite];
            if([self judgeWin])
            {
                [[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
                [[SimpleAudioEngine sharedEngine]playEffect:WIN_EFF];
                [_timeShow setString:@"Win!"];
                [_timeShow setColor:ccc3(255.0, 215.0, 0.0)];
                _delegate.gameState = EndGame;
                [self clearItem];
            }
            break;
        }
    }
    
    //set the go button according to the number of persons on the boat
    if (_boat.priestNumber + _boat.devilNumber > 0) [_transitItem setIsEnabled:YES];
    else                                            [_transitItem setIsEnabled:NO];
}

当游戏不是在“游戏中”状态时(InGame),点击精灵应当不会响应。这个非常easy理解。最重要的是理解一下moveSprite究竟会面对哪些情况,以及在每种情况下做了什么事情:当玩家点击一个牧师/魔鬼的时候。这人有可能在船上。也有可能在岸上。于是我们分下面情况讨论:

1. 当人在岸上时。上船的时候要推断船上有没有人。来决定人在船上的位置。(避免在船上出现人物重叠的情况)

2. 当人在船上时。查看船在哪个岸边。然后将人物放上去就可以。

接下来是船过河的函数,比較简单,仅仅需改变船的side属性,然后对船和船上的人都设置移动就可以。

-(void)transit
{
    if (_boat.priestNumber + _boat.devilNumber == 0)    return;
    
    [[SimpleAudioEngine sharedEngine]playEffect:WATER_EFF];
    _delegate.gameState = BlockGame;     // sprites can not be moved
    [_transitItem setIsEnabled:NO];
    [_helpItem setIsEnabled:NO];
    
    int moveDis = 0;
    
    if (_boat.boatSide == Right)
    {
        moveDis = -160;
        _boat.boatSide = Left;
    }
    else if (_boat.boatSide == Left)
    {
        moveDis = 160;
        _boat.boatSide = Right;
    }
    
    CCMoveBy *move = [CCMoveBy actionWithDuration:1.0 position:ccp(moveDis, 0)];
    id clear = [CCCallFunc actionWithTarget:self selector:@selector(clear)];
    [_boat runAction:[CCSequence actions:move,clear, nil]];
    
    //move the persons on the boat
    for(int i = 0;i< _boat.priestNumber + _boat.devilNumber ;++i)
    {
        CCMoveBy *myMove =[CCMoveBy actionWithDuration:1.0 position:ccp(moveDis, 0)];
        PersonSprite *sprite = [_boat.personList objectAtIndex:i];
        [sprite runAction:myMove];
    }
}

推断成功与失败的函数:

-(BOOL)judgeWin{    if (_leftBank.priestNumber == 3 && _leftBank.devilNumber == 3)        return true;    return false;}-(BOOL)judgeLose{    int leftPriestNumber = _leftBank.priestNumber + abs(_boat.boatSide - Right) * _boat.priestNumber;    int rightPriestNumber = _rightBank.priestNumber + abs(_boat.boatSide - Left) * _boat.priestNumber;        int leftDevilNumber = _leftBank.devilNumber + abs(_boat.boatSide - Right) * _boat.devilNumber;    int rightDevilNumber = _rightBank.devilNumber + abs(_boat.boatSide - Left) * _boat.devilNumber;        if ( (leftDevilNumber > leftPriestNumber && leftPriestNumber > 0 ) ||         (rightDevilNumber > rightPriestNumber && rightPriestNumber >0))        return true;}

用于游戏状态转换的函数(開始、暂停、结束、继续等)

-(void)beginGame{    //play background music    [[SimpleAudioEngine sharedEngine] playBackgroundMusic:BG_MUSIC loop:YES];    [[SimpleAudioEngine sharedEngine]playEffect:CLICK_EFF];        _delegate.gameState = InGame;        [self initTimer:timeLimit];    [self schedule:@selector(updateTimeDisplay) interval:1];        [_beginItem setIsEnabled:NO];    [_pauseItem setIsEnabled:YES];    [_endItem setIsEnabled:YES];    [_helpItem setIsEnabled:YES];        [_transitItem setVisible:YES];    [_transitItem setIsEnabled:NO];        [_timeShow setColor:ccc3(255.0f, 255.0f, 255.0f)];        NSString *time = [NSString stringWithFormat:@"%.2d:%.2d", _time / 60, _time % 60];    [_timeShow setString:time];        [self removePreviousSprite];    [self initSprites];}-(void)pauseGame{    [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];     [[SimpleAudioEngine sharedEngine]playEffect:CLICK_EFF];        _delegate.gameState = PauseGame;    [self unschedule:@selector(updateTimeDisplay)];        [_resumeItem setIsEnabled:YES];    [_pauseItem setIsEnabled:NO];    [_helpItem setIsEnabled:NO];    [_transitItem setVisible:NO];}-(void)resumeGame{    [[SimpleAudioEngine sharedEngine] resumeBackgroundMusic];    [[SimpleAudioEngine sharedEngine]playEffect:CLICK_EFF];        _delegate.gameState = InGame;        [_resumeItem setIsEnabled:NO];    [_pauseItem setIsEnabled:YES];    [_helpItem setIsEnabled:YES];    [_transitItem setVisible:YES];        [self schedule:@selector(updateTimeDisplay) interval:1];}-(void)endGame{    [[SimpleAudioEngine sharedEngine]stopBackgroundMusic];    [[SimpleAudioEngine sharedEngine]playEffect:CLICK_EFF];        _delegate.gameState = EndGame;        [self clearItem];    [self setTime:0];        NSString *time = [NSString stringWithFormat:@"%.2d:%.2d",_time / 60, _time % 60];    [_timeShow setString:time];        [self clearGame];}

清空屏幕上的sprites,用于一场游戏结束后清空屏幕上元素,避免内存泄露。

-(void)clearItem{    [_resumeItem setIsEnabled:NO];    [_endItem setIsEnabled:NO];    [_pauseItem setIsEnabled:NO];    [_beginItem setIsEnabled:YES];    [_helpItem setIsEnabled:NO];    [_transitItem setVisible:NO];        [self unschedule:@selector(updateTimeDisplay)];}-(void)clear{    _delegate.gameState = InGame;     // sprites can not be moved    [_transitItem setIsEnabled:YES];    [_helpItem setIsEnabled:YES];        if([self judgeLose])    {        [[SimpleAudioEngine sharedEngine] stopBackgroundMusic];        [[SimpleAudioEngine sharedEngine]playEffect:FAIL_EFF];        _delegate.gameState = EndGame;                [_timeShow setString:@"Lose!"];        [_timeShow setColor:ccc3(255.0, 0.0, 0.0)];        _delegate.gameState = EndGame;        [self clearItem];    }}//remove the sprites of last scene-(void)removePreviousSprite{    for(int i = 0;i<6;++i)    {        PersonSprite *temp = (PersonSprite *)[self getChildByTag:i];        if (temp != NULL) [self removeChildByTag:i];    }    if (_boat != NULL)      [self removeChild:_boat];    if (_rightBank != NULL) [self removeChild:_rightBank];    if (_leftBank != NULL)  [self removeChild:_leftBank];    if (_water != NULL)     [self removeChild:_water];}-(void)clearGame{    //change to a new scene    [[CCDirector sharedDirector]replaceScene:[BaseLayer scene]];}

其它辅助函数:

-(void)updateTimeDisplay{    _time--;    NSString *time = [NSString stringWithFormat:@"%.2d:%.2d",_time / 60, _time % 60];    [_timeShow setString:time];        if (_time <= 0)        [self endGame];}-(void)initTimer:(int)interval{    _time = interval;}

最后是help函数。

help功能主要做的是依据当前游戏中人物的位置,自己主动为玩家走下一步。算是一种比較简单的决策的体现吧。原理非常easy。就是找出一条能通关的路径,然后把各种合理的游戏状态连接到路径上,即设置一个有限状态机,储存路径图,给定输入和当前状态后,系统便能算出下一个状态。

help函数:

-(void)help{    [[SimpleAudioEngine sharedEngine]playEffect:CLICK_EFF];    int leftPriestNumber = _leftBank.priestNumber + abs(_boat.boatSide - Right) * _boat.priestNumber;    int rightPriestNumber = _rightBank.priestNumber + abs(_boat.boatSide - Left) * _boat.priestNumber;        int leftDevilNumber = _leftBank.devilNumber + abs(_boat.boatSide - Right) * _boat.devilNumber;    int rightDevilNumber = _rightBank.devilNumber + abs(_boat.boatSide - Left) * _boat.devilNumber;        int boatSide = _boat.boatSide - 100;        int deltaPriest = 0, deltaDevil = 0;        getHelp(leftPriestNumber,leftDevilNumber,rightPriestNumber,rightDevilNumber,boatSide,deltaPriest,deltaDevil);        int tempNum = _boat.priestNumber + _boat.devilNumber;    for(int i = 0;i< tempNum ; ++i)        [self moveSprite:[_boat.personList objectAtIndex:0]];    int i = 0;        while (deltaPriest > 0) {            PriestSprite *mySprite = (PriestSprite *)[self getChildByTag:i];        if (mySprite.personSide == _boat.boatSide)        {            [self moveSprite:mySprite];            deltaPriest --;        }        i++;    }        i = 3;    while (deltaDevil > 0) {                DevilSprite *mySprite = (DevilSprite *)[self getChildByTag:i];        if (mySprite.personSide == _boat.boatSide)        {            [self moveSprite:mySprite];            deltaDevil --;        }        i++;    }    [self transit];}

这里调用的是一个AI.cpp文件。cpp文件里储存了路径。

AI.h:

#ifndef RiverCrossing_AI_h#define RiverCrossing_AI_hstruct state{    int boat_side;    int left_pastor;    int left_devil;    int right_pastor;    int right_devil;};////void initWays(int * ways);//int  hash(state s);//state deHash(int key);//void change(state now,state next,//            int & pastor,int & devil);/* input:state boat_side(0=left,1=right) return:void */void getHelp (int left_pastor,int left_devil, int right_pastor,int right_devil, int boat_side,int& pastor,int &devil);#endif

AI.cpp:

#include "AI.h"#include<iostream>#include<cmath>using namespace std;void initWays(int * ways){  ways[10033]=231;  ways[231]=10132;  ways[10132]=330;  ways[330]=10231;  ways[10231]=2211;  ways[2211]=11122;  ways[11122]=3102;  ways[3102]=13003;  ways[13003]=3201;  ways[3201]=13102;  ways[13102]=3300;  ways[3300] = 3300;      ways[1122]=10132;  ways[132]=10033;}int  hash(state s){  int key;  key=s.boat_side*10000+s.left_pastor*1000+s.left_devil*100+s.right_pastor*10+s.right_devil;  return key;}state deHash(int key){  int boat_side=key/10000;  int left_pastor=key%10000/1000;  int left_devil=key%1000/100;  int right_pastor=key%100/10;  int right_devil=key%10;  struct state s={boat_side,left_pastor,left_devil,right_pastor,right_devil};  return s;}void change(state now,state next,            int & pastor,int & devil){  pastor=abs(now.left_pastor-next.left_pastor);  devil=abs(now.left_devil-next.left_devil);}/*input:state      boat_side(0=left,1=right)return:void */void getHelp(int left_pastor,int left_devil,             int right_pastor,int right_devil,             int boat_side,             int & pastor,int & devil){  int ways[13334];  initWays(ways);  struct state now={boat_side,left_pastor,left_devil,right_pastor,right_devil};  int now_state_key=hash(now);  int next_state_key=ways[now_state_key];      struct state next=deHash(next_state_key);  change(now,next,pastor,devil);}

特别说明,在.m编译文件cpp文件。需要.m该后缀.mm工作。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/116678.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • pycharm无法使用第三方库_python第三方库安装失败

    pycharm无法使用第三方库_python第三方库安装失败前言:在使用pycharm学习python的时候,经常需要第三方库,没有第三方库程序就会报错,pycharm也会提醒你要安装所需要的库,安装第三方库的时候往往就出现了问题,如图;下面我将谈谈一些我遇到的问题及解决经验。1.检查pip是否为最新版本pip不是最新版本时,会直接导致你安装第三方库失败。解决方法:第一,看是否直接在pycharm的setting里面Project下的Projec…

  • Word2Vec原理简单解析

    Word2Vec原理简单解析前言词的向量化就是将自然语言中的词语映射成是一个实数向量,用于对自然语言建模,比如进行情感分析、语义分析等自然语言处理任务。下面介绍比较主流的两种词语向量化的方式: 第一种即One-Hot编码是一种基于词袋(bagofwords)的编码方式。假设词典的长度为N即包含N个词语,并按照顺序依次排列。One-Hot编码将词语表示成长度为N的向量,每一向量分量代表词典中的一个词语,则One-Hot编码的词语向量只有一位分量值为1。假设词语在词典中的位置为k,那么该词语基于One-

  • sqlmap命令详解pdf_SQLmap

    sqlmap命令详解pdf_SQLmapsqlmap命令详解目录0x01sqlmap确定目标1.1直连数据库1.2URL探测1.3文件读取目标1.4Google批量扫描注入0x02sqlmap请求参数设置(一)2.1设置HTTP方法2.2设置POST提交参数2.3设置参数分割符2.4设置Cookie头2.5设置User-Agent头2.6设置Host头2.7设置Referer头2.8设置额外HTTP头2.9设置HTTP协议认证2.10设置HTTP代理0x03sql

    2022年10月22日
  • adb的工作原理

    adb的工作原理

  • linux修改文件名字

    linux修改文件名字linux下重命名文件或文件夹使用mv既可实现。例子:①将一个名为abc.txt的文件重命名为1234.txt[root@station90root]#mvabc.txt1234.txt

  • 记忆化搜索(递归)讲解「建议收藏」

    记忆化搜索(递归)讲解「建议收藏」记忆化搜索

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号