⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cards.pas

📁 这是一个扑克牌游戏。 1.抓有黑桃7 的玩家首先出黑桃7。 2.然后按逆时针方向出牌。每位玩家依次出牌
💻 PAS
📖 第 1 页 / 共 2 页
字号:
var
  suit, num, i, suit1, num1: Integer;
  b: Boolean;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  //判断这张牌前面的牌是否被自已盖了,若是需盖
  for i := 0 to FPlayerCoverCards[APlayerIndex].Count - 1 do
  begin
    suit1 := GetSuit(FPlayerCoverCards[APlayerIndex].Card[i]);
    num1 := GetNum(FPlayerCoverCards[APlayerIndex].Card[i]);
    if suit = suit1 then
    begin
      if ((num > 6) and (num1 > 6) and (num > num1))
        or ((num < 6) and (num1 < 6) and (num < num1)) then
      begin
        Result := True;
        Exit;
      end;
    end;
  end;
  //判断这张牌前面已出的最大或最小牌在出来后,其他玩家是否都盖过牌了
  //如果都盖过牌了且这张牌是当前牌前面的牌,则需盖
  if FOutCards[suit].Min = scNone then  //未出过牌的花色排除
  begin
    Result := False;
    Exit;
  end;
  b := True;
  for i := 0 to PLAYER_COUNT - 1 do
  begin
    if i = APlayerIndex then Continue;
    if num > 6 then
      b := b and FOutCards[suit].MaxCover[i]
    else
      b := b and FOutCards[suit].MinCover[i];
    if not b then break;
  end;
  Result := b;
end;

function TCards.IsLate(APlayerIndex, ACardIndex: Integer): Boolean;
var
  i, j, n, m, suit, num, suit1, num1: Integer;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  j := 0;
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if i = ACardIndex then Continue;
    if FPlayerCards[APlayerIndex].Card[i] = scNone then Continue;
    suit1 := GetSuit(FPlayerCards[APlayerIndex].Card[i]);
    num1 := GetNum(FPlayerCards[APlayerIndex].Card[i]);
    if (suit = suit1) then
      if ((num > 6) and (num > num1)) or ((num < 6) and (num < num1)) then
        Inc(j);
  end;
  if num > 6 then
    n := num - FOutCards[suit].Max - 1
  else
    n := FOutCards[suit].Min - num - 1;
  m := (FPlayerCards[APlayerIndex].Count - j - 1) * 3;
  Result := n > m  //n = 当前牌和已出的牌的距离   m = 最大出牌机会
end;

function TCards.HaveCont(APlayerIndex, ACardIndex: Integer): Boolean;
var
  suit, num, i, l_min, l_max: Integer;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  //定义需要查找是否在自已手上的牌区间
  if num > 6 then
  begin
    if FOutCards[suit].Min <> scNone then  //如果此花色未出牌
      l_min := FOutCards[suit].Max + 1
    else
      l_min := 7;
    l_max := num - 1;
  end
  else begin
    l_min := num + 1;
    if FOutCards[suit].Min <> scNone then  //如果此花色未出牌
      l_max := FOutCards[suit].Min - 1
    else
      l_max := 5;
  end;
  //查找区间的所有牌是否在自已手上
  for i := l_min to l_max do
  begin
    if FindCard(APlayerIndex, suit, i) = -1 then //不在自已手上,则返回false
    begin
      Result := False;
      Exit;
    end;
  end;
  Result := True;
end;

function TCards.HaveNext(APlayerIndex, ACardIndex: Integer; ANextN: Integer = 1): Boolean;
var
  suit, num: Integer;
  bmin, bmax: Boolean;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  bmax := FindCard(APlayerIndex, suit, num + ANextN) >=0 ;
  bmin := FindCard(APlayerIndex, suit, num - ANextN) >= 0;
  if num = 6 then
    Result := bmax and bmin
  else if num > 6 then
    Result := bmax
  else
    Result := bmin;
end;

function TCards.IsTop(APlayerIndex, ACardIndex: Integer): Boolean;
var
  suit, num: Integer;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  //若当前牌为1或K则就是最头上的牌
  if (num = 0) or (num = 12) then
    Result := True
  //若当前牌后面一张牌被盖了,则就是最头上的牌
  else if (num > 6) and (FindCoverCard(APlayerIndex, suit, num + 1) >= 0) or
    (num < 6) and (FindCoverCard(APlayerIndex, suit, num - 1) >= 0) then
    Result := True
  else
    Result := False;
end;

function TCards.AfterScore(APlayerIndex, ACardIndex: Integer): Integer;
var
  i, suit, num, suit1, num1: Integer;
begin
  Result := 0;
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if i = ACardIndex then Continue;
    if FPlayerCards[APlayerIndex].Card[i] = scNone then Continue;
    suit1 := GetSuit(FPlayerCards[APlayerIndex].Card[i]);
    num1 := GetNum(FPlayerCards[APlayerIndex].Card[i]);
    if (suit = suit1) and
      ((num = 6) or ((num > 6) and (num1 > num)) or ((num1 < 6) and (num1 < num))) then
      Result := Result + GetNum(FPlayerCards[APlayerIndex].Card[i]) + 1;
  end;
end;

function TCards.AfterScoreAll(APlayerIndex, ACardIndex: Integer): Integer;
var
  i, suit, num: Integer;
begin
  Result := 0;
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  if num > 6 then
    for i := num + 1 to 12 do
      Result := Result + GetScore(suit, i)
  else
    for i := 0 to num - 1 do
      Result := Result + GetScore(suit, i);
end;

function TCards.AfterQuantity(APlayerIndex, ACardIndex: Integer): Integer;
var
  i, suit, num, suit1, num1: Integer;
begin
  Result := 0;
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if i = ACardIndex then Continue;
    if FPlayerCards[APlayerIndex].Card[i] = scNone then Continue;
    suit1 := GetSuit(FPlayerCards[APlayerIndex].Card[i]);
    num1 := GetNum(FPlayerCards[APlayerIndex].Card[i]);
    if (suit = suit1) and
      ((num = 6) or (num > 6) and (num1 > num) or (num < 6) and (num1 < num)) then
      Inc(Result);
  end;
end;

function TCards.BeforeQuantity(APlayerIndex, ACardIndex: Integer): Integer;
var
  i, suit, num, suit1, num1: Integer;
begin
  Result := 0;
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if i = ACardIndex then Continue;
    if FPlayerCards[APlayerIndex].Card[i] = scNone then Continue;
    suit1 := GetSuit(FPlayerCards[APlayerIndex].Card[i]);
    num1 := GetNum(FPlayerCards[APlayerIndex].Card[i]);
    if (suit = suit1) and
      ((num > 6) and (num1 < num)) or ((num1 < 6) and (num1 > num)) then
      Inc(Result);
  end;
end;

function TCards.DistanceOut(ACardID: Integer): Integer;
var
  suit, num: Integer;
begin
  suit := GetSuit(ACardID);
  num := GetNum(ACardID);
  if FOutCards[suit].Min = scNone then //如果花色未出过牌,则返回-1
  begin
    Result := -1;
    exit;
  end;
  if num > 6 then
    Result := num - FOutCards[suit].Max - 1
  else
    Result := FOutCards[suit].Min - num - 1;
end;

function TCards.PriorOutIsMe(ASuit, APlayerIndex, ANum: Integer): Boolean;
begin
  if ANum > 6 then
    Result := FOutCards[ASuit].MaxOwner = APlayerIndex
  else
    Result := FOutCards[ASuit].MinOwner = APlayerIndex;
end;

function TCards.SureOut(APlayerIndex, ACardIndex: Integer): Boolean;
var
  i, suit, num, n: Integer;
  b: boolean;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  //判断已出的最大或最小牌在出来后,其他玩家是否都没盖过牌
  //如果都没盖过牌了且这张牌和已出牌相距1,则肯定可出
  //如果相距大于1, 而前一张牌在自已手里的话,则看前一张是否和已出牌相距1。
  b := False;
  for i := 0 to PLAYER_COUNT - 1 do
  begin
    if i = APlayerIndex then Continue;
    if num > 6 then
      b := b or FOutCards[suit].MaxCover[i]
    else
      b := b or FOutCards[suit].MinCover[i];
    if b then  //如果有人盖过牌,则返回假
    begin
      Result := False;
      Exit;
    end;
  end;
  n := ACardIndex;
  repeat
    if DistanceOut(FPlayerCards[APlayerIndex].Card[n]) < 1 then //返回真
    begin
      Result := True;
      Exit;
    end;
    if num > 6 then
      Dec(num)
    else
      Inc(num);
    n := FindCard(APlayerIndex, suit, num);
  until (num = 6) or (n < 0);
  Result := False;
end;

function TCards.NextIsCover(APlayerIndex, ACardIndex: Integer): Boolean;
var
  i, suit, num, l_min, l_max: Integer;
begin
  suit := GetSuit(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  num := GetNum(FPlayerCards[APlayerIndex].Card[ACardIndex]);
  if num > 6 then
  begin
    l_min := num + 1;
    l_max := 12;
  end
  else begin
    l_min := 0;
    l_max := num - 1;
  end;
  for i := l_min to l_max do
    if FindCoverCard(APlayerIndex, suit, i) >= 0 then
    begin
      Result := True;
      Exit;
    end;
  Result := False;
end;

function TCards.CalcOutCard(APlayerIndex: Integer): Integer;
var
  cs, qz: TPlayerCard;
  i, j, suit, num: Integer;
begin
  cs.Count := 0;
  //若玩家牌数为1,则这张牌就是要发的牌
  if FPlayerCards[APlayerIndex].Count = 1 then
    for i := 0 to PLAYER_CARD_COUNT - 1 do
      if FPlayerCards[APlayerIndex].Card[i] <> scNone then
      begin
        Result := i;
        Exit;
      end;
  //得到所有可出的牌
  for i := 0 to PLAYER_CARD_COUNT - 1 do
    if CanOut(APlayerIndex, i) then
    begin
      if FPlayerCards[APlayerIndex].Card[i] = FIRST_OUT_CARD then
      begin
        Result := i;
        Exit;
      end;
      Inc(cs.Count);
      cs.Card[cs.Count - 1] := i;
    end;
  //若可出的牌只有一张,则返回这张牌
  if cs.Count = 1 then
  begin
    Result := cs.Card[0];
    Exit;
  end;
  //根据权值计算优先出的牌,权值大的先出。
  for i := 0 to cs.Count - 1 do
  begin
    suit := GetSuit(FPlayerCards[APlayerIndex].Card[cs.Card[i]]);
    num := GetNum(FPlayerCards[APlayerIndex].Card[cs.Card[i]]);
    //置初始权值,置初始权值,离7远的权值大,小于7的又比大于7的大
    qz.Card[i] := (1 - num div 7) * 6 + Abs(num - 6);
    if num <> 6 then
      qz.Card[i] := qz.Card[i] + AfterQuantity(APlayerIndex, cs.Card[i]) //后面牌多的先出
    //若牌为7,且自已的总分大于110的,优先出
    else if (FPlayerCards[APlayerIndex].Score > 100) then
    begin
        qz.Card[i] := qz.Card[i] + 50;
        qz.Card[i] := qz.Card[i] + AfterQuantity(APlayerIndex, cs.Card[i]);
    end;
    //若牌大于7且后面的分数占了所有分数的一半的,优先出
    if (num > 6) and (AfterScore(APlayerIndex, cs.Card[i]) * 2 > AfterScoreAll(APlayerIndex, i)) then
      qz.Card[i] := qz.Card[i] + 10;
    //若牌小于7且后面的张数占了所有张数的一半的,优先出
    if (num < 6) and (AfterQuantity(APlayerIndex, cs.Card[i]) * 2 > 6) then
      qz.Card[i] := qz.Card[i] + 10;
    //最头上的牌,则优先出
    if IsTop(APlayerIndex, cs.Card[i]) then
      qz.Card[i] := qz.Card[i] + 10
    //后面自已没有牌的且不是最头上的牌,则考虑先不出
    else if AfterQuantity(APlayerIndex, cs.Card[i]) = 0 then
    begin
      if num > 6 then
        qz.Card[i] := qz.Card[i] - 20;
      if num < 6 then
        qz.Card[i] := qz.Card[i] - 10;
    end
    //后面紧接的牌在自已手上, 则优先出
    else if HaveNext(APlayerIndex, cs.Card[i]) then
      qz.Card[i] := qz.Card[i] + 10
    //如果后面隔一张在自已这里的,则优先出
    else if HaveNext(APlayerIndex, cs.Card[i], 2) then
      qz.Card[i] := qz.Card[i] + 20;
    //================= 在以上权值相同的情况下 ================
    //花色先出的牌先出
    qz.Card[i] := qz.Card[i] * 4 + 4 - FOutCards[suit].Order;
  end;
  //将权值最大的返回
  j := 0;
  for i := 1 to cs.Count - 1 do
    if qz.Card[j] <= qz.Card[i] then j := i;
  Result := cs.Card[j];
end;


function TCards.CalcCoverCard(APlayerIndex: Integer): Integer;
var
  qz: TPlayerCard;
  suit, num, i, j: Integer;
begin
  //若玩家牌数为1,则这张牌就是要盖的牌
  if FPlayerCards[APlayerIndex].Count = 1 then
    for i := 0 to PLAYER_CARD_COUNT - 1 do
      if FPlayerCards[APlayerIndex].Card[i] <> scNone then
      begin
        Result := i;
        Exit;
      end;
  //根据权值计算优先盖的牌,权值大的先盖。
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if FPlayerCards[APlayerIndex].Card[i] = scNone then
     begin qz.Card[i] := 0; Continue; end;
    //如果前面牌被盖或没有出牌机会了,则先盖.
    if IsCover(APlayerIndex, i) or IsLate(APlayerIndex, i) then
    begin
      Result := i;
      Exit;
    end;
    suit := GetSuit(FPlayerCards[APlayerIndex].Card[i]);
    num := GetNum(FPlayerCards[APlayerIndex].Card[i]);
    //置初始权值,离7远的权值大,小于7的比大于7的大
    qz.Card[i] := (1 - num div 7) * 6 + Abs(num - 6);
    //离已出的牌远的先盖
    qz.Card[i] := qz.Card[i] + 5 * DistanceOut(FPlayerCards[APlayerIndex].Card[i]);
    //如果确定可出的牌,先不盖
    if SureOut(APlayerIndex, i) then
      qz.Card[i] := qz.Card[i] - 10;
    //如果后面有牌被自已盖的,先不盖
    if NextIsCover(APlayerIndex, i) then
      qz.Card[i] := qz.Card[i] - 10
    //如果后面没有牌的(包括后面没盖过牌的)
    else begin
      if AfterQuantity(APlayerIndex, i) = 0 then
      begin
        //如果牌前面的牌是不连续的,则优先盖
        if not HaveCont(APlayerIndex, i) then qz.Card[i] := qz.Card[i] + 1;
        //若大于7且小于J或 小于7且大于4的则优先盖
        if (num > 6) and (num < 10) then qz.Card[i] := qz.Card[i] + 30 - num;
        if (num < 6) and (num > 3) then qz.Card[i] := qz.Card[i] + 10 + num;
      end;
      //如果没有后面紧接的牌且这张牌大于7小于10且后面的牌分数小于15的,优先盖
      if not HaveNext(APlayerIndex, i) and (num > 6) and (num < 9) and (AfterScore(APlayerIndex, i) < 15) then
        qz.Card[i] := qz.Card[i] + 10 + AfterScoreAll(APlayerIndex, i) - AfterScore(APlayerIndex, i);
    end;
    //如果距离已出牌为1,则已出的那张牌是自已出的,则先不盖
    if (DistanceOut(FPlayerCards[APlayerIndex].Card[i]) = 1) and PriorOutIsMe(suit, APlayerIndex, num) then
      qz.Card[i] := qz.Card[i] - 10;
    //================= 在以上权值相同的情况下 ================
    //前面的牌多的先盖
    qz.Card[i] := qz.Card[i] * 5 + BeforeQuantity(APlayerIndex, i);
    //花色后出的牌先盖
    qz.Card[i] := qz.Card[i] * 4 + FOutCards[suit].Order;
  end;
  //将权值最大的返回
  j := -1;
  for i := 0 to PLAYER_CARD_COUNT - 1 do
  begin
    if FPlayerCards[APlayerIndex].Card[i] = scNone then Continue;
    if (j < 0) or (qz.Card[j] <= qz.Card[i]) then j := i;
  end;
  Result := j;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -