使用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)


相关推荐

  • spssk均值聚类报告_K均值聚类

    spssk均值聚类报告_K均值聚类机器学习中的k均值聚类属于无监督学习,所谓k指的是簇类的个数,也即均值向量的个数。算法初始状态下,要根据我们设定的k随机生成k个中心向量,随机生成中心向量的方法既可以随机从样本中抽取k个样本作为中心向量,也可以将中心向量固定在样本的维度范围之内,避免中心向量过偏远离大多数样本点。然后每个样本点需要与k个中心向量分别计算欧氏距离,取欧氏距离最小的中心向量作为该样本点的簇类中心,当第一轮迭代完成之后,…

    2022年10月28日
  • freemarker 教程_freemarker自定义标签

    freemarker 教程_freemarker自定义标签FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java等。页面的静态化有的较多中的注释都是以#号表示的第一个项目结构代码的实现[java…

  • c++ listnode 赋值_C++之ListNode[通俗易懂]

    单链表,弄清楚可stl中list的区别。ListNode的结构structListNode{intval;//当前结点的值ListNode*next;//指向下一个结点的指针ListNode(intx):val(x),next(NULL){}//初始化当前结点值为x,指针为空};如何向ListNode中插入新的结点:从键盘输入ListNode*temp1=new…

  • Flashfxp 3.4的注册码

    Flashfxp 3.4的注册码FLASHFXP0wC2kbML0wAAAADEW5MNJwTnsl790jgG5F4CTA4jUAdMi66HHqFbShaEpEGXzjtFkAERmtW1wZmK/Vr9KMEMtWcIOXrEECP9avIvc1nfQxdTWr1V4KCB3zPf2djj/s4+66IIFDE2TtaVk88VxI1JlVz+7GX4vCjZhDeN2zwKOnKYnwEHVbXs4S06bzpo7kJ…

  • vue的双向绑定原理_数据双向绑定原理

    vue的双向绑定原理_数据双向绑定原理Vue双向绑定原理入门双向绑定概念数据可观测依赖收集完整示例总结从开始学习前端到现在走在进入中高级前端开发的路上,觉得上手容易又简单的就是Vue框架,包含其相关的生态系统。一直只是简单了解双向绑定的原理,并没有手动去实现或者去拜读过源码。而vue双向绑定基本是面试必考项,通过这段时间的学习,输出以下双向绑定的简单实现示例。参考文章:通俗易懂了解Vue双向绑定原理及实现双向绑定概念概念:…

  • sql模糊查询 like[通俗易懂]

    sql模糊查询 like[通俗易懂]like经常与where字句和通配符在一块进行使用,表示像啥啥,模糊查询通配符主要是_和%  %百分号表示零个,一个或多个字符  _下划线表示单个字符**注意:**1、MSAccess使用问号(?)而不是下划线(_)2、百分号和下划线也可以组合使用!   3、可以使用AND或OR运算符组合任意数量的条件语法:select*from表名where字段…

发表回复

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

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