void AI::debug() { Player human = (this->player == CROSS ? NOUGHT : CROSS); std::cout << std::endl << ":::::::DEBUG::::::" << std::endl; for (int i=0; i<BOARD_SIZE; i++) { for (int j=0; j<BOARD_SIZE; j++) { Position position = MakePosition(i, j); std::cout << "Position (" << i << "," << j << "):" << std::endl; std::cout << "\tAI:" << std::endl; std::map<Direction, int> & aiWeights = this->weightsAtPositionForPlayer(position, this->player); for (std::map<Direction, int>::iterator it=aiWeights.begin(); it!=aiWeights.end(); ++it) { std::cout << "\t\t" << DirectionName(it->first) << ": " << it->second << std::endl; } std::cout << "\tHuman:" << std::endl; std::map<Direction, int> & humanWeights = this->weightsAtPositionForPlayer(position, human); for (std::map<Direction, int>::iterator it=humanWeights.begin(); it!=humanWeights.end(); ++it) { std::cout << "\t\t" << DirectionName(it->first) << ": " << it->second << std::endl; } } } std::cout << std::endl; }
bool Board::isFinished(Player &winner) const { bool finished = false; int row = 0; while (row < BOARD_SIZE && !finished) { int column = 0; while (column < BOARD_SIZE && !finished) { Position pos = MakePosition(row, column); Box &box = this->boxAtPosition(pos); if (box.isOccupied()) { const Player &player = box.getPlayer(); int nDirections; Direction *directions = this->getDirectionsToCheckForPosition(pos, nDirections); int i = 0; while (i < nDirections && !finished) { Direction nextDirection = directions[i]; bool samePlayer = true; Position nextPos = MovePosition(pos, nextDirection); while (this->positionIsValid(nextPos) && samePlayer) { Box &box = this->boxAtPosition(nextPos); samePlayer = (box.isOccupied() && box.getPlayer() == player); nextPos = MovePosition(nextPos, nextDirection); } finished = (samePlayer); if (finished) { winner = player; } ++i; } delete [] directions; } ++column; } ++row; } return finished; }
void AI::recalculateWeights() { Player humanPlayer = (this->player == CROSS ? NOUGHT : CROSS); for (int i=0; i<BOARD_SIZE; i++) { for (int j=0; j<BOARD_SIZE; j++) { Position position = MakePosition(i, j); int nDirectionsToCheck; Direction *directionsToCheck = this->board->getDirectionsToCheckForPosition(position, nDirectionsToCheck); int nextDirectionIndex = 0; while (nextDirectionIndex < nDirectionsToCheck) { Direction nextDirection = directionsToCheck[nextDirectionIndex]; std::map<Position, int> aiWeightsInCurrDirection = this->board->weightForBoxesFromPositionInDirectionForPlayer(position, nextDirection, this->player); this->applyWeightForBoxesFromPositionInDirectionAndPlayer(aiWeightsInCurrDirection, nextDirection, this->player); std::map<Position, int> humanWeightInCurrDirection = this->board->weightForBoxesFromPositionInDirectionForPlayer(position, nextDirection, humanPlayer); this->applyWeightForBoxesFromPositionInDirectionAndPlayer(humanWeightInCurrDirection, nextDirection, humanPlayer); ++nextDirectionIndex; } delete [] directionsToCheck; } } if (DEBUG > 1) { this->debug(); } }
void OvrSliderComponent::GetVerticalSliderParms( VRMenu & menu, VRMenuId_t const parentId, VRMenuId_t const rootId, imageInfo_t const & iconImage, imageInfo_t const & baseImage, imageInfo_t const & trackImage, imageInfo_t const & trackFullImage, imageInfo_t const & scrubberImage, imageInfo_t const & bubbleImage, VRMenuId_t const scrubberId, VRMenuId_t const bubbleId, VRMenuId_t const fillId, float const sliderFrac, float const minValue, float const maxValue, float const sensitivityScale, Array< VRMenuObjectParms const* > & parms ) { Vector3f const fwd( 0.0f, 0.0f, -1.0f ); Vector3f const right( 1.0f, 0.0f, 0.0f ); Vector3f const up( 0.0f, 1.0f, 0.0f ); float const BASE_FWD_OFFSET = 0.033f; float const FWD_INC = 0.01f; //float TRACK_UP_OFFSET = ( baseImage.h - trackImage.h - iconImage.h ) * 0.5f; // offset track just above the button image float TRACK_UP_OFFSET = ( baseImage.h * 0.5f ) - ( trackImage.h * 0.5f + iconImage.h ); // offset track just above the button image Vector3f const localSlideDelta( MakePosition( 0.0f, trackImage.h, 0.0f ) ); bool const vertical = true; // add parms for the root object that holds all the slider components { Array< VRMenuComponent* > comps; comps.PushBack( new OvrSliderComponent( menu, sliderFrac, localSlideDelta, minValue, maxValue, sensitivityScale, rootId, scrubberId, VRMenuId_t(), bubbleId, fillId ) ); Array< VRMenuSurfaceParms > surfParms; char const * text = "slider_root"; Vector3f scale( 1.0f ); Posef pose( MakePose( Quatf(), 0.0f, ( baseImage.h * 0.5f ) - ( iconImage.h * 0.5f ), 0.0f ) ); Posef textPose( Quatf(), Vector3f( 0.0f ) ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms; VRMenuObjectFlags_t objectFlags( VRMENUOBJECT_RENDER_HIERARCHY_ORDER ); VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_CONTAINER, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, rootId, objectFlags, initFlags ); itemParms->ParentId = parentId; parms.PushBack( itemParms ); } // add parms for the base image that underlays the whole slider { Array< VRMenuComponent* > comps; Array< VRMenuSurfaceParms > surfParms; VRMenuSurfaceParms baseParms( "base", GetSliderImage( baseImage, vertical ).ToCStr(), SURFACE_TEXTURE_DIFFUSE, NULL, SURFACE_TEXTURE_MAX, NULL, SURFACE_TEXTURE_MAX ); surfParms.PushBack( baseParms ); char const * text = "base"; Vector3f scale( 1.0f ); Posef pose( MakePose( Quatf(), BASE_FWD_OFFSET, 0.0f, 0.0f ) ); Posef textPose( Quatf(), Vector3f( 0.0f ) ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms; VRMenuObjectFlags_t objectFlags( VRMENUOBJECT_DONT_RENDER_TEXT ); objectFlags |= VRMENUOBJECT_FLAG_NO_DEPTH; VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_BUTTON, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, VRMenuId_t(), objectFlags, initFlags ); itemParms->ParentId = rootId; parms.PushBack( itemParms ); } // add parms for the track image { Array< VRMenuComponent* > comps; Array< VRMenuSurfaceParms > surfParms; VRMenuSurfaceParms baseParms( "track", GetSliderImage( trackImage, vertical ).ToCStr(), SURFACE_TEXTURE_DIFFUSE, NULL, SURFACE_TEXTURE_MAX, NULL, SURFACE_TEXTURE_MAX ); surfParms.PushBack( baseParms ); char const * text = "track"; Vector3f scale( 1.0f ); Posef pose( MakePose( Quatf(), BASE_FWD_OFFSET - FWD_INC * 1, -TRACK_UP_OFFSET, 0.0f ) ); Posef textPose( Quatf(), Vector3f( 0.0f ) ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms; VRMenuObjectFlags_t objectFlags( VRMENUOBJECT_DONT_RENDER_TEXT ); VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_BUTTON, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, VRMenuId_t(), objectFlags, initFlags ); itemParms->ParentId = rootId; parms.PushBack( itemParms ); } // add parms for the filled track image { Array< VRMenuComponent* > comps; Array< VRMenuSurfaceParms > surfParms; VRMenuSurfaceParms baseParms( "track_full", GetSliderImage( trackFullImage, vertical ).ToCStr(), SURFACE_TEXTURE_DIFFUSE, NULL, SURFACE_TEXTURE_MAX, NULL, SURFACE_TEXTURE_MAX ); surfParms.PushBack( baseParms ); char const * text = "track_full"; Vector3f scale( 1.0f ); Posef pose( MakePose( Quatf(), BASE_FWD_OFFSET - FWD_INC * 2, -TRACK_UP_OFFSET, 0.0f ) ); Posef textPose( Quatf(), Vector3f( 0.0f ) ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms; VRMenuObjectFlags_t objectFlags( VRMENUOBJECT_DONT_RENDER_TEXT ); VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_BUTTON, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, fillId, objectFlags, initFlags ); itemParms->ParentId = rootId; parms.PushBack( itemParms ); } // add parms for the scrubber { Array< VRMenuComponent* > comps; Array< VRMenuSurfaceParms > surfParms; VRMenuSurfaceParms baseParms( "scrubber", GetSliderImage( scrubberImage, vertical ).ToCStr(), SURFACE_TEXTURE_DIFFUSE, NULL, SURFACE_TEXTURE_MAX, NULL, SURFACE_TEXTURE_MAX ); surfParms.PushBack( baseParms ); char const * text = "scrubber"; Vector3f scale( 1.0f ); Posef pose( MakePose( Quatf(), BASE_FWD_OFFSET - FWD_INC * 3, -TRACK_UP_OFFSET, 0.0f ) ); Posef textPose( Quatf(), Vector3f( 0.0f ) ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms; VRMenuObjectFlags_t objectFlags( VRMENUOBJECT_DONT_RENDER_TEXT ); VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_BUTTON, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, scrubberId, objectFlags, initFlags ); itemParms->ParentId = rootId; parms.PushBack( itemParms ); } // add parms for the bubble { Array< VRMenuComponent* > comps; Array< VRMenuSurfaceParms > surfParms; VRMenuSurfaceParms baseParms( "bubble", GetSliderImage( bubbleImage, vertical ).ToCStr(), SURFACE_TEXTURE_DIFFUSE, NULL, SURFACE_TEXTURE_MAX, NULL, SURFACE_TEXTURE_MAX ); surfParms.PushBack( baseParms ); char const * text = NULL; Vector3f scale( 1.0f ); //Posef pose( Quatf(), right * ( trackImage.w + SLIDER_BUBBLE_CENTER ) + fwd * ( BASE_FWD_OFFSET - ( FWD_INC * 4 ) ) ); float const SLIDER_BUBBLE_CENTER = bubbleImage.w * 0.5f; Posef pose( MakePose( Quatf(), BASE_FWD_OFFSET - FWD_INC * 4, 0.0f , trackImage.w + bubbleImage.w * 0.5593f ) ); const float bubbleTextScale = 0.66f; const float bubbleTextCenterOffset = SLIDER_BUBBLE_CENTER - ( bubbleImage.w * 0.5f ); const Vector3f textPosition = right * bubbleTextCenterOffset; Posef textPose( Quatf(), textPosition ); Vector3f textScale( 1.0f ); VRMenuFontParms fontParms( HORIZONTAL_CENTER, VERTICAL_CENTER, false, false, true, bubbleTextScale ); VRMenuObjectFlags_t objectFlags; VRMenuObjectInitFlags_t initFlags( VRMENUOBJECT_INIT_FORCE_POSITION ); VRMenuObjectParms * itemParms = new VRMenuObjectParms( VRMENU_BUTTON, comps, surfParms, text, pose, scale, textPose, textScale, fontParms, bubbleId, objectFlags, initFlags ); itemParms->ParentId = scrubberId; parms.PushBack( itemParms ); } }
Posef MakePose( Quatf const & q, float const fwdDist, float const upDist, float const leftDist ) { return Posef( q, MakePosition( fwdDist, upDist, leftDist ) ); }
Position AI::nextMovement() { int aiBestWeight = INT_MAX; Position aiBestWeightPosition = MakePosition(0, 0); float aiBestMedianWeight = FLT_MAX; Position aiBestMedianWeightPosition = MakePosition(0, 0); int humanBestWeight = INT_MAX; Position humanBestWeightPosition; float humanBestMedianWeight = FLT_MAX; Position humanBestMedianWeightPosition; Player humanPlayer = (this->player == CROSS ? NOUGHT : CROSS); for (int i=0; i<BOARD_SIZE; i++) { for (int j=0; j<BOARD_SIZE; j++) { Position position = MakePosition(i, j); // We have to decide if to attack or to defend. // Let's see what is the best box to check for the AI and what is its // weight but also which will be the best one for the user. // We will make one of those 2 movements: the one with the lowest // weight. //ATTACK int currAIBestWeight; float currAIBestMedianWeight; bool aiAnySolution = this->getAttackInfoToBoxAtPositionForPlayer(position, this->player, currAIBestWeight, currAIBestMedianWeight); if (aiAnySolution) { bool change = ((currAIBestWeight < aiBestWeight) || ((currAIBestWeight == aiBestWeight) && rand()%2)); //let's add some random behaviour to make it harder to predict. if (change) { aiBestWeight = currAIBestWeight; aiBestWeightPosition = MakePosition(i, j); } change = ((currAIBestMedianWeight < aiBestMedianWeight) || ((fabsf(currAIBestMedianWeight - aiBestMedianWeight) < 0.01f) && rand()%2)); if (change) { aiBestMedianWeight = currAIBestMedianWeight; aiBestMedianWeightPosition = MakePosition(i, j); } } //DEFFEND int currHumanBestWeight; float currHumanBestMedianWeight; bool humanAnySolution = this->getAttackInfoToBoxAtPositionForPlayer(position, humanPlayer, currHumanBestWeight, currHumanBestMedianWeight); if (humanAnySolution) { bool change = ((currHumanBestWeight < humanBestWeight) || ((currHumanBestWeight == humanBestWeight) && rand()%2)); if (change) { humanBestWeight = currHumanBestWeight; humanBestWeightPosition = MakePosition(i, j); } change = ((currHumanBestMedianWeight < humanBestMedianWeight) || ((fabsf(currHumanBestMedianWeight-humanBestMedianWeight) < 0.0001f) && rand()%2)); if (change) { humanBestMedianWeight = currHumanBestMedianWeight; humanBestMedianWeightPosition = MakePosition(i, j); } } } } bool shouldTakeMiddlePosition = (!this->board->positionIsOccupied(MakePosition(BOARD_SIZE/2, BOARD_SIZE/2))); if (shouldTakeMiddlePosition) { switch (this->aiLevel) { case EASY: break; shouldTakeMiddlePosition = (rand()%3 == 0); case NORMAL: shouldTakeMiddlePosition = (rand()%2 == 0); break; default: break; } } Position pos; if (aiBestWeight == 1) { if (DEBUG) { std::cout << " 1st --> Attacking at best weight" << std::endl; } pos = aiBestWeightPosition; } else if (humanBestWeight == 1) { if (DEBUG) { std::cout << " 2nd --> Defending at best weight" << std::endl; } pos = humanBestWeightPosition; } else if (!this->board->positionIsOccupied(MakePosition(BOARD_SIZE/2, BOARD_SIZE/2))) { if (DEBUG) { std::cout << " 3rd --> Taking the middle position" << std::endl; } pos = MakePosition(BOARD_SIZE/2, BOARD_SIZE/2); } else if (humanBestMedianWeight < aiBestMedianWeight) { if (DEBUG) { std::cout << " 4th --> Defending at best median" << std::endl; } pos = humanBestMedianWeightPosition; } else { if (DEBUG) { std::cout << " 5th --> Attacking at best median" << std::endl; } pos = aiBestMedianWeightPosition; } this->board->setPlayerAtPosition(this->player, pos); return pos; }