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; } } }
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; } }
/* * 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; }
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; }