Changeset 3


Ignore:
Timestamp:
Dec 12, 2020, 11:09:33 PM (3 years ago)
Author:
chronos
Message:
  • Modified: Try to use token with most steps (first token) if possible.
  • Modified: Move own token from start position if possible.
  • Fixed: Player who finished game should not have three dice throws.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Games/UClovece.pas

    r2 r3  
    1414
    1515  TTileKind = (tkNone, tkHome, tkYard);
     16  TTileKindSet = set of TTileKind;
    1617
    1718  { TToken }
     
    2223    procedure SetTile(AValue: TTile);
    2324  public
     25    MoveCount: Integer;
    2426    Player: TPlayer;
    2527    property Tile: TTile read FTile write SetTile;
     
    3032  TTokens = class(TFPGObjectList<TToken>)
    3133    function AddNew(Player: TPlayer): TToken;
    32     function GetCountByTileKind(Kind: TTileKind): Integer;
    33     function GetSingleByTileKind(Kind: TTileKind): TToken;
     34    function GetCountByTileKind(Kind: TTileKindSet): Integer;
     35    function GetSingleByTileKind(Kind: TTileKindSet): TToken;
     36    procedure GetByTileKind(Kind: TTileKindSet; const Tiles: TTokens);
    3437  end;
    3538
     
    137140  UGeometric;
    138141
    139 const
    140   Directions: array[0..3] of TPoint = ((X: 1; Y: 1), (X: -1; Y: 1),
    141     (X: -1; Y: -1), (X: 1; Y: -1));
    142   Directions2: array[0..3] of TPoint = ((X: 1; Y: 0), (X: 0; Y: 1),
    143     (X: -1; Y: 0), (X: 0; Y: -1));
    144   Directions3: array[0..3] of TPoint = ((X: 0; Y: 1), (X: 1; Y: 0),
    145     (X: 0; Y: -1), (X: 1; Y: 0));
    146 
    147142{ TToken }
    148143
     
    278273end;
    279274
    280 function TTokens.GetCountByTileKind(Kind: TTileKind): Integer;
     275function TTokens.GetCountByTileKind(Kind: TTileKindSet): Integer;
    281276var
    282277  I: Integer;
     
    284279  Result := 0;
    285280  for I := 0 to Count - 1 do
    286     if Items[I].Tile.Kind = Kind then Inc(Result);
    287 end;
    288 
    289 function TTokens.GetSingleByTileKind(Kind: TTileKind): TToken;
     281    if Items[I].Tile.Kind in Kind then Inc(Result);
     282end;
     283
     284function TTokens.GetSingleByTileKind(Kind: TTileKindSet): TToken;
    290285var
    291286  I: Integer;
    292287begin
    293288  I := 0;
    294   while (I < Count) and (Items[I].Tile.Kind <> Kind) do Inc(I);
     289  while (I < Count) and (not (Items[I].Tile.Kind in Kind)) do Inc(I);
    295290  if I < Count then Result := Items[I]
    296291    else Result := nil;
     292end;
     293
     294procedure TTokens.GetByTileKind(Kind: TTileKindSet; const Tiles: TTokens);
     295var
     296  I: Integer;
     297begin
     298  Tiles.Clear;
     299  for I := 0 to Count - 1 do
     300    if Items[I].Tile.Kind in Kind then Tiles.Add(Items[I]);
    297301end;
    298302
     
    320324function TPlayer.CanPlay: Boolean;
    321325begin
    322   Result := (Tokens.GetCountByTileKind(tkYard) > 0) or
    323     (Tokens.GetCountByTileKind(tkNone) > 0);
     326  Result := Tokens.GetCountByTileKind([tkYard, tkNone]) > 0;
    324327end;
    325328
     
    359362  P: TPoint;
    360363  P1, P2: TPoint;
    361   Tile: TTile;
    362364  R: Integer;
    363365  Between: Boolean;
     
    434436      P := Point(Trunc(Center.X + R + TokenCount * TileDistance * 1.35), Center.Y);
    435437      P := RotatePoint(Center, P, Angle);
    436       Tile := Tiles.AddNew(RotatePoint(P, Point(P.X + Trunc(0.7 * TileDistance), P.Y), I / TokenCount * 2 * Pi + Pi / 4), tkYard, Players[J]);
     438      Tiles.AddNew(RotatePoint(P, Point(P.X + Trunc(0.7 * TileDistance), P.Y), I / TokenCount * 2 * Pi + Pi / 4), tkYard, Players[J]);
    437439    end;
    438440  end;
     
    474476begin
    475477  Steps := TTiles.Create(False);
    476   Token.Tile.GetNextSteps(DiceValue, CurrentPlayer, Steps);
    477   Token.Tile := nil;
    478   for I := 0 to Steps.Count - 1 do begin
    479     Steps[I].AnimateToken := Token;
    480     Repaint;
    481     Application.ProcessMessages;
    482     Sleep(200);
    483     Steps[I].AnimateToken := nil;
    484   end;
    485   Steps.Free;
     478  try
     479    Token.Tile.GetNextSteps(DiceValue, CurrentPlayer, Steps);
     480    Token.Tile := nil;
     481    for I := 0 to Steps.Count - 1 do begin
     482      Steps[I].AnimateToken := Token;
     483      Repaint;
     484      Application.ProcessMessages;
     485      Sleep(200);
     486      Steps[I].AnimateToken := nil;
     487    end;
     488  finally
     489    Steps.Free;
     490  end;
    486491  Token.Tile := NewTile;
     492  Token.MoveCount := Token.MoveCount + DiceValue;
     493end;
     494
     495function CompareTokenMoveCount(const Item1, Item2: TToken): Integer;
     496begin
     497  if Item1.MoveCount < Item2.MoveCount then Result := 1
     498  else if Item1.MoveCount > Item2.MoveCount then Result := -1
     499  else Result := 0;
    487500end;
    488501
     
    493506  TurnDone: Boolean;
    494507  I: Integer;
     508  SortedTokens: TTokens;
    495509begin
    496510  TurnDone := False;
     
    498512  LastDiceValue := DiceValue;
    499513  if DiceValue = 6 then begin
    500     if CurrentPlayer.Tokens.GetCountByTileKind(tkYard) > 0 then begin
     514    if CurrentPlayer.Tokens.GetCountByTileKind([tkYard]) > 0 then begin
    501515      if (not Assigned(CurrentPlayer.StartTile.Token)) or (
    502516      Assigned(CurrentPlayer.StartTile.Token) and (CurrentPlayer.StartTile.Token.Player <> CurrentPlayer)) then begin
     
    506520        end;
    507521        // Move one token from yard to start
    508         CurrentPlayer.StartTile.Token := CurrentPlayer.Tokens.GetSingleByTileKind(tkYard);
     522        Token := CurrentPlayer.Tokens.GetSingleByTileKind([tkYard]);
     523        Token.MoveCount := 0;
     524        CurrentPlayer.StartTile.Token := Token;
    509525        TurnDone := True;
    510526      end;
    511527    end;
    512528  end;
    513   if not TurnDone and (CurrentPlayer.Tokens.GetCountByTileKind(tkNone) > 0) then begin
    514     for I := 0 to CurrentPlayer.Tokens.Count - 1 do
    515     if CurrentPlayer.Tokens[I].Tile.Kind in [tkHome, tkNone] then begin
    516       Token := CurrentPlayer.Tokens[I];
     529  if not TurnDone and (CurrentPlayer.Tokens.GetCountByTileKind([tkNone, tkHome]) > 0) then begin
     530    if Assigned(CurrentPlayer.StartTile.Token) and (CurrentPlayer.StartTile.Token.Player = CurrentPlayer) then begin
     531      // Own token is on start position, move it away
     532      Token := CurrentPlayer.StartTile.Token;
    517533      NewTile := Token.Tile.GetNext(DiceValue, CurrentPlayer);
    518       if not Assigned(NewTile) then Continue;
    519       if Assigned(NewTile.Token) then begin
    520         if NewTile.Token.Player = Token.Player then begin
    521           // Another own token is blocking way, use another one if possible
    522           Continue;
    523         end else begin
    524           // Move opponents token back to its yard
    525           NewTile.Token.Tile := NewTile.Token.Player.YardTiles.GetTileWithoutToken;
    526           AnimateTokenMovement(Token, NewTile);
    527           TurnDone := True;
    528           Break;
    529         end;
    530       end else begin
    531         // Normal token move
     534      if not Assigned(NewTile.Token) or (NewTile.Token.Player <> CurrentPlayer) then begin
    532535        AnimateTokenMovement(Token, NewTile);
    533536        TurnDone := True;
    534         Break;
    535537      end;
    536538    end;
     539    if not TurnDone then begin
     540      SortedTokens := TTokens.Create(False);
     541      try
     542        CurrentPlayer.Tokens.GetByTileKind([tkNone, tkHome], SortedTokens);
     543        SortedTokens.Sort(CompareTokenMoveCount);
     544        for I := 0 to SortedTokens.Count - 1 do begin
     545          Token := SortedTokens[I];
     546          NewTile := Token.Tile.GetNext(DiceValue, CurrentPlayer);
     547          if not Assigned(NewTile) then Continue;
     548          if Assigned(NewTile.Token) then begin
     549            if NewTile.Token.Player = Token.Player then begin
     550              // Another own token is blocking way, use another one if possible
     551              Continue;
     552            end else begin
     553              // Move opponents token back to its yard
     554              NewTile.Token.Tile := NewTile.Token.Player.YardTiles.GetTileWithoutToken;
     555              AnimateTokenMovement(Token, NewTile);
     556              TurnDone := True;
     557              Break;
     558            end;
     559          end else begin
     560            // Normal token move
     561            AnimateTokenMovement(Token, NewTile);
     562            TurnDone := True;
     563            Break;
     564          end;
     565        end;
     566      finally
     567        SortedTokens.Free;
     568      end;
     569    end;
    537570  end;
    538571  Inc(DiceThrow);
    539   if ((CurrentPlayer.Tokens.GetCountByTileKind(tkNone) = 0) and (DiceThrow >= 3)) or
    540     ((CurrentPlayer.Tokens.GetCountByTileKind(tkNone) > 0) and (DiceValue <> 6)) then begin
     572  if ((CurrentPlayer.Tokens.GetCountByTileKind([tkNone]) = 0) and (DiceThrow >= 3)) or
     573    ((CurrentPlayer.Tokens.GetCountByTileKind([tkNone]) > 0) and (DiceValue <> 6)) or
     574    (CurrentPlayer.Tokens.GetCountByTileKind([tkHome]) = TokenCount) then begin
    541575    repeat
    542576      CurrentPlayer := Players[(Players.IndexOf(CurrentPlayer) + 1) mod Players.Count];
Note: See TracChangeset for help on using the changeset viewer.