Using Clojure vector to model a 7 card poker hand - clojure

I have a vector that represents a 7 card poker hand and I want to find the next hand using the following method:
values are from 0 to 12 and are sorted (e.g. [0 0 7 11 11 12 12])
A valid vector has atmost 4 of one value
The first valid vector is [0 0 0 0 1 1 1]
If the values at index and index + 1 are different then increment the value at index and set all the values from 0 to index - 1 to zero
Repeat the last step until the vector is valid
For example, (next-hand [0 0 0 0 1 1 1]) would return [0 0 0 1 1 1 1] directly. However, (next-hand [0 0 0 1 1 1 1]) would loop through,
[0 0 1 1 1 1 1] (invalid)
[0 1 1 1 1 1 1] (invalid)
[1 1 1 1 1 1 1] (invalid)
[0 0 0 0 0 0 2] (invalid)
[0 0 0 0 0 1 2] (invalid)
and return this valid hand:
[0 0 0 0 1 1 2]
Here is the sudo code I have, but need to convert this to clojure. Note how I'm adding a really large integer to the end of the hand to make the last comparison always true. Thus, in the case of [1 1 1 1 1 1 1 99] the first loop would end at i=6 with 1 < 99 == true.
let hand = [hand 99]
while hand is invalid
for i in range(0,6)
if hand[i] < hand[i+1]
increment hand[i]
break
for j in range(0,i-1)
hand[j] = 0
Edit Friday, Mar 29, 2013:
In order for the select solution to work with the poker hand model I added an is-valid function like so:
(defn is-valid [v]
(let [distinct-ranks (partition-by identity v)
count-distinct (map count distinct-ranks)
max-count (apply max count-distinct)]
(<= max-count 4)))
and updated to (filter #(is-valid %) in next-hand.

One possible solution:
(defn next [v]
(let [i (->> (map < v (rest v))
(map-indexed vector)
(filter #(% 1))
first)
index (if i (i 0) 6)]
(for [[i x] (map-indexed vector v)]
(cond (= i index) (inc x)
(< i index) 0
:else x))))
(defn next-hand [v]
(->> (iterate next (next v))
(filter #(= 4 (apply + %)))
first
vec))
(next-hand [0 0 0 1 1 1 1])

Related

Clojure: Same vector values in a row checker

I'm creating an Clojure Tic Tac Toe game, where I have a board variable with 9 numbers (def moves [0 0 0 0 0 0 0 0 0]) . This variable gets filled with 1's en 2's (no "x" or "o" yet). At the end of the game the variable could look like [2 1 2 1 1 1 2 1 2] where 1 owns the second row. Now I need a function to check if there's three in a row. I wanted to start horizontally. Which means I need a function to check if there's after each 3 numbers 3 of the same number are in a row. any ideas how I can create a function like this?
So this is the function so far:
(def moves [0 0 0 0 0 0 0 0 0])
(defn wongame? [playedmoved]
(
(def counter 0)
;action here....
)
)
(won moves) ;gives true/false
Something like this should work:
(defn end-of-game? [moves]
(->> moves
(partition 3)
(remove #(= [0 0 0] %))
(map (partial apply =))
(some identity)))
With your example input of [2 1 2 1 1 1 2 1 2] (partition 3) gives:
((2 1 2) (1 1 1) (2 1 2))
We need to use = with each list. apply is required because = works with individual arguments rather than a list. partial is required because the parameters to apply = are pending. #(apply = %) could have equivalently been used.
(false true false)
some is all about '(at least) one or none'. Here if one of the list it is passed is truthy then that one will be returned.
If you really need the answer to return true/false then put a call to boolean as the last function to the thread last macro (->>). I've left that out because only rarely do you need to actually return true or false in Clojure - you can rely on nil punning.
This same function will work for vertically as well. Start off with a general transpose function that works for a matrix (e.g. [[0 0 0][0 0 0][0 0 0]]):
(defn transpose [matrix]
(apply mapv vector matrix))
Then fashion your input before, and its output after:
(defn transpose-flat [xs]
(->> xs
(partition 3)
transpose
(mapcat identity)))
(def moves [0 0 1 1 0 1 2 2 2]) #_"the game's state in the middle"
At first, if we encounter like this pattern, we need stop the game,
Otherwise we are possible to misjudge the winner of this game
if the moves reaches the state like [2 2 1 1 1 1 2 2 2]. Which is the winner? We need to call this function each turn of the game.
Second, the name "won?" isn't appropriate because this function doesn't tell the winner, but tells the end of game. "won?" function should be renamed like ["end-of-game?" "game-end?" "end?"].
Third, I try to implement "winner" that returns the winner of the game like this:
(defn winner [moves]
(let [pattern-of-end {[1 1 1]:1 [2 2 2]:2}]
(->> moves #_"I use threading macro to explain"
(partition 3) #_"group by each three symbols.
1 line of 9 elements -> 3 lines of 3 elements"
(keep pattern-of-end) #_"If there is some lines that matches
the pattern-of-end ,that will return [1] or [2]"
first #_"Because the previous expression returns lazy-seq
we can get the scalar by calling first"
)))
This tells us the winner of the game.
It would have been easier if you had proper numbers for x's and o's:
(defn the-winner-is [moves]
(let [x 5
o 7]
(->> moves
(partition 3)
(map (partial apply +))
(some #{15 21}))))
This way it even says who is the winner (15 or 21).
(the-winner-is [5 5 7 7 7 0 7 7 7]) ; 21
(the-winner-is [5 5 5 7 7 5 5 7 7]) ; 15
(the-winner-is [5 7 5 7 7 5 5 7 5]) ; nil

how to split a vector on a delimiter

I have a vector that contains numbers.
The structure of the vector is the following:
items of arbitrary length
a separator [0 0 0 0 0] (0 repeated 5 times) between the items
I want to write a function split that retrieves the list of the items (without the separator): It is similar to string/split.
For instance:
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; => [[123 0 1] [1 1] [1 0 1] [0 0 1 199]]
Remark: the code has to be effective as the length of the vector is around 1 million.
Thanks for your help.
Here:
(defn the-split [coll]
(let [part (partition-by identity coll)
ppart (partition-by #(= [0 0 0 0 0] %) part)
almost (map #(apply concat %) ppart)]
(filter (partial not= [0 0 0 0 0]) almost)))
(the-split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
=> ((123 0 1) (1 1) (1 0 1) (1 199))
Here's one approach -- with the [0 0 0 0 0] separator hardwired, but straightforward to generalize:
(defn split5z [xs]
(let [delim [0 0 0 0 0]
step (fn step [xs seg]
(lazy-seq
(if-let [xs (seq xs)]
(let [window (take 5 xs)]
(if (= window delim)
(cons seg (step (drop 5 xs) []))
(step (rest xs) (conj seg (first xs)))))
(list seg))))]
(step xs [])))
Applying it to your sample input:
(split5z [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= ([123 0 1] [1 1] [1 0 1] [1 199])
Wrap in vec if you'd like the output to be a vector rather than a seq of vectors.
Another approach -- this time eagerly consuming the input with loop/recur:
(defn split5z [sep xs]
(let [scnt (count sep)]
(loop [xs (seq xs)
out []
seg []]
(if xs
(if (= (take scnt xs) sep)
(recur (nthnext xs scnt)
(conj out seg)
[])
(recur (next xs)
out
(conj seg (first xs))))
(if (seq seg)
(conj out seg)
seg)))))
At the REPL:
(split5z [0 0 0 0 0]
[123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= [[123 0 1] [1 1] [1 0 1] [1 199]]
A lazy solution:
(defn split [v]
(let [delim (repeat 5 0)
i (->> v (partition 5 1) (take-while #(not= delim %)) count)]
(if (zero? i) [v] (lazy-seq (cons (subvec v 0 i)
(split (subvec v (+ i 5))))))))
For example
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; ([123 0 1] [1 1] [1 0 1] [0 0 1 199])

count unique values in vector in clojure

I was wondering if anyone can help me understand how can i do the below code in clojure :
int[] secondArray = new int[500];
for (int i = 0; i < firstArray.length; i++)
{
secondArray[firstArray[i]] += 1;
}
You could probably use the frequencies function:
user=> (frequencies [:foo :bar :baz :foo :foo])
{:foo 3, :bar 1, :baz 1}
Let's walk through a fairly direct translation where we treat the input vector as a sequence and then reduce it into the desired result:
First define some immutable vectors containing our starting states:
boo> (def firstVector (vec (take 30 (repeatedly #(rand-int 10)))))
#'boo/firstVector
boo> firstVector
[9 0 4 5 0 7 3 9 0 0 6 6 5 5 9 4 0 1 3 6 4 9 5 8 8 3 4 6 7 6]
boo> (def secondVector (vec (take 10 (repeat 0))))
#'boo/secondVector
boo> secondVector
[0 0 0 0 0 0 0 0 0 0]
We then want an expression that incs the appropriate element in the second array
boo> (assoc secondVector 4 (inc (secondVector 4)))
[0 0 0 0 1 0 0 0 0 0]
Then we want the result of that to be passed to the frist element in firstVector, followed by the result of that being passed to the second element in firstVector and so forth. The reduce function does this:
boo> (reduce #(assoc %1 %2 (inc (%1 %2))) secondVector firstVector)
[5 1 0 3 4 4 5 2 2 4]
in the reducer function %1 (the first argument) is the current accumulated result, and %2(the second argument) is the current value from the input sequence (firstVector).

How to count the number of ones in a vector, given an upper limit

Given a vector of ones and zeros, I would like to count the number of entries with a value one. However, the vector may be very long and I only care to know if the vector has zero, one, or more entries with a value o f one.
Using the approach given here, I can count the number of ones in the vector.
(count (filter #{1} [1 0 1 0 0 1 1]))
Can I limit filter (or use some other approach) to avoid visiting any more than three elements of the vector, in this case?
Filter is lazy, so will only do as much work as required. Since you only care about having no 1's, one 1's or two or more ones, you only need to examine up to two elements of the filtered sequence of 1's, so just take 2 before you count:
user=> (count (take 2 (filter #{1} [1 0 1 0 0 1 1])))
2
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 0])))
0
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 1])))
1
user=> (def rare (repeatedly #(if (< (rand) 0.0001) 1 0)))
#'user/rare
user=> (take 10 rare)
(0 0 0 0 0 0 0 0 0 0)
user=> (count (take 2 (filter #{1} rare)))
2

Clojure - displaying some output correctly

I'm quite new to clojure so still trying to learn... well a LOT of stuff. Right now I'm stuck on trying to get some output to display properly. Here is my function:
;function 7 - display the board
(defn display [small medium large]
(let [board (loop [i 0 boardVector [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
;(prn (bit-test small i)(bit-test medium i)(bit-test large i))
(if (< i 16)
(cond
;nothing exists
(and (not(bit-test small i))(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 0)))
;only small bit exists
(and (bit-test small i)(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 1)))
;small and medium exists on square
(and (bit-test small i)(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 3)))
;only medium exists on square
(and (not(bit-test small i))(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 2)))
;medium and large exists on square
(and (not(bit-test small i))(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 6)))
;only large exists on square
(and (not(bit-test small i))(not(bit-test medium i))(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 4)))
;all three exists on square
(and (bit-test small i)(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 7)))
)
boardVector)
)
]
(prn board)
)
)
Here is what I'm using to pass as arguments:
(display 2r1001000100 2r101001000 2r111000000)
This function takes bit variables (that are no more than 16 in length...), and calculates a final vector depending on which bits are set. a small is worth 1, medium worth 2, large worth 4. This is why I have that condition statement outlining each different possibility, excluding the possibility of having a small and large, and no medium set at the same time.
Anyhow, if none of that makes sense, here's the actual question:
How do I get my current output that displays as:
[0 0 1 2 0 0 7 4 6 1 0 0 0 0 0 0]
nil
To make it display like this?
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
I've tried using functions such as apply, map, str, interpose... but I never could figure out what the heck I was doing wrong with them. Currently I have the output displayed as a side-effect (i think that is the correct name for that...), but it's always returning nil from the output of the prn function. Dunno how to get rid of that either. Would appreciate any help!
partition it into groups of 4, then print each group:
(dorun (map #(apply println %) (partition-all 4 r)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a for expression:
(dorun (for [line (partition-all 4 r)] (apply println line)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a doseq:
(doseq [line (partition-all 4 r)] (apply println line))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
dorun (or doall) is required for the for and map examples because these are lazy and would otherwise not actually print anything unless the sequence they return was consumed. Calling apply with println and the sequence causes println to get the contents of the sequence as arguments instead of the sequence it's self, which keeps it from printing extra parens.