Merge branch 'master' of git://factorcode.org/git/factor

db4
Slava Pestov 2009-12-11 19:31:58 -05:00
commit 0d6546e994
19 changed files with 287 additions and 166 deletions

View File

@ -1,7 +1,7 @@
! Copyright (C) 2008 Doug Coleman. ! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax io.streams.string sequences USING: help.markup help.syntax io.streams.string sequences
math kernel ; math kernel quotations ;
IN: circular IN: circular
HELP: <circular-string> HELP: <circular-string>
@ -33,12 +33,12 @@ HELP: circular
HELP: growing-circular HELP: growing-circular
{ $description "A circular sequence that is growable." } ; { $description "A circular sequence that is growable." } ;
HELP: push-circular HELP: circular-push
{ $values { $values
{ "elt" object } { "circular" circular } } { "elt" object } { "circular" circular } }
{ $description "Pushes an element to a " { $link circular } " object." } ; { $description "Pushes an element to a " { $link circular } " object." } ;
HELP: push-growing-circular HELP: growing-circular-push
{ $values { $values
{ "elt" object } { "circular" circular } } { "elt" object } { "circular" circular } }
{ $description "Pushes an element onto a " { $link growing-circular } " object." } ; { $description "Pushes an element onto a " { $link growing-circular } " object." } ;
@ -48,6 +48,13 @@ HELP: rotate-circular
{ "circular" circular } } { "circular" circular } }
{ $description "Advances the start index of a circular object by one." } ; { $description "Advances the start index of a circular object by one." } ;
HELP: circular-while
{ $values
{ "circular" circular }
{ "quot" quotation }
}
{ $description "Calls " { $snippet "quot" } " on each element of the sequence until each call yields " { $link f } " in succession." } ;
ARTICLE: "circular" "Circular sequences" ARTICLE: "circular" "Circular sequences"
"The " { $vocab-link "circular" } " vocabulary implements the " { $link "sequence-protocol" } " to allow an arbitrary start index and wrap-around indexing." $nl "The " { $vocab-link "circular" } " vocabulary implements the " { $link "sequence-protocol" } " to allow an arbitrary start index and wrap-around indexing." $nl
"Creating a new circular object:" "Creating a new circular object:"
@ -63,8 +70,10 @@ ARTICLE: "circular" "Circular sequences"
} }
"Pushing new elements:" "Pushing new elements:"
{ $subsections { $subsections
push-circular circular-push
push-growing-circular growing-circular-push
} ; }
"Iterating over a circular until a stop condition:"
{ $subsections circular-while } ;
ABOUT: "circular" ABOUT: "circular"

View File

@ -23,7 +23,7 @@ IN: circular.tests
[ "boo" ] [ "foo" <circular> CHAR: b 3 pick set-nth-unsafe >string ] unit-test [ "boo" ] [ "foo" <circular> CHAR: b 3 pick set-nth-unsafe >string ] unit-test
[ "ornact" ] [ "factor" <circular> 4 over change-circular-start CHAR: n 2 pick set-nth >string ] unit-test [ "ornact" ] [ "factor" <circular> 4 over change-circular-start CHAR: n 2 pick set-nth >string ] unit-test
[ "bcd" ] [ 3 <circular-string> "abcd" [ over push-circular ] each >string ] unit-test [ "bcd" ] [ 3 <circular-string> "abcd" [ over circular-push ] each >string ] unit-test
[ { 0 0 } ] [ { 0 0 } <circular> -1 over change-circular-start >array ] unit-test [ { 0 0 } ] [ { 0 0 } <circular> -1 over change-circular-start >array ] unit-test
@ -34,11 +34,11 @@ IN: circular.tests
[ { } ] [ 3 <growing-circular> >array ] unit-test [ { } ] [ 3 <growing-circular> >array ] unit-test
[ { 1 2 } ] [ [ { 1 2 } ] [
3 <growing-circular> 3 <growing-circular>
[ 1 swap push-growing-circular ] keep [ 1 swap growing-circular-push ] keep
[ 2 swap push-growing-circular ] keep >array [ 2 swap growing-circular-push ] keep >array
] unit-test ] unit-test
[ { 3 4 5 } ] [ [ { 3 4 5 } ] [
3 <growing-circular> dup { 1 2 3 4 5 } [ 3 <growing-circular> dup { 1 2 3 4 5 } [
swap push-growing-circular swap growing-circular-push
] with each >array ] with each >array
] unit-test ] unit-test

View File

@ -1,57 +1,79 @@
! Copyright (C) 2005, 2006 Alex Chapman, Daniel Ehrenberg ! Copyright (C) 2005, 2006 Alex Chapman, Daniel Ehrenberg
! See http;//factorcode.org/license.txt for BSD license ! See http;//factorcode.org/license.txt for BSD license
USING: kernel sequences math sequences.private strings USING: kernel sequences math sequences.private strings
accessors ; accessors locals fry ;
IN: circular IN: circular
! a circular sequence wraps another sequence, but begins at an TUPLE: circular { seq read-only } { start integer } ;
! arbitrary element in the underlying sequence.
TUPLE: circular seq start ;
: <circular> ( seq -- circular ) : <circular> ( seq -- circular )
0 circular boa ; 0 circular boa ; inline
<PRIVATE <PRIVATE
: circular-wrap ( n circular -- n circular ) : circular-wrap ( n circular -- n circular )
[ start>> + ] keep [ start>> + ] keep
[ seq>> length rem ] keep ; inline [ seq>> length rem ] keep ; inline
PRIVATE> PRIVATE>
M: circular length seq>> length ; M: circular length seq>> length ; inline
M: circular virtual@ circular-wrap seq>> ; M: circular virtual@ circular-wrap seq>> ; inline
M: circular virtual-exemplar seq>> ; M: circular virtual-exemplar seq>> ; inline
: change-circular-start ( n circular -- ) : change-circular-start ( n circular -- )
#! change start to (start + n) mod length #! change start to (start + n) mod length
circular-wrap (>>start) ; circular-wrap (>>start) ; inline
: rotate-circular ( circular -- ) : rotate-circular ( circular -- )
[ 1 ] dip change-circular-start ; [ 1 ] dip change-circular-start ; inline
: push-circular ( elt circular -- ) : circular-push ( elt circular -- )
[ set-first ] [ rotate-circular ] bi ; [ set-first ] [ rotate-circular ] bi ;
: <circular-string> ( n -- circular ) : <circular-string> ( n -- circular )
0 <string> <circular> ; 0 <string> <circular> ; inline
INSTANCE: circular virtual-sequence INSTANCE: circular virtual-sequence
TUPLE: growing-circular < circular length ; TUPLE: growing-circular < circular { length integer } ;
M: growing-circular length length>> ; M: growing-circular length length>> ; inline
<PRIVATE <PRIVATE
: full? ( circular -- ? ) : full? ( circular -- ? )
[ length ] [ seq>> length ] bi = ; [ length ] [ seq>> length ] bi = ; inline
PRIVATE> PRIVATE>
: push-growing-circular ( elt circular -- ) : growing-circular-push ( elt circular -- )
dup full? [ push-circular ] dup full? [ circular-push ]
[ [ 1 + ] change-length set-last ] if ; [ [ 1 + ] change-length set-last ] if ;
: <growing-circular> ( capacity -- growing-circular ) : <growing-circular> ( capacity -- growing-circular )
{ } new-sequence 0 0 growing-circular boa ; { } new-sequence 0 0 growing-circular boa ; inline
TUPLE: circular-iterator
{ circular read-only } { n integer } { last-start integer } ;
: <circular-iterator> ( circular -- obj )
0 0 circular-iterator boa ; inline
<PRIVATE
: (circular-while) ( iterator quot: ( obj -- ? ) -- )
[ [ [ n>> ] [ circular>> ] bi nth ] dip call ] 2keep
rot [ [ dup n>> >>last-start ] dip ] when
over [ n>> ] [ [ last-start>> ] [ circular>> length ] bi + 1 - ] bi = [
2drop
] [
[ [ 1 + ] change-n ] dip (circular-while)
] if ; inline recursive
PRIVATE>
: circular-while ( circular quot: ( obj -- ? ) -- )
[ clone ] dip [ <circular-iterator> ] dip (circular-while) ; inline

View File

@ -4,6 +4,18 @@ USING: classes help.markup help.syntax io.streams.string
strings math calendar io.files.info io.files.info.unix ; strings math calendar io.files.info io.files.info.unix ;
IN: io.files.unix IN: io.files.unix
HELP: add-file-permissions
{ $values
{ "path" "a pathname string" }
{ "n" integer } }
{ $description "Ensures that the bits from " { $snippet "n" } " are set in the Unix file permissions for a given file." } ;
HELP: remove-file-permissions
{ $values
{ "path" "a pathname string" }
{ "n" integer } }
{ $description "Ensures that the bits from " { $snippet "n" } " are cleared in the Unix file permissions for a given file." } ;
HELP: file-group-id HELP: file-group-id
{ $values { $values
{ "path" "a pathname string" } { "path" "a pathname string" }
@ -231,8 +243,12 @@ ARTICLE: "unix-file-permissions" "Unix file permissions"
other-write? other-write?
other-execute? other-execute?
} }
"Writing all file permissions:" "Changing file permissions:"
{ $subsections set-file-permissions } { $subsections
add-file-permissions
remove-file-permissions
set-file-permissions
}
"Writing individual file permissions:" "Writing individual file permissions:"
{ $subsections { $subsections
set-uid set-uid

View File

@ -5,7 +5,7 @@ sequences combinators combinators.short-circuit alien.c-types
vocabs.loader calendar calendar.unix io.files.info vocabs.loader calendar calendar.unix io.files.info
io.files.types io.backend io.directories unix unix.stat io.files.types io.backend io.directories unix unix.stat
unix.time unix.users unix.groups classes.struct unix.time unix.users unix.groups classes.struct
specialized-arrays ; specialized-arrays literals ;
SPECIALIZED-ARRAY: timeval SPECIALIZED-ARRAY: timeval
IN: io.files.info.unix IN: io.files.info.unix
@ -134,6 +134,9 @@ CONSTANT: OTHER-ALL OCT: 0000007
CONSTANT: OTHER-READ OCT: 0000004 CONSTANT: OTHER-READ OCT: 0000004
CONSTANT: OTHER-WRITE OCT: 0000002 CONSTANT: OTHER-WRITE OCT: 0000002
CONSTANT: OTHER-EXECUTE OCT: 0000001 CONSTANT: OTHER-EXECUTE OCT: 0000001
CONSTANT: ALL-READ OCT: 0000444
CONSTANT: ALL-WRITE OCT: 0000222
CONSTANT: ALL-EXECUTE OCT: 0000111
: uid? ( obj -- ? ) UID file-mode? ; : uid? ( obj -- ? ) UID file-mode? ;
: gid? ( obj -- ? ) GID file-mode? ; : gid? ( obj -- ? ) GID file-mode? ;
@ -176,6 +179,12 @@ CONSTANT: OTHER-EXECUTE OCT: 0000001
: file-permissions ( path -- n ) : file-permissions ( path -- n )
normalize-path file-info permissions>> ; normalize-path file-info permissions>> ;
: add-file-permissions ( path n -- )
over file-permissions bitor set-file-permissions ;
: remove-file-permissions ( path n -- )
over file-permissions [ bitnot ] dip bitand set-file-permissions ;
M: unix copy-file-and-info ( from to -- ) M: unix copy-file-and-info ( from to -- )
[ copy-file ] [ swap file-permissions set-file-permissions ] 2bi ; [ copy-file ] [ swap file-permissions set-file-permissions ] 2bi ;

View File

@ -103,23 +103,26 @@ C: <combo> combo
: apply-combination ( m combo -- seq ) : apply-combination ( m combo -- seq )
[ combination-indices ] keep seq>> nths ; [ combination-indices ] keep seq>> nths ;
: combinations-quot ( seq k quot -- seq quot )
[ <combo> [ choose [0,b) ] keep ] dip
'[ _ apply-combination @ ] ; inline
PRIVATE> PRIVATE>
: each-combination ( seq k quot -- )
combinations-quot each ; inline
: map-combinations ( seq k quot -- )
combinations-quot map ; inline
: map>assoc-combinations ( seq k quot exemplar -- )
[ combinations-quot ] dip map>assoc ; inline
: combination ( m seq k -- seq ) : combination ( m seq k -- seq )
<combo> apply-combination ; <combo> apply-combination ;
: all-combinations ( seq k -- seq ) : all-combinations ( seq k -- seq )
<combo> [ choose [0,b) ] keep [ ] combinations-quot map ;
'[ _ apply-combination ] map ;
: each-combination ( seq k quot -- )
[ <combo> [ choose [0,b) ] keep ] dip
'[ _ apply-combination @ ] each ; inline
: map-combinations ( seq k quot -- )
[ <combo> [ choose [0,b) ] keep ] dip
'[ _ apply-combination @ ] map ; inline
: reduce-combinations ( seq k identity quot -- result ) : reduce-combinations ( seq k identity quot -- result )
[ -rot ] dip each-combination ; inline [ -rot ] dip each-combination ; inline

View File

@ -38,7 +38,7 @@ HELP: range
HELP: minmax HELP: minmax
{ $values { "seq" sequence } { "min" real } { "max" real } } { $values { "seq" sequence } { "min" real } { "max" real } }
{ $description "Finds the minimum and maximum elements of " { $snippet "seq" } " in one pass." } { $description "Finds the minimum and maximum elements of " { $snippet "seq" } " in one pass. Throws an error on an empty sequence." }
{ $examples { $examples
{ $example "USING: arrays math.statistics prettyprint ;" { $example "USING: arrays math.statistics prettyprint ;"
"{ 1 2 3 } minmax 2array ." "{ 1 2 3 } minmax 2array ."

View File

@ -89,9 +89,14 @@ PRIVATE>
histogram >alist histogram >alist
[ ] [ [ [ second ] bi@ > ] 2keep ? ] map-reduce first ; [ ] [ [ [ second ] bi@ > ] 2keep ? ] map-reduce first ;
ERROR: empty-sequence ;
: minmax ( seq -- min max ) : minmax ( seq -- min max )
#! find the min and max of a seq in one pass [
[ 1/0. -1/0. ] dip [ [ min ] [ max ] bi-curry bi* ] each ; empty-sequence
] [
[ first dup ] keep [ [ min ] [ max ] bi-curry bi* ] each
] if-empty ;
: range ( seq -- x ) : range ( seq -- x )
minmax swap - ; minmax swap - ;

View File

@ -83,7 +83,7 @@ TUPLE: sequence-parser sequence n ;
sequence length <growing-circular> :> growing sequence length <growing-circular> :> growing
sequence-parser sequence-parser
[ [
current growing push-growing-circular current growing growing-circular-push
sequence growing sequence= sequence growing sequence=
] take-until :> found ] take-until :> found
growing sequence sequence= [ growing sequence sequence= [

View File

@ -1,5 +1,5 @@
! (c)2009 Joe Groff bsd license ! (c)2009 Joe Groff bsd license
USING: help.markup help.syntax quotations sequences ; USING: assocs help.markup help.syntax quotations sequences ;
IN: sequences.product IN: sequences.product
HELP: product-sequence HELP: product-sequence
@ -44,6 +44,14 @@ HELP: product-map
{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output sequence." } { $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output sequence." }
{ $notes { $snippet "[ ... ] product-map" } " is equivalent to, but more efficient than, " { $snippet "<product-sequence> [ ... ] map" } "." } ; { $notes { $snippet "[ ... ] product-map" } " is equivalent to, but more efficient than, " { $snippet "<product-sequence> [ ... ] map" } "." } ;
HELP: product-map-as
{ $values { "sequences" sequence } { "quot" { $quotation "( sequence -- value )" } } { "exemplar" sequence } { "sequence" sequence } }
{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output sequence the same type as the " { $snippet "exemplar" } " sequence." } ;
HELP: product-map>assoc
{ $values { "sequences" sequence } { "quot" { $quotation "( sequence -- key value )" } } { "exemplar" assoc } { "assoc" assoc } }
{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output assoc." } ;
HELP: product-each HELP: product-each
{ $values { "sequences" sequence } { "quot" { $quotation "( sequence -- )" } } } { $values { "sequences" sequence } { "quot" { $quotation "( sequence -- )" } } }
{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } "." } { $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } "." }
@ -57,6 +65,8 @@ ARTICLE: "sequences.product" "Product sequences"
product-sequence product-sequence
<product-sequence> <product-sequence>
product-map product-map
product-map-as
product-map>assoc
product-each product-each
} ; } ;

View File

@ -1,5 +1,5 @@
! (c)2009 Joe Groff bsd license ! (c)2009 Joe Groff bsd license
USING: accessors arrays kernel locals math sequences ; USING: accessors arrays assocs kernel locals math sequences ;
IN: sequences.product IN: sequences.product
TUPLE: product-sequence { sequences array read-only } { lengths array read-only } ; TUPLE: product-sequence { sequences array read-only } { lengths array read-only } ;
@ -55,11 +55,21 @@ M: product-sequence nth
[ ns sequences nths quot call ns lengths product-iter ] until [ ns sequences nths quot call ns lengths product-iter ] until
] unless ; inline ] unless ; inline
:: product-map ( sequences quot -- sequence ) :: product-map-as ( sequences quot exemplar -- sequence )
0 :> i! 0 :> i!
sequences [ length ] [ * ] map-reduce sequences sequences [ length ] [ * ] map-reduce exemplar
[| result | [| result |
sequences [ quot call i result set-nth i 1 + i! ] product-each sequences [ quot call i result set-nth i 1 + i! ] product-each
result result
] new-like ; inline ] new-like ; inline
: product-map ( sequences quot -- sequence )
over product-map-as ; inline
:: product-map>assoc ( sequences quot exemplar -- assoc )
0 :> i!
sequences [ length ] [ * ] map-reduce { }
[| result |
sequences [ quot call 2array i result set-nth i 1 + i! ] product-each
result
] new-like exemplar assoc-like ; inline

View File

@ -86,7 +86,7 @@ HINTS: next* { spot } ;
spot get '[ _ char>> blank? not ] skip-until ; spot get '[ _ char>> blank? not ] skip-until ;
: string-matches? ( string circular spot -- ? ) : string-matches? ( string circular spot -- ? )
char>> over push-circular sequence= ; char>> over circular-push sequence= ;
: take-string ( match -- string ) : take-string ( match -- string )
dup length <circular-string> dup length <circular-string>
@ -147,7 +147,7 @@ HINTS: next* { spot } ;
:: parse-text ( -- string ) :: parse-text ( -- string )
3 f <array> <circular> :> circ 3 f <array> <circular> :> circ
depth get zero? :> no-text [| char | depth get zero? :> no-text [| char |
char circ push-circular char circ circular-push
circ assure-no-]]> circ assure-no-]]>
no-text [ char blank? char CHAR: < = or [ no-text [ char blank? char CHAR: < = or [
char 1string t pre/post-content char 1string t pre/post-content

View File

@ -1002,7 +1002,7 @@ HELP: pusher
"10 [ even? ] pusher [ each ] dip ." "10 [ even? ] pusher [ each ] dip ."
"V{ 0 2 4 6 8 }" "V{ 0 2 4 6 8 }"
} }
{ $notes "Used to implement the " { $link filter } " word." } ; { $notes "Used to implement the " { $link filter } " word. Compare this word with " { $link accumulator } ", which is an unfiltering version." } ;
HELP: trim-head HELP: trim-head
{ $values { $values
@ -1671,6 +1671,19 @@ ARTICLE: "sequences-comparing" "Comparing sequences"
ARTICLE: "sequences-f" "The f object as a sequence" ARTICLE: "sequences-f" "The f object as a sequence"
"The " { $link f } " object supports the sequence protocol in a trivial way. It responds with a length of zero and throws an out of bounds error when an attempt is made to access elements." ; "The " { $link f } " object supports the sequence protocol in a trivial way. It responds with a length of zero and throws an out of bounds error when an attempt is made to access elements." ;
ARTICLE: "sequences-combinator-implementation" "Implementing sequence combinators"
"Creating a new sequence unconditionally:"
{ $subsections
accumulator
accumulator-for
}
"Creating a new sequence conditionally:"
{ $subsections
pusher
pusher-for
2pusher
} ;
ARTICLE: "sequences" "Sequence operations" ARTICLE: "sequences" "Sequence operations"
"A " { $emphasis "sequence" } " is a finite, linearly-ordered collection of elements. Words for working with sequences are in the " { $vocab-link "sequences" } " vocabulary." "A " { $emphasis "sequence" } " is a finite, linearly-ordered collection of elements. Words for working with sequences are in the " { $vocab-link "sequences" } " vocabulary."
$nl $nl
@ -1708,6 +1721,8 @@ $nl
"Using sequences for control flow:" "Using sequences for control flow:"
{ $subsections "sequences-if" } { $subsections "sequences-if" }
"For inner loops:" "For inner loops:"
{ $subsections "sequences-unsafe" } ; { $subsections "sequences-unsafe" }
"Implemeting sequence combinators:"
{ $subsections "sequences-combinator-implementation" } ;
ABOUT: "sequences" ABOUT: "sequences"

View File

@ -1,30 +1,26 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors sequences kernel math io calendar grouping USING: accessors calendar.format calendar.model fonts fry
calendar.format calendar.model fonts arrays models models.arrow grouping kernel math models.arrow namespaces sequences ui
namespaces ui.gadgets ui.gadgets.labels ui ; ui.gadgets.labels ;
IN: lcd IN: lcd
: lcd-digit ( row digit -- str ) : lcd-digit ( digit row -- str )
dup CHAR: : = [ drop 10 ] [ CHAR: 0 - ] if swap { [ dup CHAR: : = [ drop 10 ] [ CHAR: 0 - ] if ] dip {
" _ _ _ _ _ _ _ _ " " _ _ _ _ _ _ _ _ "
" | | | _| _| |_| |_ |_ | |_| |_| * " " | | | _| _| |_| |_ |_ | |_| |_| * "
" |_| | |_ _| | _| |_| | |_| | * " " |_| | |_ _| | _| |_| | |_| | * "
" " " "
} nth 4 <groups> nth ; } nth 4 <groups> nth ;
: lcd-row ( num row -- string ) : lcd-row ( row digit -- string )
[ swap lcd-digit ] curry { } map-as concat ; '[ _ lcd-digit ] { } map-as concat ;
: lcd ( digit-str -- string ) : lcd ( digit-str -- string )
4 [ lcd-row ] with map "\n" join ; 4 iota [ lcd-row ] with map "\n" join ;
: hh:mm:ss ( timestamp -- string ) : <time-display> ( model -- gadget )
[ hour>> ] [ minute>> ] [ second>> >fixnum ] tri [ timestamp>hms lcd ] <arrow> <label-control>
3array [ pad-00 ] map ":" join ;
: <time-display> ( timestamp -- gadget )
[ hh:mm:ss lcd ] <arrow> <label-control>
"99:99:99" lcd >>string "99:99:99" lcd >>string
monospace-font >>font ; monospace-font >>font ;

View File

@ -1,46 +1,16 @@
USING: help.markup help.syntax strings ; USING: help.markup help.syntax math sequences strings ;
IN: poker IN: poker
HELP: <hand> HELP: best-holdem-hand
{ $values { "str" string } { "hand" "a new " { $link hand } } } { $values { "hand" sequence } { "n" integer } { "cards" sequence } }
{ $description "Creates a new poker hand containing the cards specified in " { $snippet "str" } "." } { $description "Creates a new poker hand containing the best possible combination of the cards specified in " { $snippet "seq" } "." }
{ $examples
{ $example "USING: kernel math.order poker prettyprint ;"
"\"AC KC QC JC TC\" \"7C 6D 5H 4S 2C\" [ <hand> ] bi@ <=> ." "+lt+" }
{ $example "USING: kernel poker prettyprint ;"
"\"TC 9C 8C 7C 6C\" \"TH 9H 8H 7H 6H\" [ <hand> ] bi@ = ." "t" }
}
{ $notes "Cards may be specified in any order. Hands are directly comparable to each other on the basis of their computed value. Two hands are considered equal when they would tie in a game (despite being composed of different cards)." } ;
HELP: best-hand
{ $values { "str" string } { "hand" "a new " { $link hand } } }
{ $description "Creates a new poker hand containing the best possible combination of the cards specified in " { $snippet "str" } "." }
{ $examples { $examples
{ $example "USING: kernel poker prettyprint ;" { $example "USING: kernel poker prettyprint ;"
"\"AS KD JC KH 2D 2S KC\" best-hand >value ." "\"Full House\"" } "HAND{ AS KD JC KH 2D 2S KC } best-holdem-hand drop value>hand-name ."
""""Full House""""
}
} ; } ;
HELP: >cards
{ $values { "hand" hand } { "str" string } }
{ $description "Outputs a string representation of a hand's cards." }
{ $examples
{ $example "USING: poker prettyprint ;"
"\"AC KC QC JC TC\" <hand> >cards ." "\"AC KC QC JC TC\"" }
} ;
HELP: >value
{ $values { "hand" hand } { "str" string } }
{ $description "Outputs a string representation of a hand's value." }
{ $examples
{ $example "USING: poker prettyprint ;"
"\"AC KC QC JC TC\" <hand> >value ." "\"Straight Flush\"" }
}
{ $notes "This should not be used as a basis for hand comparison." } ;
HELP: <deck> HELP: <deck>
{ $values { "deck" "a new " { $link deck } } } { $values { "deck" sequence } }
{ $description "Creates a standard deck of 52 cards." } ; { $description "Returns a vector containing a standard, shuffled deck of 52 cards." } ;
HELP: shuffle
{ $values { "deck" deck } { "deck" "a shuffled " { $link deck } } }
{ $description "Shuffles the cards in " { $snippet "deck" } ", in-place, using the Fisher-Yates algorithm." } ;

View File

@ -1,30 +1,28 @@
USING: accessors kernel math.order poker poker.private tools.test ; USING: accessors kernel math math.order poker poker.private
tools.test ;
IN: poker.tests IN: poker.tests
[ 134236965 ] [ "KD" >ckf ] unit-test [ 134236965 ] [ "KD" >ckf ] unit-test
[ 529159 ] [ "5s" >ckf ] unit-test [ 529159 ] [ "5s" >ckf ] unit-test
[ 33589533 ] [ "jc" >ckf ] unit-test [ 33589533 ] [ "jc" >ckf ] unit-test
[ 7462 ] [ "7C 5D 4H 3S 2C" <hand> value>> ] unit-test [ 7462 ] [ "7C 5D 4H 3S 2C" string>value ] unit-test
[ 1601 ] [ "KD QS JC TH 9S" <hand> value>> ] unit-test [ 1601 ] [ "KD QS JC TH 9S" string>value ] unit-test
[ 11 ] [ "AC AD AH AS KC" <hand> value>> ] unit-test [ 11 ] [ "AC AD AH AS KC" string>value ] unit-test
[ 9 ] [ "6C 5C 4C 3C 2C" <hand> value>> ] unit-test [ 9 ] [ "6C 5C 4C 3C 2C" string>value ] unit-test
[ 1 ] [ "AC KC QC JC TC" <hand> value>> ] unit-test [ 1 ] [ "AC KC QC JC TC" string>value ] unit-test
[ "High Card" ] [ "7C 5D 4H 3S 2C" <hand> >value ] unit-test [ "High Card" ] [ "7C 5D 4H 3S 2C" string>hand-name ] unit-test
[ "Straight" ] [ "KD QS JC TH 9S" <hand> >value ] unit-test [ "Straight" ] [ "KD QS JC TH 9S" string>hand-name ] unit-test
[ "Four of a Kind" ] [ "AC AD AH AS KC" <hand> >value ] unit-test [ "Four of a Kind" ] [ "AC AD AH AS KC" string>hand-name ] unit-test
[ "Straight Flush" ] [ "6C 5C 4C 3C 2C" <hand> >value ] unit-test [ "Straight Flush" ] [ "6C 5C 4C 3C 2C" string>hand-name ] unit-test
[ "6C 5C 4C 3C 2C" ] [ "6C 5C 4C 3C 2C" <hand> >cards ] unit-test [ t ] [ "7C 5D 4H 3S 2C" "KD QS JC TH 9S" [ string>value ] bi@ > ] unit-test
[ t ] [ "AC AD AH AS KC" "KD QS JC TH 9S" [ string>value ] bi@ < ] unit-test
[ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ string>value ] bi@ = ] unit-test
[ +gt+ ] [ "7C 5D 4H 3S 2C" "KD QS JC TH 9S" [ <hand> ] bi@ <=> ] unit-test [ t ] [ "7C 5D 4H 3S 2C" "2C 3S 4H 5D 7C" [ string>value ] bi@ = ] unit-test
[ +lt+ ] [ "AC AD AH AS KC" "KD QS JC TH 9S" [ <hand> ] bi@ <=> ] unit-test
[ +eq+ ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ <hand> ] bi@ <=> ] unit-test
[ t ] [ "7C 5D 4H 3S 2C" "2C 3S 4H 5D 7C" [ <hand> ] bi@ = ] unit-test [ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ string>value ] bi@ = ] unit-test
[ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ <hand> ] bi@ = ] unit-test [ 190 ] [ "AS KD JC KH 2D 2S KC" string>value ] unit-test
[ f ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ <hand> ] bi@ eq? ] unit-test
[ 190 ] [ "AS KD JC KH 2D 2S KC" best-hand value>> ] unit-test

View File

@ -1,9 +1,11 @@
! Copyright (c) 2009 Aaron Schaefer. All rights reserved. ! Copyright (c) 2009 Aaron Schaefer. All rights reserved.
! Copyright (c) 2009 Doug Coleman.
! The contents of this file are licensed under the Simplified BSD License ! The contents of this file are licensed under the Simplified BSD License
! A copy of the license is available at http://factorcode.org/license.txt ! A copy of the license is available at http://factorcode.org/license.txt
USING: accessors arrays ascii binary-search combinators kernel locals math USING: accessors arrays ascii assocs binary-search combinators
math.bitwise math.combinatorics math.order poker.arrays random sequences fry kernel locals math math.bitwise math.combinatorics
sequences.product splitting ; math.order math.statistics poker.arrays random sequences
sequences.product splitting grouping lexer strings ;
IN: poker IN: poker
! The algorithm used is based on Cactus Kev's Poker Hand Evaluator with ! The algorithm used is based on Cactus Kev's Poker Hand Evaluator with
@ -108,11 +110,13 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush"
:: (>ckf) ( rank suit -- n ) :: (>ckf) ( rank suit -- n )
rank rank suit rank card-bitfield ; rank rank suit rank card-bitfield ;
: >ckf ( str -- n ) #! Cactus Kev Format
#! Cactus Kev Format GENERIC: >ckf ( string -- n )
>upper 1 cut (>ckf) ;
: parse-cards ( str -- seq ) M: string >ckf >upper 1 cut (>ckf) ;
M: integer >ckf ;
: parse-cards ( string -- seq )
" " split [ >ckf ] map ; " " split [ >ckf ] map ;
: flush? ( cards -- ? ) : flush? ( cards -- ? )
@ -148,10 +152,10 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush"
] if ] if
] if ; ] if ;
: >card-rank ( card -- str ) : >card-rank ( card -- string )
-8 shift HEX: F bitand RANK_STR nth ; -8 shift HEX: F bitand RANK_STR nth ;
: >card-suit ( card -- str ) : >card-suit ( card -- string )
{ {
{ [ dup 15 bit? ] [ drop "C" ] } { [ dup 15 bit? ] [ drop "C" ] }
{ [ dup 14 bit? ] [ drop "D" ] } { [ dup 14 bit? ] [ drop "D" ] }
@ -159,7 +163,7 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush"
[ drop "S" ] [ drop "S" ]
} cond ; } cond ;
: hand-rank ( value -- rank ) : value>rank ( value -- rank )
{ {
{ [ dup 6185 > ] [ drop HIGH_CARD ] } ! 1277 high card { [ dup 6185 > ] [ drop HIGH_CARD ] } ! 1277 high card
{ [ dup 3325 > ] [ drop ONE_PAIR ] } ! 2860 one pair { [ dup 3325 > ] [ drop ONE_PAIR ] } ! 2860 one pair
@ -172,38 +176,92 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush"
[ drop STRAIGHT_FLUSH ] ! 10 straight-flushes [ drop STRAIGHT_FLUSH ] ! 10 straight-flushes
} cond ; } cond ;
: card>string ( card -- str ) : card>string ( n -- string )
[ >card-rank ] [ >card-suit ] bi append ; [ >card-rank ] [ >card-suit ] bi append ;
PRIVATE> PRIVATE>
TUPLE: hand
{ cards sequence }
{ value integer initial: 9999 } ;
M: hand <=> [ value>> ] compare ;
M: hand equal?
over hand? [ [ value>> ] bi@ = ] [ 2drop f ] if ;
: <hand> ( str -- hand )
parse-cards dup hand-value hand boa ;
: best-hand ( str -- hand )
parse-cards 5 hand new
[ dup hand-value hand boa min ] reduce-combinations ;
: >cards ( hand -- str )
cards>> [ card>string ] map " " join ;
: >value ( hand -- str )
value>> hand-rank VALUE_STR nth ;
TUPLE: deck
{ cards sequence } ;
: <deck> ( -- deck ) : <deck> ( -- deck )
RANK_STR SUIT_STR 2array [ concat >ckf ] product-map deck boa ; RANK_STR SUIT_STR 2array
[ concat >ckf ] V{ } product-map-as randomize ;
: shuffle ( deck -- deck ) : best-holdem-hand ( hand -- n cards )
[ randomize ] change-cards ; 5 [ [ hand-value ] [ ] bi ] { } map>assoc-combinations
infimum first2 ;
: value>string ( n -- string )
value>rank VALUE_STR nth ;
: hand>card-names ( hand -- string )
[ card>string ] map ;
: string>value ( string -- value )
parse-cards best-holdem-hand drop ;
ERROR: no-card card deck ;
: draw-specific-card ( card deck -- card )
[ >ckf ] dip
2dup index [ swap remove-nth! drop ] [ no-card ] if* ;
: start-hands ( seq -- seq' deck )
<deck> [ '[ [ _ draw-specific-card ] map ] map ] keep ;
:: holdem-hand% ( hole1 deck community n -- x )
community length 5 swap - 2 + :> #samples
n [
drop
deck #samples sample :> sampled
sampled 2 cut :> ( hole2 community2 )
hole1 community community2 3append :> hand1
hole2 community community2 3append :> hand2
hand1 hand2 [ best-holdem-hand 2array ] bi@ <=> +lt+ =
] count ;
:: compare-holdem-hands ( holes deck n -- seq )
n [
holes deck 5 sample '[
[ _ append best-holdem-hand drop ] keep
] { } map>assoc infimum second
] replicate histogram ;
: (best-omaha-hand) ( seq -- pair )
4 cut
[ 2 all-combinations ] [ 3 all-combinations ] bi*
2array [ concat [ best-holdem-hand drop ] keep ] { } product-map>assoc ;
: best-omaha-hand ( seq -- n cards ) (best-omaha-hand) infimum first2 ;
:: compare-omaha-hands ( holes deck n -- seq )
n [
holes deck 5 sample '[
[ _ append best-omaha-hand drop ] keep
] { } map>assoc infimum second
] replicate histogram ;
ERROR: bad-suit-symbol ch ;
: symbol>suit ( ch -- ch' )
ch>upper
H{
{ CHAR: ♠ CHAR: S }
{ CHAR: ♦ CHAR: D }
{ CHAR: ♥ CHAR: H }
{ CHAR: ♣ CHAR: C }
{ CHAR: S CHAR: S }
{ CHAR: D CHAR: D }
{ CHAR: H CHAR: H }
{ CHAR: C CHAR: C }
} ?at [ bad-suit-symbol ] unless ;
: card> ( string -- card )
1 over [ symbol>suit ] change-nth >ckf ;
: value>hand-name ( value -- string )
value>rank VALUE_STR nth ;
: string>hand-name ( string -- string' )
string>value value>hand-name ;
SYNTAX: HAND{
"}" parse-tokens [ card> ] { } map-as suffix! ;

View File

@ -76,7 +76,7 @@ IN: project-euler.054
PRIVATE> PRIVATE>
: euler054 ( -- answer ) : euler054 ( -- answer )
source-054 [ [ <hand> ] map first2 before? ] count ; source-054 [ [ string>value ] map first2 before? ] count ;
! [ euler054 ] 100 ave-time ! [ euler054 ] 100 ave-time
! 34 ms ave run time - 2.65 SD (100 trials) ! 34 ms ave run time - 2.65 SD (100 trials)

View File

@ -45,7 +45,7 @@ IN: project-euler.186
55 [1,b] [ (generator) ] map <circular> ; 55 [1,b] [ (generator) ] map <circular> ;
: advance ( lag -- ) : advance ( lag -- )
[ { 0 31 } swap nths sum 1000000 rem ] keep push-circular ; [ { 0 31 } swap nths sum 1000000 rem ] keep circular-push ;
: next ( lag -- n ) : next ( lag -- n )
[ first ] [ advance ] bi ; [ first ] [ advance ] bi ;