SphereCommunity
I need a more efficient function - Printable Version

+- SphereCommunity (https://forum.spherecommunity.net)
+-- Forum: Sphere 0.56d (/Forum-Sphere-0-56d)
+--- Forum: Script Requests (/Forum-Script-Requests)
+--- Thread: I need a more efficient function (/Thread-I-need-a-more-efficient-function)

Pages: 1 2


I need a more efficient function - RanXerox - 05-15-2012 02:46 PM

Hey people, I am working on a Hold'em poker script for the community... but I am in need of some help in optimizing some functions that are frequently called. The first one I'd like you to look at for me is an easy one ;-)

This function compares two poker cards to each other... In Poker the highest card is an Ace, next highest is King, then Queen, Jack, Ten, then 9 down to 2. Take a look at the function below and see if you can optimize it further for me:

Note: In this system, poker cards are represented by two letter combinations, and the ranking order needs to be: "As", "Ah", "Ad", "Ac", "Ks", "Kh", "Kd", "Kc", "Qs", "Qh", "Qd", "Qc", "Js", "Jh", "Jd", "Jc", "Ts", "Th", "Td", "Tc", "9s", "9h", "9d", "9c", "8s", "8h", "8d", "8c", "7s", "7h", "7d", "7c", "6s", "6h", "6d", "6c", "5s", "5h", "5d", "5c", "4s", "4h", "4d", "4c", "3s", "3h", "3d", "3c", "2s", "2h", "2d", "2c"

Code:
[FUNCTION f_Poker_RankCards]
//"
// Usage: f_Poker_SortCard CardA,CardB
//
// Compares CardA to CardB
//
// Returns: -1 if A is less than B
// Returns:  0 if A is equal to B
// Returns:  1 if A is greater than B
//"
IF (<ARGV>!=2)
   f_pokerlog 1,"Poker_RankCards: needs two cards as arguments"
   RETURN 1
ENDIF
LOCAL.CardA=<STRSUB 0 1 <ARGV[0]>>
LOCAL.CardB=<STRSUB 0 1 <ARGV[1]>>
f_pokerlog 1,"Poker_RankCards: CardA=<LOCAL.CardA> CardB=<LOCAL.CardB>"
IF (<ISNUM <LOCAL.CardB>>) && (<ISNUM <LOCAL.CardA>>)
   IF (<LOCAL.CardA> > <LOCAL.CardB>)
      f_pokerlog 1,"A is ranked Greater than B"
      RETURN 1
   ELSEIF (<LOCAL.CardA> < <LOCAL.CardB>)
      f_pokerlog 1,"A is ranked Less than B"
      RETURN -1
   ELSE
      f_pokerlog 1,"A is equal to B"
      RETURN 0
   ENDIF
ENDIF
IF !(<ISNUM <LOCAL.CardA>>) && (<ISNUM <LOCAL.CardB>>)
   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ENDIF
IF (<ISNUM <LOCAL.CardA>>) && !(<ISNUM <LOCAL.CardB>>)
   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ENDIF
IF     !(STRCMPI("<LOCAL.CardA>","A")) && (STRCMPI("<LOCAL.CardB>","A"))
   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ELSEIF (STRCMPI("<LOCAL.CardA>","A")) && !(STRCMPI("<LOCAL.CardB>","A"))
   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ELSEIF !(STRCMPI("<LOCAL.CardA>","K")) && (STRCMPI("<LOCAL.CardB>","K"))
   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ELSEIF (STRCMPI("<LOCAL.CardA>","K")) && !(STRCMPI("<LOCAL.CardB>","K"))
   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ELSEIF !(STRCMPI("<LOCAL.CardA>","Q")) && (STRCMPI("<LOCAL.CardB>","Q"))
   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ELSEIF (STRCMPI("<LOCAL.CardA>","Q")) && !(STRCMPI("<LOCAL.CardB>","Q"))
   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ELSEIF !(STRCMPI("<LOCAL.CardA>","J")) && (STRCMPI("<LOCAL.CardB>","J"))
   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ELSEIF (STRCMPI("<LOCAL.CardA>","J")) && !(STRCMPI("<LOCAL.CardB>","J"))
   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ELSE
   f_pokerlog 1,"A is equal to B"
   RETURN 0
ENDIF

[FUNCTION f_pokerlog]
IF (<EVAL <DEF.PokerLogging>> >= <ARGV[0]>)
   SERV.LOG Poker: <ARGV[1]>
   UID.044947.SYSMESSAGE @021 <ARGV[1]>
ENDIF

[DEFNAME poker_system]
PokerLogging=3



RE: I need a more efficient function - ShiryuX - 05-15-2012 04:13 PM

Why don't use numbers for everything?
Let me analyze this:

You got 12 cards in every color. That gives you 12 ranks.
You got numbers from 2 to 9. So you don't have 2 digits.
You got A, K, Q, J as letters, but you can use them as numbers if you like (Spanish cards goes from 1 to 12).

So let's say you make a number using the Rank and Color of the card.
For the Ace of Spades you'll have 13-1 (Saying 13 is the highest rank and 1 is the color).
And for the 4 of Spades you'll have 4-1.

That gives you 131 against 41.
Now, that's fine if you have only ONE color, now you got 4 colors, so the result may change from 131 to 134.
I'll give you the solution: Card / 10. So, if the Card is 131 (Ace of Spades) against 134 (Ace of Hearts), you divide them by 10 and that should give you 13 against 13.
If you want to recover the color for the royal flush, you can use a strsub. This way you can analyze Pairs and Three of a Kind with no problem, same goes for Poker and Full.
The only "hard part" is the flush or royal flush, since Straigth is kinda easy (divide everything by 10 and it should give you a straigth). For the Royal you can save resources by only analyzing if you first have a Straigth. In the case of the Flush, you have to analyze if you have all different ranks in the hand.

After that you can create a defname or something like that to "rename" the cards numbers.
Did you get my idea? Tongue


RE: I need a more efficient function - RanXerox - 05-16-2012 06:36 AM

I like that idea of having an array of card properties... Here is what I did instead:

Code:
[DEFNAME poker_card_properties]
//Cards     Symbol,Suit,Rank,Name,Nickname
POKER.Card.As  As,s,0,Ace of Spades,Ace of Death
POKER.Card.Ah  Ah,h,0,Ace of Hearts
POKER.Card.Ad  Ad,d,0,Ace of Diamonds
POKER.Card.Ac  Ac,c,0,Ace of Clubs
POKER.Card.Ks  Ks,s,1,King of Spades
POKER.Card.Kh  Kh,h,1,King of Hearts
POKER.Card.Kd  Kd,d,1,King of Diamonds,One Eyed King
POKER.Card.Kc  Kc,c,1,King of Clubs
POKER.Card.Qs  Qs,s,2,Queen of Spades
POKER.Card.Qh  Qh,h,2,Queen of Hearts,Helen of Troy
POKER.Card.Qd  Qd,d,2,Queen of Diamonds
POKER.Card.Qc  Qc,c,2,Queen of Clubs
POKER.Card.Js  Js,s,3,Jack of Spades
POKER.Card.Jh  Jh,h,3,Jack of Hearts,One Eyed Jack of Hearts
POKER.Card.Jd  Jd,d,3,Jack of Diamonds
POKER.Card.Jc  Jc,c,3,Jack of Clubs
POKER.Card.Ts  Ts,s,4,Ten of Spades
POKER.Card.Th  Th,h,4,Ten of Hearts
POKER.Card.Td  Td,d,4,Ten of Diamonds,Diamond Dime
POKER.Card.Tc  Tc,c,4,Ten of Clubs
POKER.Card.9s  9s,s,5,Nine of Spades
POKER.Card.9h  9h,h,5,Nine of Hearts
POKER.Card.9d  9d,d,5,Nine of Diamonds,The Curse of Scotland
POKER.Card.9c  9c,c,5,Nine of Clubs
POKER.Card.8s  8s,s,6,Eight of Spades
POKER.Card.8h  8h,h,6,Eight of Hearts
POKER.Card.8d  8d,d,6,Eight of Diamonds
POKER.Card.8c  8c,c,6,Eight of Clubs
POKER.Card.7s  7s,s,7,Seven of Spades
POKER.Card.7h  7h,h,7,Seven of Hearts
POKER.Card.7d  7d,d,7,Seven of Diamonds
POKER.Card.7c  7c,c,7,Seven of Clubs,Clubbed Walking Stick
POKER.Card.6s  6s,s,8,Six of Spades
POKER.Card.6h  6h,h,8,Six of Hearts,Loyalty at the Risk of Death
POKER.Card.6d  6d,d,8,Six of Diamonds
POKER.Card.6c  6c,c,8,Six of Clubs
POKER.Card.5s  5s,s,9,Five of Spades,Nickle Spade
POKER.Card.5h  5h,h,9,Five of Hearts
POKER.Card.5d  5d,d,9,Five of Diamonds
POKER.Card.5c  5c,c,9,Five of Clubs
POKER.Card.4s  4s,s,10,Four of Spades
POKER.Card.4h  4h,h,10,Four of Hearts
POKER.Card.4d  4d,d,10,Four of Diamonds
POKER.Card.4c  4c,c,10,Four of Clubs
POKER.Card.3s  3s,s,11,Three of Spades
POKER.Card.3h  3h,h,11,Three of Hearts
POKER.Card.3d  3d,d,11,Three of Diamonds
POKER.Card.3c  3c,c,11,Three of Clubs
POKER.Card.2s  2s,s,12,Two of Spades
POKER.Card.2h  2h,h,12,Two of Hearts
POKER.Card.2d  2d,d,12,Two of Diamonds
POKER.Card.2c  2c,c,12,Two of Clubs

[FUNCTION f_Poker_RankCards]
//"
// Usage: f_Poker_RankCards CardA,CardB
//
// Compares CardA to CardB
//
// Returns: -1 if A is less than B
// Returns:  0 if A is equal to B
// Returns:  1 if A is greater than B
//"
IF (<ARGV>!=2)
//   f_pokerlog 1,"Poker_RankCards: needs two cards as arguments"
   RETURN 1
ENDIF
LOCAL.CardA.Rank=<getargv 2 <DEF.POKER.Card.<ARGV[0]>>>
LOCAL.CardB.Rank=<getargv 2 <DEF.POKER.Card.<ARGV[1]>>>
f_pokerlog 1,".CardA Rank=<dLOCAL.CardA.Rank> CardB Rank=<dLOCAL.CardB.Rank>"
IF (<LOCAL.CardA> > <LOCAL.CardB>)
//   f_pokerlog 1,"A is ranked Greater than B"
   RETURN 1
ELSEIF (<LOCAL.CardA> < <LOCAL.CardB>)
//   f_pokerlog 1,"A is ranked Less than B"
   RETURN -1
ELSE
//   f_pokerlog 1,"A is equal to B"
   RETURN 0
ENDIF

I alluded to a more complicated optimization.... here is a card sorting function (a horrifying CompSci 201 bubble sort that leverages the previous f_poker_RankCards function)... It works but its not ideal. Can anyone make me a quicksort or merge-sort version while I carry on with other functions?

Code:
[FUNCTION f_Poker_SortCards]
//"
// Usage: f_Poker_SortCards DeckUID
//
// Sorts a Global LIST object containing an array of abbreviated Poker card names.
//"
IF (<ARGV>==0)
   f_pokerlog 1,"Poker_SortCards: needs a DeckUID"
   RETURN 1
ENDIF
LOCAL.Input=<ARGS>
LOCAL.InputSize=<LIST.<LOCAL.Input>.COUNT>
LOCAL.Swapped=1
WHILE (<dLOCAL.Swapped>==1)
   LOCAL.Swapped=0
   FOR LoopNumber 1 <EVAL <LOCAL.InputSize>-1>
//      f_pokerlog 2,"Loop <dLOCAL.LoopNumber>"
      LOCAL.CardA="<STRSUB 1 2 <LIST.<LOCAL.Input>.<EVAL <LOCAL.LoopNumber>-1>>>"
      LOCAL.CardB="<STRSUB 1 2 <LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>>>"
//      f_pokerlog 2,".Is <LOCAL.CardA> greater than <LOCAL.CardB>?  STRCMP(<LOCAL.CardA>,<LOCAL.CardB>)"
      IF (<f_Poker_RankCards <LOCAL.CardA>,<LOCAL.CardB>>==-1) //CardA is Less than CardB
//         f_pokerlog 3,"..Yes, swap them"
         LIST.<LOCAL.Input>.<EVAL <LOCAL.LoopNumber>-1>=<LOCAL.CardB>
         LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>=<LOCAL.CardA>
         LOCAL.Swapped=1
      ELSE
//         f_pokerlog 3,"..No, skipping"
      ENDIF
   ENDFOR
   LOCAL.InputSize=<EVAL <LOCAL.InputSize>-1>
ENDWHILE
f_pokerlog 1,"Poker_SortCards: Complete... size=<LIST.<LOCAL.Input>.COUNT>"

In order to make a new deck of cards (as a global LIST object containing an array of abbreviated Poker card names)... and then shuffle it... these functions will come in handy:

Code:
[DEFNAME poker_card_and_suit_properties]//Card and Suit Symbols:
POKER.Card.Symbols=A,K,Q,J,T,9,8,7,6,5,4,3,2
POKER.Suit.Symbols=s,h,d,c

[FUNCTION f_Poker_NewDeck]
//"
// Usage: f_Poker_NewDeck DeckUID
//
// Creates a Global LIST object named DeckUID and load it with a full deck of abbreviated Poker card names.
//"
IF (<ARGV>==0)
   f_pokerlog 1,"Poker_NewDeck: needs a DeckUID"
   RETURN 1
ENDIF
LOCAL.Input=<ARGS>
FOR Cards 0 <EVAL <f_sizeof <DEF.POKER.Card.Symbols>>-1>
   FOR Suits 0 <EVAL <f_sizeof <DEF.POKER.Suit.Symbols>>-1>
      LOCAL.TheCard=<getargv <dLOCAL.Cards> <DEF.POKER.Card.Symbols>><getargv <dLOCAL.Suits> <DEF.POKER.Suit.Symbols>>
      LIST.<LOCAL.Input>.ADD <LOCAL.TheCard>
   ENDFOR
ENDFOR
f_pokerlog 1,"Poker_NewDeck: size=<LIST.<LOCAL.Input>.COUNT>"

[FUNCTION f_Poker_Shuffle]
//"
// Usage: f_Poker_Shuffle DeckUID
//
// Shuffles a Global LIST object containing an array of abbreviated Poker card names.
//"
IF (<ARGV>==0)
   f_pokerlog 1,"Poker_Shuffle: needs a DeckUID"
   RETURN 1
ENDIF
LOCAL.Input=<ARGS>
FOR LoopNumber 0 <EVAL <LIST.<LOCAL.Input>.COUNT>-1>
   LOCAL.Rand=<R0,<EVAL <LIST.<LOCAL.Input>.COUNT>-1>>
   LOCAL.CardA=<STRSUB 1 2 <LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>>>
   LOCAL.CardB=<STRSUB 1 2 <LIST.<LOCAL.Input>.<dLOCAL.Rand>>>
   LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>=<LOCAL.CardB>
   LIST.<LOCAL.Input>.<dLOCAL.Rand>=<LOCAL.CardA>
ENDFOR
f_pokerlog 1,"Poker_Shuffle: size=<LIST.<LOCAL.Input>.COUNT>"

As always... please point out suggestions for optimization!


RE: I need a more efficient function - RanXerox - 07-11-2012 07:54 AM

This function:

Code:
[FUNCTION f_Poker_SortCards]
//"
// Usage: f_Poker_SortCards CardArray
//
// Sorts an existing LIST object named CardArray, which is assumed to contain
// CardSymbols.  The sort order has highest ranked cards (Ace) first (suit is
// ignored.)
//"
IF (<ARGV>==0)
   f_pokerlog 1,"Poker_SortCards: needs a CardArray"
   RETURN 1
ENDIF
LOCAL.Input=<ARGS>
LOCAL.InputSize=<LIST.<LOCAL.Input>.COUNT>
IF (<LOCAL.InputSize> < 2)
   f_pokerlog 1,"Poker_SortCards: CardArray <LOCAL.Input> is too small to sort"
   RETURN 1
ENDIF
f_pokerlog 1,"Poker_SortCards: Start sorting <LOCAL.Input> (size=<LOCAL.InputSize>)"
LOCAL.Swapped=1
WHILE (<dLOCAL.Swapped>==1)
   LOCAL.Swapped=0
   FOR LoopNumber 1 <EVAL <LOCAL.InputSize>-1>
      LOCAL.CardA="<STRSUB 1 2 <LIST.<LOCAL.Input>.<EVAL <LOCAL.LoopNumber>-1>>>"
      LOCAL.CardB="<STRSUB 1 2 <LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>>>"
      f_pokerlog 2,"Poker_SortCards: ..Loop=<dLOCAL.LoopNumber>: Is <LOCAL.CardA> ranked higher than <LOCAL.CardB>?"
      IF (<f_Poker_RankCards <LOCAL.CardA>,<LOCAL.CardB>>==-1) //CardA ranks lower than CardB
         f_pokerlog 3,"Poker_SortCards: ....swap them"
         LIST.<LOCAL.Input>.<EVAL <LOCAL.LoopNumber>-1>=<LOCAL.CardB>
         LIST.<LOCAL.Input>.<dLOCAL.LoopNumber>=<LOCAL.CardA>
         LOCAL.Swapped=1
      ELSE
         f_pokerlog 3,"Poker_SortCards: ....skipping"
      ENDIF
   ENDFOR
   LOCAL.InputSize=<EVAL <LOCAL.InputSize>-1>
ENDWHILE
f_pokerlog 1,"Poker_SortCards: Sorting Completed"

Sometimes produces an error:

Code:
15:31:(Poker.scp,642)Poker: Poker_SortCards: Start sorting POKERGame_040036a76_Player7 (size=07)
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is 2h ranked higher than Js?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=2: Is 2h ranked higher than Qc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=3: Is 2h ranked higher than 9h?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=4: Is 2h ranked higher than Tc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=5: Is 2h ranked higher than 9s?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=6: Is 2h ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Js ranked higher than Qc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=2: Is Js ranked higher than 9h?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=3: Is 9h ranked higher than Tc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=4: Is 9h ranked higher than 9s?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=5: Is 9s ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Qc ranked higher than Js?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=2: Is Js ranked higher than Tc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=3: Is Tc ranked higher than 9h?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=4: Is 9h ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Qc ranked higher than Js?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=2: Is Js ranked higher than Tc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=3: Is Tc ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Qc ranked higher than Js?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=2: Is Js ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Qc ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....swap them
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=1: Is Ac ranked higher than Qc?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:ERROR:(Poker_CardFunctions.scp,121)Can't resolve <STRSUB1>
15:31:(Poker.scp,642)Poker: Poker_SortCards: ..Loop=0: Is 0 ranked higher than Ac?
15:31:(Poker.scp,642)Poker: Poker_SortCards: ....skipping
15:31:(Poker.scp,642)Poker: Poker_SortCards: Sorting Completed

Any suggestions for a proper fix?


RE: I need a more efficient function - Skul - 07-11-2012 08:33 AM

Just a few questions, is LIST global or local? Does it get erased after the game is aquitted? If not, you should think of storing your LIST as a TAG on the game holder, have it stored like an array sorted by commas to retrieve and organize it all. I would suggest CTAG but it is online only, and sometimes players have connection issues.

You could probably sort your tags out (in a similar fashion) on the table masters/game hosts character as:

tag.poker.cardlist //cards to be played (all 52 shuffled at the beginning of the hand)
tag.poker.hand //current hand (to be organized as posted above)

The idea of LIST looks bulky to me, especially considering a gameserver can populate very high. With a couple tags, storing the info as an array, you can erase these after the game ends. Maybe it'll help, not sure.

Your code above looks optimized, loops are always a bit of a ram chug but it's the only way you can sort your hands, seeing that poker will have 5 cards to sort out between all players won't show much of a problem in my opinion... it looks alright.

An easy way to know how to sort your cards (by #), go to the store, pickup a fresh pack of cards for $1. Start counting them out, that'll give you a numbered list and an proper array to sort out Smile


RE: I need a more efficient function - RanXerox - 07-11-2012 09:07 AM

LIST is global like VAR, it is permanent (they are saved in spheredata.scp like VARs are.)

I originally implemented the entire thing in TAGs but it was a huge pain to manage mixed (string/numeric) values and the LIST functions manage all that automatically. Its also trivial to build multi-dimensional arrays using LIST and doing that in TAGs is nightmarish due to the parsing of the delimiter characters etc.

The problem with the code above is that sometimes the last comparison causes the FOR loop to reverse (it essentially becomes FOR x 1 0) and then CardA becomes invalid because its looking at LIST[-1] (which is invalid) or something like that.

This is line 121:

Code:
LOCAL.CardA="<STRSUB 1 2 <LIST.<LOCAL.Input>.<EVAL <LOCAL.LoopNumber>-1>>>"



RE: I need a more efficient function - Skul - 07-11-2012 09:26 AM

Right, I know what you mean now (considering how your script originally was). But after reading Shir's suggestion, sorting your cart types using numbers 1 - 52 that 'mess' of an array will be gone if you were to use TAGs, guaranteed. You can use a function to read your hand, shuffle the cards, let me think up a simple script quick:
Code:
[function f_poker_shuffle]
while !(<dlocal.y>==52)
local.x=<eval {1 52}>
if !(<local.x.<dlocal.x>>)
  if (<isempty <tag.poker.hand.shuffled>>)
   tag.poker.hand.shuffled=<local.x>
  else
   tag.poker.hand.shuffled=<tag.poker.hand.shuffled>,<local.x>
  endif
  local.y += 1
endif
endwhile

[function f_poker_pass_card]
//argn1 = cards
//argn2 = uid of game host
if (<argn1>)
for x 1 <argn1>
  if (<isempty <tag.poker.hand>>)
   tag.poker.hand=<uid.<argn2>.f_poker_retrieve_card <uid.<argn2>.tag0.poker.hand.shuffled>>
  else
   tag.poker.hand=<tag.poker.hand>,<uid.<argn2>.f_poker_retrieve_card <uid.<argn2>.tag0.poker.hand.shuffled>>
  endif
endfor
endif

[function f_poker_retrieve_card]
if (<tag0.poker.hand.shufffled>)
tag.poker.hand.shuffled=
for x 1 <eval <args> +-1> //eliminate the first card from the array, restore the tag.
  if(<isempty <tag.poker.hand.shuffled>>)
   tag.poker.hand.shuffled=<argv[<local.x>]>
  else
   tag.poker.hand.shuffled=<tag.poker.hand.shuffled>,<argv[<local.x>]>
  endif
endfor
return <argv[0]> //the first card in the array (after shuffling)
else
return '' //no tag, no return
endif

So if you were to sort your card names by 1 - 52 in a defname, as an example you can retrieve the card name by number like
Code:
<serv.def.Poker_Card<card #1-52>_Name
<serv.def.Poker_Card<card #1-52>_Name_Short

Cards are also sorted by suite, example Spades are more than Hearts are more than Clubs are more than Diamonds. So sorting it out in number you can simplify this by dividing your deck by 4 suites.
Code:
if (<card #> <= 52) && (<card #> >= <eval 52 - <eval 52 /4>>)
//spades
elseif (<card #> < <eval 52 - <eval 52 /4>>) && (<card #> >= <eval 52 - <eval <eval 52 /4> *2>>)
//hearts
elseif (<card #> < <eval 52 - <eval <eval 52 /4> *2>) && (<card #> >= <eval 52 - <eval <eval 52 /4> *3>>)
//clubs
else
//diamonds
endif



RE: I need a more efficient function - RanXerox - 07-11-2012 09:55 AM

I added an extra IF (<LOCAL.LoopNumber>) to prevent it from doing anything when LoopNumber is zero... Hopefully that doesn't have a negative side effect.


RE: I need a more efficient function - infinitynotpi - 09-16-2012 10:03 PM

This is me holding a flower...(see Venn diagram)

Wolfram Alpha

And this is me just showing my ass...

First Function of 2 Boolean Variables

And this is me just being a friend...

I've included some C for you!

Which includes the fast algorithm you're looking for in it -- Monte Carlo

133,784,560 combinations

Snippet here

Code:
/*
* returns number of dead cards, -1 on error
*
* argc, argv are the standard arguments to main
* num_dead is a return value of the number of dead cards
* dead_cards is a return value of the dead cards
*/
static int
parse_args(int argc, char **argv, int *num_dead, CardMask *dead_cards) {
  int i, c, o, rc, len;

  if (num_dead == NULL) {
    return (-1);
  }

  if (dead_cards == NULL) {
    return (-1);
  }

  *num_dead = 0;
  CardMask_RESET(*dead_cards);

  /*
   * parse any options passed to us.
   * -d "c1 [...]" is dead cards
   */
  while((o = getopt(argc, argv, opts)) != -1) {
    switch(o) {
    case 'd':
      len = strlen(optarg);
      for(i = 0;i < len;) {
    rc = StdDeck_stringToCard(optarg+i, &c);
    if (rc) {
      StdDeck_CardMask_SET(*dead_cards, c);
      (*num_dead)++;
      i += 2;
    } else {
      i++;
    }
      }
      break;
    }
  }

  return (*num_dead);
}
[/code]

The Count of Monte Cristo


RE: I need a more efficient function - Rayvolution - 09-18-2012 08:40 AM

(09-16-2012 10:03 PM)infinitynotpi Wrote:  This is me holding a flower...(see Venn diagram)

Wolfram Alpha

And this is me just showing my ass...

First Function of 2 Boolean Variables

And this is me just being a friend...

I've included some C for you!

Which includes the fast algorithm you're looking for in it -- Monte Carlo

133,784,560 combinations

Snippet here

Code:
/*
* returns number of dead cards, -1 on error
*
* argc, argv are the standard arguments to main
* num_dead is a return value of the number of dead cards
* dead_cards is a return value of the dead cards
*/
static int
parse_args(int argc, char **argv, int *num_dead, CardMask *dead_cards) {
  int i, c, o, rc, len;

  if (num_dead == NULL) {
    return (-1);
  }

  if (dead_cards == NULL) {
    return (-1);
  }

  *num_dead = 0;
  CardMask_RESET(*dead_cards);

  /*
   * parse any options passed to us.
   * -d "c1 [...]" is dead cards
   */
  while((o = getopt(argc, argv, opts)) != -1) {
    switch(o) {
    case 'd':
      len = strlen(optarg);
      for(i = 0;i < len;) {
    rc = StdDeck_stringToCard(optarg+i, &c);
    if (rc) {
      StdDeck_CardMask_SET(*dead_cards, c);
      (*num_dead)++;
      i += 2;
    } else {
      i++;
    }
      }
      break;
    }
  }

  return (*num_dead);
}
[/code]

The Count of Monte Cristo

what good is C programming going to do with his Sphere .SCP? Tongue