2019-08-12 19:05:45 +02:00
|
|
|
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 }
|
|
|
|
|
2019-08-13 23:55:50 +02:00
|
|
|
let empty =
|
|
|
|
{ cards = [] }
|
|
|
|
|
2019-08-12 19:05:45 +02:00
|
|
|
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 ;;
|
|
|
|
|
2019-08-13 23:55:50 +02:00
|
|
|
let flatten table : card list=
|
2019-08-12 19:05:45 +02:00
|
|
|
List.map (fun (ts:tcards) -> ts.cards) table.cards |>
|
|
|
|
List.concat ;;
|
|
|
|
|
2019-08-13 23:55:50 +02:00
|
|
|
let contains tc table =
|
|
|
|
List.mem tc table.cards
|
|
|
|
|
|
|
|
let neighbors tcs table : card list=
|
|
|
|
let all = flatten table in
|
2019-08-12 19:05:45 +02:00
|
|
|
match tcs.strategy with
|
2019-08-13 23:55:50 +02:00
|
|
|
| Tris -> List.filter (fun x -> tcs.cards@[x] |> Cards.is_tris) all
|
|
|
|
| Straight -> List.filter (fun x -> tcs.cards@[x] |> Cards.is_straight) all
|
|
|
|
| Single -> all |>
|
|
|
|
List.filter (fun x -> let cs = tcs.cards@[x] in
|
|
|
|
Cards.is_straight cs || Cards.is_tris cs)
|
|
|
|
|
2019-08-12 19:05:45 +02:00
|
|
|
|
|
|
|
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
|
2019-08-13 23:55:50 +02:00
|
|
|
match (Tcards.remove to_move hd) with
|
|
|
|
| None -> _play tl in_play to_move accum
|
|
|
|
| Some x -> _play tl in_play to_move (x::accum)
|
2019-08-12 19:05:45 +02:00
|
|
|
else
|
|
|
|
_play tl in_play to_move (hd::accum)
|
|
|
|
in
|
2019-08-13 23:55:50 +02:00
|
|
|
assert (table |> contains in_play) ;
|
2019-08-12 19:05:45 +02:00
|
|
|
_play table.cards in_play to_move [] |> make
|
|
|
|
;;
|
|
|
|
|
2019-08-13 23:55:50 +02:00
|
|
|
let update best max_score original newt score =
|
|
|
|
if score > max_score && (constraints original newt) then
|
|
|
|
score, newt
|
|
|
|
else
|
|
|
|
max_score, best
|
|
|
|
|
|
|
|
let is_best_outcome table =
|
|
|
|
(invalids table |> List.length) == 0
|
|
|
|
|
|
|
|
(* let rec alg table original_table n (scores:int list) best max_score (dbg: table -> unit) =
|
|
|
|
* dbg table ;
|
|
|
|
* let ascore = score table in
|
|
|
|
* (\* if Hashset.has (hash table) then () *\)
|
|
|
|
* (\* else ( *\)
|
|
|
|
* (\* Hashset.add (hash table) ; *\)
|
|
|
|
* let mmax, bbest = update best max_score original_table table ascore in
|
|
|
|
* if is_best_outcome table || n > 14 || doesnt_improve (scores@[ascore]) then
|
|
|
|
* ()
|
|
|
|
* else
|
|
|
|
* table.cards |>
|
|
|
|
* List.map (fun tcs -> neighbors tcs table |> List.map (fun v -> (tcs,v))) |> (\* lista di carta:vicini *\)
|
|
|
|
* List.concat |> (\* flatten *\)
|
|
|
|
* List.map (fun (card, neigh) -> play table card neigh) |> (\* list of new_tables *\)
|
|
|
|
* List.iter (fun new_table -> alg new_table original_table (n+1) (scores@[ascore]) bbest mmax dbg)
|
|
|
|
* (\* ) *\) *)
|
|
|
|
|
|
|
|
let alg table n (scores:int list) : (table * int * int list) list =
|
|
|
|
table.cards |>
|
|
|
|
List.map (fun tcs -> neighbors tcs table |> List.map (fun v -> (tcs,v))) |> (* lista di carta:vicini *)
|
|
|
|
List.concat |> (* flatten *)
|
|
|
|
List.map (fun (card, neigh) -> (play table card neigh), (n+1), (scores@[score table]) )
|
|
|
|
|
|
|
|
let condizioni table n scores set =
|
|
|
|
if List.mem (hash table) set || doesnt_improve scores ||
|
|
|
|
is_best_outcome table || n > 14 then
|
|
|
|
true
|
|
|
|
else false
|
|
|
|
|
|
|
|
let rec prova original_table set best max_score (dbg: table -> unit) (accum: (table*int*int list) list)
|
|
|
|
(sols: (table*int*int list) list) =
|
|
|
|
match accum with
|
|
|
|
| [] -> sols
|
|
|
|
| (table, n, scores)::tl -> dbg table ;
|
|
|
|
if condizioni table n scores set then
|
|
|
|
prova original_table ((hash table)::set) best max_score dbg tl ([table, n, scores]@sols)
|
|
|
|
else
|
|
|
|
prova original_table ((hash table)::set) best max_score dbg ((alg table n scores)@tl) sols
|