From: "Jesús Gabriel y Galán" Date: 2012-08-03T18:03:04+09:00 Subject: Re: Having difficulty processing text files - some techniques? On Fri, Aug 3, 2012 at 11:02 AM, Jesús Gabriel y Galán wrote: > On Fri, Aug 3, 2012 at 10:39 AM, b1_ __ wrote: >> I am trying to extract information from a po-ker hand history text file >> as an exercise in learning RegExp and ruby file manipulation classes IO >> and File. >> >> The way the hand history text file is set out is like so: >> >> Hand No. xxxx - Date xxxx Time xxxx >> Game type: xxxx Blinds level: xxxx >> Table type: xxx >> Player 1: xxxx (chip count) >> Player 2: xxxx (chip count) >> Player 3: xxxx (chip count) >> Player 4: xxxx (chip count) >> Hole Cards Phase >> Player 1 calls >> Player 2 raise >> Player 3 folds >> Flop Phase >> Player 1 raises >> Player 2 calls >> Turn Phase >> etc >> etc >> River Phase >> etc >> etc >> Player 2 wins >> >> >> >> In my testing I have extracted successfully the very simple statistic of >> VP$IP, which is the percentage of times a player Voluntarily Puts $ In >> Pot pre-flop. So this is: >> >> Number of time called or raise pre-flop / Number of hands at the table >> >> My code (I used what I think is a Finite State Machine?): >> >> File.open("test_read.txt") do |f| >> >> count = 0 >> state = nil >> >> while (line = f.gets) >> case (state) >> when nil >> # Look for the words "Hole Cards" and if found turn on text >> processing >> if (line.match(/Hole Cards/)) >> state = :parsing >> end >> when :parsing >> # Look for word "Flop" or "wins" and if found stop processing text >> if (line.match(/Flop/)) || (line.match(/wins/)) >> state = nil >> else >> if (line.match(/#{name} calls/)) || (line.match(/#{name} >> raises/)) then count += 1 end >> end >> end >> end >> >> return count >> >> end >> >> This code processes text only when inside the Hole Card phase (pre-flop >> phase) between lines with words "Hole Cards" (start text processing) and >> "Flop" or "wins" (stop processing text). It increments a counter if it >> finds the words "calls" and "raises" next to a player's name. This code >> ran through the whole file, maybe over hundreds of hands, and extracted >> the data. >> >> The problem I am having is that I need to have the extracted data >> associate with hand data. Hand data might be the date of the hand was >> played, the number of players in the hand, the blind level. This means I >> need isolate each hand, extract the hand data and put it in a hash for >> example, then extract stats like VP$IP for each player (a hand-by-hand >> approach rather than a file-wide approach). So the output might go into >> a text file specific to each player that would look like: >> >> Player 1 >> VP$IP 2P 3P 4P All HandsAtTables >> 2012-07-23 3 201 21 225 534 >> 2012-07-24 45 10 3 58 1001 >> 2012-07-25 5 5 5 15 420 >> >> Can I do this without storing data in arrays or objects? I've been >> thinking I can use another Finite State Machine, only look for the words >> "Hand" (start of hand) and "wins" (end of hand), the problem is I need >> some of the data on the line that has the word "Hand" on it, something I >> can't do with my code above. I also need to switch between hands when >> there are no lines between the word "wins" and the next line which will >> have the word "Hands" on it indicating the start of the next hand. > > I don't understand the part about not using arrays or objects. If you > need to accumulate stuff while processing that's the only way. > It seems that you want to keep separate counts by date and number of > players. So I would use a hash whose key is a composite of both values > (a struct with both fields for example), or maybe a hash of hashes. > > When you find the "Hand" line, you parse the date and the following > lines to find out the number of players. With this you get the key to > the hash. The value will be the count. Then you keep your current > logic of being before the flop and counting. When you find another > Hand, you first write the count to the hash with the current key, then > recompute the next key based on the Hand line and number of players. > Something like: > > > Key = Struct.new :date, :number_of_players > state = nil > current_key = nil > results = Hash.new(0) # keys will return a value of 0 when they don't exist > while (line = f.gets) > case (state) > when nil > if(line.match(/^Hand/) > #find the date and the number of players in subsequent lines > key = Key.new date,number_of_players There's an error. That should be current_key = ... Jesus.