mmmm
This commit is contained in:
parent
a5ed95b86d
commit
23d38adf7f
4 changed files with 277 additions and 121 deletions
108
cards.ml
108
cards.ml
|
@ -1,6 +1,5 @@
|
|||
open List;;
|
||||
open Core;;
|
||||
open Out_channel;;
|
||||
open String;;
|
||||
|
||||
Random.self_init ();;
|
||||
|
||||
|
@ -20,22 +19,111 @@ let card_type_to_string = function
|
|||
|
||||
type card = { seed: card_type ; value: int }
|
||||
|
||||
let card_to_string c = String.concat ["{ seed: "; card_type_to_string c.seed;
|
||||
"; value: "; string_of_int c.value; " }"]
|
||||
let print_card chan card = Out_channel.output_string chan (card_to_string card);;
|
||||
let value_cmp a b = Int.compare a.value b.value
|
||||
let make seed value =
|
||||
{ seed=seed; value=value }
|
||||
|
||||
let value_cmp a b = if a.value < b.value then -1 else if a.value = b.value then 0 else 1 (* TFW TODO *)
|
||||
let seed_cmp = fun a b -> if card_type_to_string a.seed > card_type_to_string b.seed then 1 else
|
||||
if card_type_to_string a.seed = card_type_to_string b.seed then 0 else -1
|
||||
|
||||
let make_set tp =
|
||||
List.map ~f:(fun x -> { seed=tp; value=x }) (List.range 1 14);; (* make a set of cards of one seed *)
|
||||
let rec range start _end accum = if start < _end then range (start+1) _end accum@[start] else accum in
|
||||
List.map (fun x -> { seed=tp; value=x }) (range 1 14 []);; (* make a set of cards of one seed *)
|
||||
let init =
|
||||
List.concat [make_set Hearts ; make_set Tiles ; make_set Clovers ; make_set Pikes ;
|
||||
make_set Hearts ; make_set Tiles ; make_set Clovers ; make_set Pikes] |>
|
||||
List.map ~f:(fun e -> Random.bits (), e) |>
|
||||
List.sort ~compare:(fun a b -> if fst a > fst b then 1 else -1) |>
|
||||
List.map ~f:snd
|
||||
List.map (fun e -> Random.bits (), e) |>
|
||||
List.sort (fun a b -> if fst a > fst b then 1 else -1) |>
|
||||
List.map snd
|
||||
|
||||
let draw deck = match deck with
|
||||
| [] as l -> {seed=Nothing ; value=0}, l
|
||||
| hd::tl -> hd, tl
|
||||
|
||||
let no_double_seed cards =
|
||||
List.sort_uniq seed_cmp cards |> List.length = List.length cards
|
||||
|
||||
let is_only_one_seed cards =
|
||||
List.sort_uniq seed_cmp cards |> List.length = 1
|
||||
|
||||
let no_double_value cards =
|
||||
List.sort_uniq value_cmp cards |> List.length = List.length cards
|
||||
|
||||
let is_tris cards =
|
||||
match (List.sort_uniq value_cmp cards) with
|
||||
| [_] -> no_double_seed cards (* only one value, check for right seeds *)
|
||||
| _::_ -> false
|
||||
| [] -> assert false
|
||||
|
||||
let rec split l fst =
|
||||
match l with
|
||||
| hd::hd'::tl when hd=hd'-1 -> split (hd'::tl) (fst@[hd])
|
||||
| hd::tl -> fst@[hd], tl
|
||||
| [] -> assert false
|
||||
|
||||
|
||||
let is_straight _cards =
|
||||
let rec _is_straight cards =
|
||||
match cards with
|
||||
| hd::hd'::tl when hd=hd'-1 -> _is_straight (hd'::tl)
|
||||
| [] -> assert false
|
||||
| [_] -> true (* list was consumed *)
|
||||
| _::_ -> false in
|
||||
|
||||
if (not (no_double_value _cards && is_only_one_seed _cards)) then
|
||||
false
|
||||
else
|
||||
let last = List.rev _cards |> hd in
|
||||
let cards = List.map (fun c -> c.value) _cards (* use only values *) in
|
||||
if last.value = 13 && (hd cards) = 1 then (* circolare *)
|
||||
let fst, snd = split cards [] in (_is_straight fst) && (_is_straight snd)
|
||||
else
|
||||
_is_straight cards
|
||||
|
||||
let is_valid _cards =
|
||||
let cards = List.sort value_cmp _cards in
|
||||
if List.length cards < 3 then
|
||||
false
|
||||
else
|
||||
match cards with
|
||||
| a::b::_ when value_cmp a b = 0 -> is_tris cards
|
||||
| _ -> is_straight cards;;
|
||||
|
||||
|
||||
|
||||
(* TEST TODO *)
|
||||
let cards = [{seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Tiles; value=1}; {seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Tiles; value=2}; {seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=2}; {seed=Hearts; value=2}; {seed=Hearts; value=4}]
|
||||
in assert (not (no_double_value cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=2}; {seed=Hearts; value=2}; {seed=Hearts; value=4}]
|
||||
in assert (not (no_double_seed cards));;
|
||||
|
||||
let cards = [{seed=Pikes; value=2}; {seed=Clovers; value=2}; {seed=Tiles; value=4}; {seed=Hearts; value=4}]
|
||||
in assert (no_double_seed cards);;
|
||||
|
||||
let cards = [{seed=Hearts; value=4}; {seed=Hearts; value=3}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Hearts; value=13}; {seed=Hearts; value=12}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Pikes; value=13}; {seed=Hearts; value=12}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Pikes; value=13}; {seed=Pikes; value=12}; {seed=Pikes; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
let cards = [{seed=Hearts; value=12}; {seed=Pikes; value=12}; {seed=Pikes; value=1}]
|
||||
in assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=13}; {seed=Hearts; value=3}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
|
|
161
main.ml
161
main.ml
|
@ -1,9 +1,54 @@
|
|||
open List
|
||||
open Cards
|
||||
open Core;;
|
||||
open Out_channel;;
|
||||
|
||||
type ingame_cards = card list
|
||||
type player = { name: string ; cards: card list }
|
||||
type table = { deck: card list ; ingame: ingame_cards; players: player list }
|
||||
open Cards;;
|
||||
open Tcards;;
|
||||
open Table;;
|
||||
|
||||
let card_to_string c = String.concat ["{ seed: "; card_type_to_string c.seed;
|
||||
"; value: "; string_of_int c.value; " }"]
|
||||
let print_card chan card = Out_channel.output_string chan (card_to_string card);;
|
||||
|
||||
let tcards_to_string c = "TCards: <"::
|
||||
Tcards.card_tag_to_string c.tag::":"::
|
||||
Tcards.game_strategy_to_string c.strategy::
|
||||
">["::
|
||||
(List.map ~f:(fun c -> card_to_string c) c.cards |> String.concat)::
|
||||
"]"::[] |> String.concat
|
||||
let print_tcards chan tcards = Out_channel.output_string chan (tcards_to_string tcards);;
|
||||
|
||||
let table_to_string c = "Table: <"::
|
||||
(List.map ~f:(fun c -> tcards_to_string c) c.cards |> String.concat)::
|
||||
">"::[] |> String.concat ;;
|
||||
let print_table chan table = Out_channel.output_string chan (table_to_string table);;
|
||||
|
||||
|
||||
let t = play (make [
|
||||
Tcards.make [
|
||||
Cards.make Pikes 2;
|
||||
Cards.make Tiles 2;
|
||||
Cards.make Hearts 2;
|
||||
];
|
||||
Tcards.make [
|
||||
Cards.make Hearts 2;
|
||||
]
|
||||
]) (* table_cards *)
|
||||
(Tcards.make [
|
||||
Cards.make Pikes 2;
|
||||
Cards.make Tiles 2;
|
||||
Cards.make Hearts 2;
|
||||
]) (* in_play *)
|
||||
(Cards.make Hearts 2) (* to_move *)
|
||||
(* in make [
|
||||
* Tcards.make [
|
||||
* Cards.make Pikes 2;
|
||||
* Cards.make Tiles 2;
|
||||
* Cards.make Hearts 2;
|
||||
* Cards.make Hearts 2;
|
||||
* ]
|
||||
* ] ;; *)
|
||||
in
|
||||
Printf.printf "%a\n" t
|
||||
|
||||
let deck = Cards.init
|
||||
let card, _ = draw deck;;
|
||||
|
@ -16,111 +61,5 @@ Printf.printf "%a\n" print_card card
|
|||
considerata una carta giocabile in mano, considera le carte "prossime", bruteforce;
|
||||
*)
|
||||
|
||||
type status =
|
||||
| Valid
|
||||
| Invalid
|
||||
| Unknown ;;
|
||||
|
||||
|
||||
let no_double_seed cards =
|
||||
List.sort_uniq Cards.seed_cmp cards |> List.length = List.length cards
|
||||
|
||||
let is_only_one_seed cards =
|
||||
List.sort_uniq Cards.seed_cmp cards |> List.length = 1
|
||||
|
||||
let no_double_value cards =
|
||||
List.sort_uniq Cards.value_cmp cards |> List.length = List.length cards
|
||||
|
||||
let is_tris cards =
|
||||
match (List.sort_uniq Cards.value_cmp cards) with
|
||||
| [_] -> no_double_seed cards (* only one value, check for right seeds *)
|
||||
| _::_ -> false
|
||||
| [] -> assert false
|
||||
|
||||
let rec split l fst =
|
||||
match l with
|
||||
| hd::hd'::tl when hd=hd'-1 -> split (hd'::tl) (fst@[hd])
|
||||
| hd::tl -> fst@[hd], tl
|
||||
| [] -> assert false
|
||||
|
||||
|
||||
let is_straight _cards =
|
||||
let rec _is_straight cards =
|
||||
match cards with
|
||||
| hd::hd'::tl when hd=hd'-1 -> _is_straight (hd'::tl)
|
||||
| [] -> assert false
|
||||
| [_] -> true (* list was consumed *)
|
||||
| _::_ -> false in
|
||||
|
||||
if (not (no_double_value _cards && is_only_one_seed _cards)) then
|
||||
false
|
||||
else
|
||||
let last = List.rev _cards |> hd in
|
||||
let cards = List.map (fun c -> c.value) _cards (* use only values *) in
|
||||
if last.value = 13 && (hd cards) = 1 then (* circolare *)
|
||||
let fst, snd = split cards [] in (_is_straight fst) && (_is_straight snd)
|
||||
else
|
||||
_is_straight cards
|
||||
|
||||
let is_valid _cards =
|
||||
let cards = List.sort Cards.value_cmp _cards in
|
||||
if length cards < 3 then
|
||||
false
|
||||
else
|
||||
match cards with
|
||||
| a::b::_ when Cards.value_cmp a b = 0 -> is_tris cards
|
||||
| _ -> is_straight cards;;
|
||||
|
||||
|
||||
let rec play cards =
|
||||
true
|
||||
|
||||
let start_play ingame cards =
|
||||
ingame @ cards |> List.sort Cards.value_cmp |> play
|
||||
;;
|
||||
(* TESTS TODO: *)
|
||||
let cards = [{seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Tiles; value=1}; {seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Tiles; value=2}; {seed=Clovers; value=1}; {seed=Hearts; value=1}; {seed=Pikes; value=1}] in
|
||||
assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=2}; {seed=Hearts; value=2}; {seed=Hearts; value=4}]
|
||||
in assert (not (no_double_value cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=2}; {seed=Hearts; value=2}; {seed=Hearts; value=4}]
|
||||
in assert (not (no_double_seed cards));;
|
||||
|
||||
let cards = [{seed=Pikes; value=2}; {seed=Clovers; value=2}; {seed=Tiles; value=4}; {seed=Hearts; value=4}]
|
||||
in assert (no_double_seed cards);;
|
||||
|
||||
let cards = [{seed=Hearts; value=4}; {seed=Hearts; value=3}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Hearts; value=13}; {seed=Hearts; value=12}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
let cards = [{seed=Pikes; value=13}; {seed=Hearts; value=12}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Pikes; value=13}; {seed=Pikes; value=12}; {seed=Pikes; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
let cards = [{seed=Hearts; value=12}; {seed=Pikes; value=12}; {seed=Pikes; value=1}]
|
||||
in assert (not (is_valid cards));;
|
||||
|
||||
let cards = [{seed=Hearts; value=13}; {seed=Hearts; value=3}; {seed=Hearts; value=2}; {seed=Hearts; value=1}]
|
||||
in assert (is_valid cards);;
|
||||
|
||||
|
||||
let cards = [{seed=Hearts; value=1}] in
|
||||
let ingame = [{seed=Hearts; value=13}; {seed=Hearts; value=3}; {seed=Hearts; value=2}]
|
||||
in assert (start_play ingame cards);;
|
||||
|
||||
let cards = [{seed=Tiles; value=12}; {seed=Tiles; value=13}; {seed=Pikes; value=3}; {seed=Clovers; value=3}] in
|
||||
let ingame = [{seed=Hearts; value=1}; {seed=Hearts; value=13}; {seed=Hearts; value=12};
|
||||
{seed=Pikes; value=1}; {seed=Clovers; value=1}; {seed=Tiles; value=1};
|
||||
{seed=Hearts; value=2}; {seed=Pikes; value=2}; {seed=Clovers; value=2}]
|
||||
in assert (start_play ingame cards);; (* Risultato: straight 1-2-12-13 Hearts; straight 1-2-3 Pikes; straight 1-2-3 Clovers; straight 1-13-12 Tiles *)
|
||||
|
|
69
table.ml
Normal file
69
table.ml
Normal file
|
@ -0,0 +1,69 @@
|
|||
open List;;
|
||||
|
||||
open Cards;;
|
||||
open Tcards;;
|
||||
|
||||
let sum a b = a + b (* TODO: investigate why list.fold doesn't accept + *)
|
||||
|
||||
type table = { cards: tcards list}
|
||||
|
||||
let make tcards =
|
||||
{ cards=tcards }
|
||||
|
||||
let valids table =
|
||||
List.filter (fun ts -> ts.tag == Valid) table.cards;;
|
||||
|
||||
let invalids table =
|
||||
List.filter (fun ts -> ts.tag == Invalid) table.cards;;
|
||||
|
||||
let score table =
|
||||
List.length (valids table) - List.length (invalids table)
|
||||
|
||||
let hash table =
|
||||
List.map (fun ts ->Tcards.hash ts) table.cards |>
|
||||
List.fold_left sum 0;;
|
||||
|
||||
let size table =
|
||||
List.map (fun tl -> Tcards.length tl) table.cards |>
|
||||
List.fold_left sum 0 ;;
|
||||
|
||||
let flatten table =
|
||||
List.map (fun (ts:tcards) -> ts.cards) table.cards |>
|
||||
List.concat ;;
|
||||
|
||||
let neighbors tcs table =
|
||||
match tcs.strategy with
|
||||
| Tris -> List.filter (fun (x:tcards) -> tcs.cards@x.cards |> Cards.is_tris) table.cards
|
||||
| Straight -> List.filter (fun (x:tcards) -> tcs.cards@x.cards |> Cards.is_straight) table.cards
|
||||
| Single -> List.filter (fun (x:tcards) ->
|
||||
tcs.cards@x.cards |> Cards.is_straight || tcs.cards@x.cards |> Cards.is_tris)
|
||||
table.cards
|
||||
|
||||
let constraints start eend =
|
||||
let hand = List.filter (fun ts -> ts.strategy == Single) start.cards in
|
||||
let res = List.filter (fun (e:tcards) -> e.strategy == Single && not (List.mem e hand)) eend.cards in
|
||||
(List.length res) == 0;; (* investigate why not = nstead of == (TODO) *)
|
||||
|
||||
let doesnt_improve scores =
|
||||
if List.length scores < 7 then
|
||||
false
|
||||
else
|
||||
let max = List.fold_left max (-1000) scores in
|
||||
let min = List.fold_left min 1000 scores in
|
||||
abs (max - min) < 2
|
||||
|
||||
let play table in_play to_move =
|
||||
let rec _play table_cards in_play to_move accum =
|
||||
match table_cards with
|
||||
(* put new combination on the table *)
|
||||
| hd::tl when hd = in_play -> _play tl in_play to_move ((Tcards.make (to_move::in_play.cards))::accum)
|
||||
| [] -> accum (* generate a new table *)
|
||||
| hd::tl -> if hd |> Tcards.contains to_move then
|
||||
let filtered = List.filter (fun x -> x != to_move) hd.cards in
|
||||
_play tl in_play to_move ((Tcards.make filtered)::accum)
|
||||
else
|
||||
_play tl in_play to_move (hd::accum)
|
||||
in
|
||||
_play table.cards in_play to_move [] |> make
|
||||
;;
|
||||
|
60
tcards.ml
Normal file
60
tcards.ml
Normal file
|
@ -0,0 +1,60 @@
|
|||
open List;;
|
||||
open Hashtbl;;
|
||||
|
||||
open Cards;;
|
||||
|
||||
type card_tag =
|
||||
| Invalid
|
||||
| Valid
|
||||
|
||||
let card_tag_to_string t =
|
||||
match t with
|
||||
| Invalid -> "Invalid"
|
||||
| Valid -> "Valid"
|
||||
|
||||
type game_strategy =
|
||||
| Tris
|
||||
| Straight
|
||||
| Single
|
||||
|
||||
let game_strategy_to_string t =
|
||||
match t with
|
||||
| Tris -> "Tris"
|
||||
| Straight -> "Straight"
|
||||
| Single -> "Single"
|
||||
|
||||
type tcards = { cards: card list ; tag: card_tag ; strategy: game_strategy }
|
||||
|
||||
let make cards =
|
||||
let strategy = if List.length cards = 1 then Single else
|
||||
if Cards.is_tris cards then Tris else Straight in
|
||||
{ cards=cards ; tag=if Cards.is_valid cards then Valid else Invalid; strategy=strategy }
|
||||
|
||||
let contains needle haystack = List.mem needle haystack.cards
|
||||
|
||||
let (=) a b =
|
||||
if List.length a.cards != List.length b.cards || a.tag != b.tag || a.strategy != b.strategy then
|
||||
false
|
||||
else
|
||||
a.cards = b.cards
|
||||
|
||||
let length ts = List.length ts.cards
|
||||
let cmp a b =
|
||||
(* TODO: improve *)
|
||||
if a.strategy == Tris && List.length a.cards == 4 then -1
|
||||
else if b.strategy == Tris && List.length b.cards == 4 then 1
|
||||
else if a.strategy != Single && b.strategy == Single then 1
|
||||
else if a.strategy == Single && b.strategy != Single then -1
|
||||
else if a.tag == Invalid && b.tag == Valid then 1
|
||||
else -1 ;;
|
||||
|
||||
(* TODO tests *)
|
||||
assert (make [Cards.make Pikes 2] |>
|
||||
cmp (make [Cards.make Pikes 2 ; Cards.make Clovers 2]) == 1);; (* less than *)
|
||||
assert (make [Cards.make Pikes 2] |>
|
||||
cmp (make [Cards.make Pikes 2 ; Cards.make Clovers 2 ; Cards.make Tiles 2; Cards.make Hearts 2]) == -1)
|
||||
|
||||
let hash ts =
|
||||
ts.cards |>
|
||||
List.sort (fun a b -> if a.seed == b.seed then Cards.value_cmp a b else Cards.seed_cmp a b) |>
|
||||
Hashtbl.hash;;
|
Loading…
Reference in a new issue