From f0a7b23efbdb45b29740fa080bdf42b1a327f614 Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 22 Dec 2019 22:06:24 -0800 Subject: [PATCH] little progress --- Makefile | 3 ++ card.go | 44 +++++++++++++------- cmd/hehand/main.go | 101 --------------------------------------------- deck.go | 21 ++++------ deck_test.go | 8 ++-- go.mod | 9 ++++ go.sum | 21 ++++++++++ hand.go | 59 +++++++++++++++----------- hand_test.go | 17 ++++++++ 9 files changed, 126 insertions(+), 157 deletions(-) delete mode 100644 cmd/hehand/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 hand_test.go diff --git a/Makefile b/Makefile index cb24be5..569614e 100644 --- a/Makefile +++ b/Makefile @@ -6,3 +6,6 @@ test: *.go run: cd cmd/* && go get -v && go build . + +fmt: + go fmt *.go diff --git a/card.go b/card.go index bbd92f2..6ef52fd 100644 --- a/card.go +++ b/card.go @@ -1,11 +1,8 @@ package poker -import "encoding/binary" -import "fmt" -import crand "crypto/rand" import . "github.com/logrusorgru/aurora" -import log "github.com/sirupsen/logrus" +import "fmt" import "strings" type Suit rune @@ -41,9 +38,33 @@ type Card struct { type Cards []*Card +func NewCardsFromString(input string) (*Cards, error) { + c := make(Cards, 0) + sl := strings.Split(input, ",") + for _, pc := range sl { + newCard, err := NewCardFromString(pc) + if err != nil { + return nil, err + } + c = append(c, newCard) + } + return &c, nil +} + +func NewCardFromString(input string) (*Card, error) { + if len(input) != 2 { + return nil, fmt.Errorf("invalid card string: '%s'", input) + } + nc := new(Card) + pr := input[0:1] + ps := input[1:2] + panic(fmt.Sprintf("pr=%s ps=%s nc=%s\n", pr, ps, nc)) + return nil, nil +} + func (c *Cards) formatForTerminal() (output string) { var cardstrings []string - for _, card := range *c { + for _, card := range *c { cardstrings = append(cardstrings, card.formatForTerminal()) } output = strings.Join(cardstrings, ",") @@ -65,21 +86,12 @@ func (c *Card) formatForTerminal() (output string) { color = Black } - rank = fmt.Sprintf("%s", BgGray(Bold(color(*c.Rank)))) - suit = fmt.Sprintf("%s", BgGray(Bold(color(*c.Suit)))) + rank = fmt.Sprintf("%s", BgGray(12, Bold(color(c.Rank)))) + suit = fmt.Sprintf("%s", BgGray(12, Bold(color(c.Suit)))) output = fmt.Sprintf("%s%s", rank, suit) return output } -func cryptoUint64() (v uint64) { - err := binary.Read(crand.Reader, binary.BigEndian, &v) - if err != nil { - log.Fatal(err) - } - log.Debugf("crand cryptosource is returning Uint64: %d", v) - return v -} - func (self *Card) String() string { return fmt.Sprintf("%s%s", string(self.Rank), string(self.Suit)) } diff --git a/cmd/hehand/main.go b/cmd/hehand/main.go deleted file mode 100644 index f5bf002..0000000 --- a/cmd/hehand/main.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -import ( - "errors" - "fmt" - log "github.com/sirupsen/logrus" - "github.com/sneak/poker" - "io" - "net/http" - "net/rpc" - "net/rpc/jsonrpc" - "os" - "time" -) - -type JSONRPCServer struct { - *rpc.Server -} - -func NewJSONRPCServer() *JSONRPCServer { - return &JSONRPCServer{rpc.NewServer()} -} - -func (s *JSONRPCServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { - log.Println("rpc server got a request") - conn, _, err := w.(http.Hijacker).Hijack() - if err != nil { - log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error()) - return - } - io.WriteString(conn, "HTTP/1.0 200 Connected to Go JSON-RPC\n\n") - codec := jsonrpc.NewServerCodec(conn) - log.Println("ServeCodec") - s.Server.ServeCodec(codec) - log.Println("finished serving request") -} - -type Args struct { - A, B int -} - -type Quotient struct { - Quo, Rem int -} - -type Arith int - -func (t *Arith) Multiply(args *Args, reply *int) error { - *reply = args.A * args.B - return nil -} - -func (t *Arith) Divide(args *Args, quo *Quotient) error { - if args.B == 0 { - return errors.New("divide by zero") - } - quo.Quo = args.A / args.B - quo.Rem = args.A % args.B - return nil -} - -func main() { - //log.SetFormatter(&log.JSONFormatter{}) - - // Output to stdout instead of the default stderr - // Can be any io.Writer, see below for File example - log.SetOutput(os.Stdout) - - // Only log the warning severity or above. - //log.SetLevel(log.WarnLevel) - - log.Infof("starting up") - - go runHttpServer() - - running := true - - for running { - time.Sleep(1 * time.Second) - } -} - -func runHttpServer() { - js := NewJSONRPCServer() - arith := new(Arith) - js.Register(arith) - - port := 8080 - - listenaddr := fmt.Sprintf("0.0.0.0:%d", port) - - s := &http.Server{ - Addr: listenaddr, - Handler: js, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - } - log.Infof("starting up http server %s", listenaddr) - log.Fatal(s.ListenAndServe()) -} diff --git a/deck.go b/deck.go index d69abd2..9a6fb4f 100644 --- a/deck.go +++ b/deck.go @@ -1,14 +1,10 @@ package poker import "encoding/binary" -import "fmt" import crand "crypto/rand" -import . "github.com/logrusorgru/aurora" import log "github.com/sirupsen/logrus" import rand "math/rand" -import "strings" - type Deck struct { Cards Cards DealIndex int @@ -25,19 +21,20 @@ func cryptoUint64() (v uint64) { } func NewShuffledDeck() *Deck { - d := newDeck() - d.ShuffleSeedVal = int64(cryptoUint64()) - d.Shuffle() + d := newDeck() + d.ShuffleSeedVal = int64(cryptoUint64()) + d.Shuffle() + return d } func NewDeckFromSeed(seed int64) *Deck { - d := newDeck() - d.ShuffleSeedVal = seed - d.Shuffle() + d := newDeck() + d.ShuffleSeedVal = seed + d.Shuffle() + return d } func newDeck() *Deck { - self := new(Deck) ranks := []Rank{ @@ -65,7 +62,7 @@ func newDeck() *Deck { func (self *Deck) Shuffle() { //FIXME(sneak) not sure if this is constant time or not - rnd := rand.New(rand.NewSource(self.ShuffleSeedVal))) + rnd := rand.New(rand.NewSource(self.ShuffleSeedVal)) rnd.Shuffle(len(self.Cards), func(i, j int) { self.Cards[i], self.Cards[j] = self.Cards[j], self.Cards[i] }) self.DealIndex = 0 } diff --git a/deck_test.go b/deck_test.go index 89b2bfe..f498bfc 100644 --- a/deck_test.go +++ b/deck_test.go @@ -9,19 +9,17 @@ type ShuffleTestResults []struct { } func TestPokerDeck(t *testing.T) { - d := NewDeck() - d.ShuffleDeterministically(437) + d := NewDeckFromSeed(437) cards := d.Deal(7) - //expected := "7C,5S,QS,2D,6D,QC,3H" expected := "7♣,5♠,Q♠,2♦,6♦,Q♣,3♥" assert.Equal(t, cards.String(), expected) x := d.Remaining() assert.Equal(t, 45, x) - d.ShuffleDeterministically(123456789) + d = NewDeckFromSeed(123456789) cards = d.Deal(10) - expected = "2♣,T♠,4♥,Q♣,9♦,7♥,7♠,6♥,5♥,5♠" + expected = "5♥,4♥,5♠,2♣,6♦,6♣,3♦,Q♠,8♥,A♣" assert.Equal(t, expected, cards.String()) x = d.Remaining() assert.Equal(t, 42, x) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fd60a9b --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/sneak/poker + +go 1.13 + +require ( + github.com/logrusorgru/aurora v0.0.0-20191116043053-66b7ad493a23 + github.com/sirupsen/logrus v1.4.2 + github.com/stretchr/testify v1.4.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9986f5a --- /dev/null +++ b/go.sum @@ -0,0 +1,21 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/logrusorgru/aurora v0.0.0-20191116043053-66b7ad493a23 h1:Wp7NjqGKGN9te9N/rvXYRhlVcrulGdxnz8zadXWs7fc= +github.com/logrusorgru/aurora v0.0.0-20191116043053-66b7ad493a23/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/hand.go b/hand.go index 3f427de..5a88b03 100644 --- a/hand.go +++ b/hand.go @@ -1,18 +1,24 @@ package poker +import "errors" + type HEPokerHand struct { - Cards Cards - HandScore HandScore + HoleCards Cards + CommCardsNotUsed Cards + CommCardsUsed Cards + CommCardsAll Cards + HandScore HandScore } type HandScoreType uint8 type HandScoreRanking Rank type HandScore struct { - Type HandScoreType - Ranking HandScoreRanking - Kickers Cards - Description string + Type HandScoreType + PrimaryRanking HandScoreRanking + SecondaryRanking HandScoreRanking + Kickers Cards + Description string } const ( @@ -31,40 +37,47 @@ func (self *HandScore) BeatsHand(v *HandScore) bool { panic("not implemented") } -func (self *HEPokerHand) IsReducedYet() bool { - if len(self.Cards) == 5 { - return true - } +func (self *HEPokerHand) IsPair() bool { + panic("not implemented") return false } -func (self *HEPokerHand) IsPair() bool { -} - func (self *HEPokerHand) IsTwoPair() bool { + panic("not implemented") + return false } func (self *HEPokerHand) IsSet() bool { + panic("not implemented") + return false } func (self *HEPokerHand) IsStraight() bool { + panic("not implemented") + return false } func (self *HEPokerHand) IsFlush() bool { + panic("not implemented") + return false } func (self *HEPokerHand) IsFullHouse() bool { + panic("not implemented") + return false +} + +// this takes a list of pointers to 5 or more cards, permutes them into every +// possible five-card hand, by removing each in turn and recursing to +// itself, and then returns the best one as an *HEPokerHand +// out of all possible five-card permutations. +func ScoreCardsForHoldEm(input *Cards) (*HEPokerHand, error) { + if len(*input) < 5 { + return nil, errors.New("need at least 5 cards for an HEPokerHand") + } + panic("not implemented") } func (self *HEPokerHand) ScoreHand() *HandScore { - -} - -func scoreHEPokerHand(input Cards) *HEPokerHand { - // this takes a list of pointers to 7 cards, permutes them into every - // possible five-card hand, by removing each in turn and recursing to - // itself, and then returns the best one as an *HEPokerHand - // out of all possible five-card permutations. - - return 1 + return nil } diff --git a/hand_test.go b/hand_test.go new file mode 100644 index 0000000..986e909 --- /dev/null +++ b/hand_test.go @@ -0,0 +1,17 @@ +package poker + +//import "github.com/stretchr/testify/assert" +import "fmt" +import "testing" + +func TestPokerHand(t *testing.T) { + + var v int64 + for { + v = int64(cryptoUint64()) + d := NewDeckFromSeed(v) + holeCards := d.Deal(2) + commCards := d.Deal(5) + fmt.Printf("%s %s\n", holeCards, commCards) + } +}