24 February, 2009, 01:19
Although it has been a while since Brian posted the poker problem in his blog, I haven’t got the chance to look at it until I came across in ProjectEuler Problem 54. It is not the elegant or best solution at all, but just wanted to join the crew and can confirm it works with the problem’s 1000 games’ dataset.
Hope this helps.
#light
(* Problem 54 *)
type suit = |Spades |Hearts |Clubs |Diamonds
type card= |Ace = 14 |Two = 2 |Three =3 |Four = 4 |Five = 5 |Six = 6
|Seven =7 |Eight = 8 |Nine = 9 |Ten = 10 |Jack = 11 |Queen =12 |King =13
type acard = (card * suit)
let carder x:card= enum x
let card_value = function
| 'A' -> card.Ace
| 'K' -> card.King
| 'Q' -> card.Queen
| 'J' -> card.Jack
| 'T' -> card.Ten
| c -> carder(System.Int32.Parse(c.ToString()))
let suit_value = function
| 'S' -> Spades
| 'H' -> Hearts
| 'C' -> Clubs
| 'D' -> Diamonds
| a -> invalid_arg (a.ToString())
let Create (str: string) :acard = (card_value str.[0],suit_value str.[1])
let isstraigh (mycards:acard list) =
let mycards = List.sort_by (fun (a,b) -> a,b) mycards
let rec isstr previouscard mycards (straightlist : acard list) =
if straightlist.Length >= 5 then straightlist
else match mycards with
| cur :: rest -> if int (fst cur) = int ((fst previouscard)) + 1 then isstr cur rest (cur::straightlist)
else isstr cur rest []
| _ -> []
let head = List.hd mycards
isstr head (List.tl mycards) [head]
let pairl (mycards : acard list) groupfunction minelementCount =
mycards |> Seq.group_by groupfunction
|> Seq.filter (fun a -> Seq.length (snd a) >= minelementCount)
|> Seq.to_list
|> List.unzip
type Ranks =
| Highest of card
| Pair of card
| TwoPair of card*card
| Three of card
| Straight of card
| Flush of card
| FullHouse of card*card
| Four of card
| StraightFlush of card
type Player = |One |Two |Noone
let rank (mycards : acard list) =
let traverseL (l :'a list) = if not l.IsEmpty then l |> List.hd |> Seq.to_list
else []
let isflush mycards = snd (pairl mycards snd 5) |> traverseL
let FofF l = traverseL l |> List.hd |> fst
let flush = isflush mycards
let straight = isstraigh mycards
let ispair count= pairl mycards fst count
let four,fours = let f,s = ispair 4
f,s|> traverseL
let three,threes = ispair 3
let two,twos = ispair 2
let maxcard c = fst (List.max c)
if not flush.IsEmpty && not straight.IsEmpty then StraightFlush(maxcard flush),flush
elif not fours.IsEmpty then Four(four.Head),fours
elif not threes.IsEmpty && not twos.IsEmpty && FofF twos <> FofF threes then FullHouse(two.Head, three.Head), List.append (threes |> traverseL) (traverseL twos)
elif not flush.IsEmpty then Flush(maxcard flush),flush
elif not straight.IsEmpty then Straight(maxcard straight),straight
elif not three.IsEmpty then Three( three.Head), threes |> traverseL
elif List.length two = 2 then TwoPair(two.Head,two.Tail.Head),Seq.append (twos.Head) (twos.Tail.Head) |> Seq.to_list
elif not (twos |> traverseL).IsEmpty then Pair(two.Head), twos |> traverseL
else Highest(maxcard mycards), [List.max mycards]
let play input =
let convert (line: string) = let l = line.Split([|' '|])
[|[for j in 0 .. 4 do yield Create( l.[j])]; [for j in 5 .. 9 do yield Create( l.[j])]|]
let playercrds = convert input
let rec iswinner pcards=
let ranks,rankcards = pcards |> Array.map (rank) |> Array.unzip
let removecards (mainlist) (toberemoved) =
mainlist |> Array.map2 (fun rem main-> main |> List.filter (fun c->
List.fold_left(fun ac x-> if x = c then ac && false else ac && true) true rem)) toberemoved
if ranks.[0]>ranks.[1] then One
elif ranks.[0]<ranks.[1] then Two
else iswinner (removecards pcards rankcards)
iswinner playercrds
play "5H 5C 6S 7S KD 2C 3S 8S 8D TD"
play "5D 8C 9S JS AC 2C 5C 7D 8S QH"
play "2D 9C AS AH AC 3D 6D 7D TD QD"
play "4D 6S 9H QH QC 3D 6D 7H QD QS" // prob pair queens look at the highes
play "2H 2D 4C 4D 4S 3C 3D 3S 9S 9D"
play "2H 2D 4C 4D 4S 2H 2D 4C 4D 4S"
play "TH 8D 6C 4D 3S TH 8D 6C 4D 4S"
let rdinput = use file = System.IO.File.OpenText("poker.txt")
let p1count = ref 0
while not file.EndOfStream do
if play (file.ReadLine()) = One then p1count := !p1count+1
file.Close()
!p1count
6 January, 2008, 04:13
The other day, I was struggling with my playlist on itunes. As you may know iTunes doesn’t have the notion of the folder structure of your mp3s. So if you do organise your music in folders you won’t have them in iTunes. I decided to write a script using the iTunes COM SDK for doing that.
Here is the scenario all the music is stored in d:\Music. So the script starts exploring everything inside in the folder and create an entry in iTunes, and it happens only in one level. First I did it with JavaScript with a lot of pain. I was pain because of the ugly interface and also unclear documentation. Luckily there were the samples in the SDK to play with it.
var iTunesApp = WScript.CreateObject("iTunes.Application");
var mainLibrary = iTunesApp.LibraryPlaylist;
var mainLibrarySource = iTunesApp.LibrarySource;
var tracks = mainLibrary.Tracks;
var numTracks = tracks.Count;
var numPlaylistsCreated = 0;
var ITTrackKindFile = 1;
var albumArray = new Array();
var playlists = mainLibrarySource.Playlists;
for (var i = 1; i <= numTracks; i++)
{
var currTrack = tracks.Item(i);
if (currTrack.Kind == ITTrackKindFile)
{
if (currTrack.Location != "")
{
var p =currTrack.Location
var location = p
if ((location != undefined) && (location != ""))
{
if (albumArray[location] == undefined)
{
albumArray[location] = new Array();
}
albumArray[location].push(currTrack);
}
}
}
}
WScript.Echo(" Tracks Read " + numTracks);
for (var albumNameKey in albumArray)
{
var trackArray = albumArray[albumNameKey];
var p = albumNameKey;
var ignoreFirst = p.indexOf("music",0); //3
var firstChar = 0;
var secondChar = 0;
var firstChar = ignoreFirst +5 ;
var myArr = new Array();
while (true)
{
var firstChar = p.indexOf("\\", firstChar);
var secondChar = p.indexOf("\\", firstChar+1);
if (secondChar == -1 )
break;
var newStr = p.substring(firstChar+1, secondChar)
myArr.push(newStr);
firstChar = secondChar;
}
var plist = null;
if (myArr.length == 0)
{
if (playlists.ItemByName("_") != null)
{
plist = playlists.ItemByName("_") ;
}
else
{
plist = iTunesApp.CreatePlaylist("_");
numPlaylistsCreated++;
}
}
else if ( playlists.ItemByName(myArr[0]) != null)
{
plist = playlists.ItemByName(myArr[0])
}
else
{
plist = iTunesApp.CreatePlaylist( myArr[0]);
numPlaylistsCreated++;
}
for (var trackIndex in trackArray)
{
var currTrack = trackArray[trackIndex];
plist.AddTrack(currTrack);
}
}
//create playlist
if (numPlaylistsCreated > 0)
{
WScript.Echo( numPlaylistsCreated + " (s) created.");
}
else
{
WScript.Echo("No playlist createds");
}
Downloads: 179 File Name: itunes.js
.
(It is written in a quick way without caring about the beauty
)
It was doing its job that I wanted but I also wanted to have my folder structure in itunes rather than a single entry for a folder. This time I implemented in F#. I have chosen F# mainly because of the type inference and the intellisense. In JavaScript without the documentation, you couldn’t do anything. F# is also chosen because of interoperability with COM and friends. So I have to admit that I didn’t like the COM interface of iTunes. All the best F# implementation with more functionality gave %40 less code
#light
#r "Interop.iTunesLib.dll";;
open iTunesLib;
open System.IO;
open System.Text.RegularExpressions
let itunes = new iTunesLib.iTunesAppClass()
let playLists = itunes.LibrarySource.Playlists
let tracks = itunes.LibraryPlaylist.Tracks
let track = tracks.Item(2)
for track in tracks do
if track.Kind = ITTrackKind.ITTrackKindFile &&
(track:?> IITFileOrCDTrack).Location <> null then
let track = track :?> IITFileOrCDTrack
let regex = new System.Text.RegularExpressions.Regex( @"^( ?<Drive>([a-zA-Z])):\\_music\\
((?< directory>[\w\W]+)\\)*((?<
playlist>[\w\W]+)\\)(?<
filename>([\w\W]+.mp3))",
RegexOptions.IgnoreCase)
printf "%d\n" track.Index
let resMatch = regex.Match(track.Location)
if resMatch.Length = 0
()
else
let lastFolder =
resMatch.Groups.Item("directory").Captures |> Seq.untyped_fold
(fun (acc:IITPlaylist) (a: (System.Text.RegularExpressions.Capture)) ->
match (playLists.ItemByName(a.Value)) with
| null ->
if acc.Index = 1 then
itunes.CreateFolder(a.Value)
else
(acc :?> IITUserPlaylist).CreateFolder(a.Value)
| a1 ->
if (a1 :?> IITUserPlaylist).SpecialKind = ITUserPlaylistSpecialKind.ITUserPlaylistSpecialKindFolder then
a1
else
itunes.CreateFolder(a.Value)
)
(playLists.Item(1) )
let pListName = resMatch.Groups.Item("playlist").Captures.Item(0).Value
let lastPlayList=
match (playLists.ItemByName(pListName)) with
| null ->
if lastFolder.Index = 1 then
itunes.CreatePlaylist(pListName) :?> IITUserPlaylist
else
let fol = lastFolder :?> IITUserPlaylist
fol.CreatePlaylist(pListName) :?> IITUserPlaylist
| a2 ->
if (a2 :?> IITUserPlaylist).SpecialKind = ITUserPlaylistSpecialKind.ITUserPlaylistSpecialKindFolder then
match (playLists.ItemByName("_" + pListName)) with
| null -> (a2:?> IITUserPlaylist).CreatePlaylist("_" + pListName) :?> IITUserPlaylist
| a3 ->a3 :?> IITUserPlaylist
else
a2 :?> IITUserPlaylist
lastPlayList.AddTrack(ref (track :> obj)) |> ignore
done
Downloads: 216 File Name: itunes.fs
.
The folder playlist is not implemented on iPod. Although it make sense to use in iTunes, there is no point doing it for iPod. I was a bit frustrated, it was my sole purpose. Anyway it was nice to play with it…
So I hope it will be helpful in a way, the folder playlist didn’t help me, maybe in the next firmware update… On the other hand, I still use the first implementation for my automatic one-level folder playlist.
Tags:
com,
folder,
fs,
fsharp,
ipod,
itunes,
mp3,
organizer,
plugin,
sdk Category:
F#,
javascript |
4 Comments