float DifficultyAnalyzer::CalculateDifficulty(const vec3 &tee, const vec3 &target, vec3 &p1_adjusted, vec3 &p2_adjusted, float &distance) {
    /*
     See attached description of golf shot modelling.
     */
    
    distance = glm::length(target - tee);
    
    // Lift tee and target just slightly to avoid immediate collisions with ground
    vec3 adjustedTee = tee + vec3(0,0.1,0);
    vec3 adjustedTarget = target + vec3(0,0.1,0);;
    
    vec3 tee_to_target_xz = adjustedTarget - adjustedTee;
    tee_to_target_xz.y = 0;
    
    float L = length(tee_to_target_xz);
    float h = adjustedTarget.y - adjustedTee.y;

    // Steps when finding difficulty
    int heightSteps = 0;
    int curveSteps = 0;
    int comboSteps = 0; // combination of height and curve
    
    // We need to adjust height if target is to high for our initial approach
    float initialHeightDifficulty = 0; // Stems from having to hit high enough to reach the green
    float adjustedHeight = defaultShotHeight; // The new height of the golf shot
    if (h + heightPerStep > defaultShotHeight) {
        heightSteps = 1 + ceil((h - defaultShotHeight) / heightPerStep); // Increase heightSteps to get future height difficulty calculations right
        adjustedHeight += heightSteps * heightPerStep;
        initialHeightDifficulty = HeightDifficulty(heightSteps * heightPerStep); // Difficulty to add to curve difficulty
    }
    
    float l = ( L * adjustedHeight ) / ( adjustedHeight - h * (1 - p2_relative) );
    
    vec3 dir = normalize(tee_to_target_xz);
    vec3 up(0, 1, 0);
    vec3 right = cross(dir, up);
    
    const vec3 p1 = adjustedTee + dir * l * p1_relative + up * adjustedHeight;
    const vec3 p2 = adjustedTee + dir * l * p2_relative + up * adjustedHeight;
    
    // These will be adjusted as difficulty increases
    p1_adjusted = p1;
    p2_adjusted = p2;
    
    // Is path clear to begin with?
    if (PathIsClear(adjustedTee, p1, p2, adjustedTarget))
        return distance + HeightDifficulty(heightSteps * heightPerStep) + initialHeightDifficulty;
    
    while (true) {
        
        // Take next step depending on which is easiest.
        float heightDifficulty = distance + HeightDifficulty((heightSteps + 1) * heightPerStep);
        float curveDifficulty  = distance + CurveDifficulty((curveSteps + 1) * curvePerStep) + initialHeightDifficulty;
        float comboDifficulty  = distance + ComboDifficulty((comboSteps + 1) * comboPerStep, (comboSteps + 1) * comboPerStep);
        
        // If difficulty exceeded IMPOSSIBLE, indicate this bu returning -1
        if (heightDifficulty > IMPOSSIBLE && curveDifficulty > IMPOSSIBLE && comboDifficulty > IMPOSSIBLE)
            return -1;
        
        // Which approach offers the easiest shot?
        float minDifficulty = std::min(heightDifficulty, std::min(curveDifficulty, comboDifficulty));
        
        vec3 diff;
        if (minDifficulty == heightDifficulty) {
            
            heightSteps += 1;
            
            diff = up * (heightSteps * heightPerStep);
            p1_adjusted = p1 + diff;
            p2_adjusted = p2 + diff;
            if (PathIsClear(adjustedTee, p1_adjusted, p2_adjusted, adjustedTarget))
                return heightDifficulty;
            
        } else if (minDifficulty == curveDifficulty) {
            
            curveSteps += 1;
            
            // Try curve to the right (path curves left)
            diff = right * (curveSteps * curvePerStep);
            p1_adjusted = p1 + diff;
            p2_adjusted = p2 + diff;
            if (PathIsClear(adjustedTee, p1_adjusted, p2_adjusted, adjustedTarget))
                return curveDifficulty;
            
            // Try curve to the left (path curves right)
            diff = -right * (curveSteps * curvePerStep);
            p1_adjusted = p1 + diff;
            p2_adjusted = p2 + diff;
            if (PathIsClear(adjustedTee, p1_adjusted, p2_adjusted, adjustedTarget))
                return curveDifficulty;
            
            
            
        } else if (minDifficulty == comboDifficulty) {
            
            comboSteps += 1;
            
            // Try curve to the right (path curves left)
            diff = up * (comboSteps * heightPerStep) + right * (comboSteps * curvePerStep);
            p1_adjusted = p1 + diff;
            p2_adjusted = p2 + diff;
            if (PathIsClear(adjustedTee, p1_adjusted, p2_adjusted, adjustedTarget))
                return comboDifficulty;
            
            // Try curve to the left (path curves right)
            diff = up * (comboSteps * heightPerStep) - right * (comboSteps * curvePerStep);
            p1_adjusted = p1 + diff;
            p2_adjusted = p2 + diff;
            if (PathIsClear(adjustedTee, p1_adjusted, p2_adjusted, adjustedTarget))
                return comboDifficulty;
        }
    }
}
Exemplo n.º 2
0
int CNavigationPath::ComputePath (CSystem *pSystem, CSovereign *pSovereign, const CVector &vFrom, const CVector &vTo, int iDepth, CVector **retpPoints)

//	ComputePath
//
//	This is a recursive function that returns a set of points that define a safe path
//	between the two given points.
//
//	We return an allocated array of CVectors in retpPoints

	{
	int i;

	//	If we're very close to our destination, then the best option is a direct path
	//	If the path is clear, then a direct path is also the best option.

	CSpaceObject *pEnemy;
	CVector vAway;
	if (iDepth >= MAX_PATH_RECURSION
			|| ((vTo - vFrom).Length2() <= MAX_SAFE_DIST2)
			|| PathIsClear(pSystem, pSovereign, vFrom, vTo, &pEnemy, &vAway))
		{
		(*retpPoints) = new CVector;
		(*retpPoints)[0] = vTo;
		return 1;
		}

	//	Otherwise, we deflect the path at the enemy base and recurse for the
	//	two path segments.

	else
		{
		//	Compute the mid-point

		CVector vMidPoint = pEnemy->GetPos() + (AVOID_DIST * vAway);

		//	Recurse

		CVector *pLeftPoints;
		int iLeftCount = ComputePath(pSystem, pSovereign, vFrom, vMidPoint, iDepth+1, &pLeftPoints);

		CVector *pRightPoints;
		int iRightCount = ComputePath(pSystem, pSovereign, vMidPoint, vTo, iDepth+1, &pRightPoints);

		//	Compose the two paths together

		int iCount = iLeftCount + iRightCount;
		ASSERT(iCount > 0);
		(*retpPoints) = new CVector [iCount];

		int iPos = 0;
		for (i = 0; i < iLeftCount; i++)
			(*retpPoints)[iPos++] = pLeftPoints[i];

		for (i = 0; i < iRightCount; i++)
			(*retpPoints)[iPos++] = pRightPoints[i];

		delete [] pLeftPoints;
		delete [] pRightPoints;

		return iCount;
		}
	}
Exemplo n.º 3
0
/*
 * PieceCanMove:  Return True iff the piece at p1 can move to p2.
 *   Assumes that p1 contains a piece of the player's color.
 */
Bool PieceCanMove(Board *b, POINT p1, POINT p2, BYTE color)
{
   BYTE piece;
   Square *s2;
   int direction, dy;
   
   if (p1.x == p2.x && p1.y == p2.y)
      return False;

   piece = b->squares[p1.y][p1.x].piece;
   s2 = &b->squares[p2.y][p2.x];
   
   // First verify that piece can move this way
   switch (piece)
   {
   case PAWN:
      direction = (color == WHITE) ? 1 : -1;
      dy = p2.y - p1.y;
      
      // Make sure moving in the correct direction
      if (dy == 0 || abs(dy) > 2 || SGN(dy) != direction)
	 return False;
      
      // 3 cases:  capturing diagonally, moving straight ahead, or illegal move
      switch (abs(p2.x - p1.x))
      {
      case 0:
	 // If moving straight, can't capture
	 if (s2->piece != NONE)
	    return False;
	 break;
      case 1:
	 // Look for en passant capture
	 if (b->en_passant)
	 {
	    if (b->squares[p2.y - direction][p2.x].piece == PAWN &&
		b->squares[p2.y - direction][p2.x].color != color &&
		p2.x == b->passant_square.x &&
		p2.y == b->passant_square.y)
	       break;
	 }
	 
	 // If moving diagonally, must capture
	 if (s2->piece == NONE || s2->color == color)
	    return False;
	 break;
      default:
	 return False;
      }

      // Can only move 2 squares forward on first move
      if (abs(dy) == 2)
	 if ((color == WHITE && p1.y != 1) ||
	     (color == BLACK && p1.y != 6))
	    return False;
      break;
   case ROOK:
      if (p1.x != p2.x && p1.y != p2.y)
	 return False;
      break;
   case KNIGHT:
      if (abs(p2.x - p1.x) + abs(p2.y - p1.y) != 3)
	 return False;

      if (abs(p2.x - p1.x) == 3 || abs(p2.y - p1.y) == 3)
	 return False;
      break;
   case BISHOP:
      if (abs(p2.x - p1.x) != abs(p2.y - p1.y))
	 return False;
      break;
   case QUEEN:
      if (p1.x != p2.x && p1.y != p2.y && abs(p2.x - p1.x) != abs(p2.y - p1.y))
	 return False;
      break;
   case KING:
      if (IsLegalCastle(b, p1, p2, color))
	 break;

      if (abs(p2.x - p1.x) > 1 || abs(p2.y - p1.y) > 1)
	 return False;
      break;
   default:
      debug(("ChessMoveIsLegal got unknown piece type %d\n", piece));
      return False;
   }

   // Can't move onto same color
   if (s2->piece != NONE && s2->color == color)
      return False;
      
   // Check path to make sure no pieces are in the way (except for knights)
   if (piece != KNIGHT)
      if (!PathIsClear(b, p1, p2, color))
	 return False;
   return True;
}
Exemplo n.º 4
0
static BOOL FAR MazeToolProc (HWND hWnd,LONG lParam,WORD wMsg)
{
    HDC     hDC;
    LPFRAME lpFrame;
    LPTR    lpLine;
    POINT   pt;
    RGBS    Pixel;
    static int x1,y1;

    pt.x = LOWORD(lParam);
    pt.y = HIWORD(lParam);
    switch (wMsg)
    {
    case WM_LBUTTONDOWN:
        if (!bTrack)
        {
            lpFrame = ImgGetBaseEditFrame (lpImage);
            lpLine = FramePointer (lpFrame,pt.x,pt.y,FALSE);
            FrameGetRGB (lpFrame,lpLine,&Pixel,1);
            if (Pixel.green && !(Pixel.red & Pixel.blue)) // start green pel
            {
//                SoundStartID (IDC_LINES,NO,0);
                SoundStartResource ("icons",NO,0);
                MazeTrailPoints[0].x = x1 = pt.x;
                MazeTrailPoints[0].y = y1 = pt.y;
                nNumTrailPoints = 1;
                if (bShowSolution || bSolved)
                {
                    bShowSolution = bSolved = FALSE;
                    InvalidateRect (hWnd,NULL,FALSE);
                    UpdateWindow (hWnd);
                }
                bTrack = TRUE;
            }
            else if (!AnimateProc(hWnd,lParam,wMsg))
                SoundStartResource ("WRONGANSWER1",NO,0);
        }
        break;
    case WM_MOUSEMOVE:
        if (!bTrack)
            break;
        if (!fAppActive || GetUpdateRect (hWnd,NULL,FALSE))
        {
            InvertLine (hWnd,x1,y1,x1,y1);
            break;
        }
        InvertLine (hWnd,x1,y1,pt.x,pt.y);
        if (!LBUTTON || (pt.x == x1 && pt.y == y1))
            break;
        // else button is down, so fall through to anchor a point
    case WM_LBUTTONUP:
        if (bTrack)
        {
            if (PathIsClear (x1,y1,pt.x,pt.y))
            {
                lpFrame = ImgGetBaseEditFrame (lpImage);
                lpLine = FramePointer (lpFrame,pt.x,pt.y,FALSE);
                FrameGetRGB (lpFrame,lpLine,&Pixel,1);
                if (Pixel.red && !(Pixel.green & Pixel.blue)) // end red pel
                {
                    SoundStartResource ("GOODANSWER1",NO,0);
					StartAnimation(hWnd);
                    bSolved = TRUE;
                    bTrack = FALSE;
                }
                else
                {
                    hDC = GetDC (hWnd);
                    DrawLineEx (hDC,x1,y1,pt.x,pt.y,
                        hMazePen ? hMazePen : (HPEN)GetStockObject (BLACK_PEN),FALSE);
                    ReleaseDC (hWnd,hDC);
                    x1 = pt.x;
                    y1 = pt.y;
                    if (nNumTrailPoints < MAX_LINEPOINTS)
                    {
                        MazeTrailPoints[nNumTrailPoints].x = x1;
                        MazeTrailPoints[nNumTrailPoints].y = y1;
                        nNumTrailPoints++;
                    }
                }
            }
            else
                SoundStartResource ("WRONGANSWER1",NO,0);
        }
        break;
    case WM_PAINT:
        if (bTrack)
        {
            int i;

            hDC = GetDC (hWnd);
            pt.x = MazeTrailPoints[0].x;
            pt.y = MazeTrailPoints[0].y;
            for (i = 1; i < nNumTrailPoints; i++)
            {
                DrawLineEx (hDC,pt.x,pt.y,
                    MazeTrailPoints[i].x,MazeTrailPoints[i].y,
                    hMazePen ? hMazePen : (HPEN)GetStockObject (BLACK_PEN),FALSE);
                pt.x = MazeTrailPoints[i].x;
                pt.y = MazeTrailPoints[i].y;
            }
            ReleaseDC (hWnd,hDC);
        }
        break;
    }
    return TRUE;
}