Welcome
Guest
, you are in:
<root>
•
Login
Assaultware Wiki
Navigation
¶
Main Page
NoteCaddy
Random Page
Create a new Page
All Pages
Categories
Navigation Paths
Administration
File Management
Create Account
Search the wiki
»
Back
NoteCaddy note creation information
Modified on 2014/01/03 16:35
by
Administrator
Categorized as
Uncategorized
{toc} ===Hand grabbers=== NoteCaddy creates data by reading the hands in your database. There are two methods with which this can be done: '''Turbo hand grabber''' creates a cursor ([^http://en.wikipedia.org/wiki/Cursor_%28databases%29|more information]) to your database which gives it the ability to quickly cycle through hands. This mode puts significant strain on weak computers. It is turned off by default '''Standard hand grabber''' repeatedly executes queries grabbing 1000 hands at a time. This is much slower than the turbo hand grabber. However, it works well on weak computers. You configure which hand grabber to use by going to file->settings->database settings [image||http://7243-49642.el-alt.com/img/wiki/turbo.png] ===Creating notes=== In each hand there are 2-10 players. NoteCaddy will look at each player unless a white list or black list is defined in file->filters. For each player, NoteCaddy will see if any active note definition is valid. If it is, NoteCaddy will create a note for that player. All of the notes are stored in memory temporarily. You can see the progress of this on the ''creating notes'' panel in NoteCaddy [image||http://7243-49642.el-alt.com/img/wiki/creating_notes.png] This screen lists how many hands are in your database and how many of them NoteCaddy has processed. As you can see in the screenshot, the total hands is listed as an estimate. For large databases, it can take several minutes to count the exact amount of hands. This is time that is wasted since that number is of no practical consequence. The estimate that is used takes only a fraction of a second to obtain. This number will be less accurate if you have purged hands from your database or have encountered a large amount of import errors. If you are using the HM-App version of NoteCaddy (the one embedded in HM2) then this process will start automatically. Please see [^http://forums.holdemmanager.com/notecaddy/147941-just-getting-started-notecaddy-read-first.html|Getting Started with NoteCaddy] for recommended settings. You can configure NoteCaddy to not automatically create notes by going to file->settings->database settings and unchecking "automatically start taking notes when HM2 opens" [image||http://7243-49642.el-alt.com/img/wiki/automatic.png] NoteCaddy will create notes only for the database you have selected in HM2. There is no way to configure a certain database to be excluded. __When you play new hands, notes are automatically created__ for them assuming two things are true: * You did not configure NoteCaddy to not automatically take notes (see the screenshot above) * Your entire database has been processed already ===Saving notes to the database=== The data cannot remain in memory as that would be lost when you close HM2. Therefore it is saved to the database periodically. When this happens, you will see a message that says "Saving notes to the database" on the ''creating notes'' panel. By default this is every 2000 hands. You can configure NoteCaddy to wait longer by going to file->settings->database settings and entering a larger number [image||http://7243-49642.el-alt.com/img/wiki/persist.png] In the above image you can see that it is set to 5000. This can lead to a performance increase. The reason is that there is less time spent writing to the database. However, if HM2 closes in the middle of those 5000 hands, then no data will be saved and the next time you open HM2 they will need to be processed again. Therefore you should avoid making this value too large ===Vacuuming your database=== The database that HM2 uses is PostGres. This database temporarily occupies excessive disk space when data is being created and updated. You can immediately reclaim this space by performing the vacuum function. You can perform this directly from NoteCaddy by clicking tools->Vacuum Database. Furthermore, a [^Pending-Tasks|Pending Task] will be created for you if you process more than 100,000 hands. This is as a reminder that you may want to perform a database vacuum. ===Data persistence format=== NoteCaddy stores all player data in the database. One row is created for each player and the full data is stored as a single piece of text. This is done to avoid issues with database schema changes. The name of the table is notecaddy_data. If you are a developer you can easily read the data from there. An example query would be: select * from notecaddy_dat where player_id = 7 or <nowiki>select ncd.* from notecaddy_data ncd inner join players p on p.player_id = ncd.player_id where p.playername = 'SretiCentV'}} Below is a source code sample of this data is parsed {{ String rawNote = dt.Rows[0]["data"].ToString(); if (rawNote.Trim() == "") return null; String[] noteTokens = rawNote.Split('\n'); Int32 index = 0; foreach (String noteToken in noteTokens) { NoteDetails nd = new NoteDetails(); nd.Player = player; String[] fieldTokens = noteToken.Split('\t'); Int16 dbID = Int16.Parse(fieldTokens[0]); if (!GlobalController.DbNoteDefinitions.ContainsKey(dbID)) { ReadDescription definition = GlobalController.NoteDefinitions.FirstOrDefault( d => d.DatabaseID == dbID); if (definition == null) continue; try { GlobalController.DbNoteDefinitions.TryAdd(dbID, definition); } catch { } } nd.Definition = GlobalController.DbNoteDefinitions[dbID]; nd.DatabaseIndex = dbID; //this prevents the note from getting deleted using the task //if (!nd.Definition.IsActive) // continue; #if DEBUG if (nd.Definition == null) nd.Definition = new ReadDescription(); #endif nd.ShowPercentage = true; nd.ShowPrefix = true; nd.ReadID = nd.Definition.ID.ToString(); nd.Demographics = Int16.Parse(fieldTokens[7]); nd.Prefix = nd.Definition.Category; //List<Int32> instanceHits = new List<Int32>(); #region instances String rawGuilty = fieldTokens[1]; if (!String.IsNullOrEmpty(rawGuilty)) { String[] guiltyTokens = rawGuilty.Split(','); foreach (String guiltyToken in guiltyTokens) instances.Add(Int32.Parse(guiltyToken)); //Int32 skip = 0; if (!nd.Definition.IsSaveHistory) { nd.Instances = instances[0]; nd.Opportunities = instances[1]; } else { //if (useLast != 0 && useLast < instances.Count) // skip = instances.Count - useLast; foreach (Int32 i in instances)//.Skip(skip)) { nd.GuiltyHands.Add(i); nd.Opportunities++; nd.InstanceIndex++; if (i > 0) { nd.Instances++; //instanceHits.Add(i); } } } } #endregion #region range variable String rawRangeVar = fieldTokens[5]; if (!String.IsNullOrEmpty(rawRangeVar)) { Int32[] rangeVarResults = rawRangeVar.ToInt32List(); foreach (Int32 i in rangeVarResults)//.Skip(skip)) { //if (i == 0) // continue; nd.RangeVariableResults.Add(i); } nd.RangeVarIndex = rangeVarResults.Length; } #endregion #region spark Int32[] sparkPoints = null; String rawSpark = fieldTokens[2]; if (!String.IsNullOrEmpty(rawSpark)) { sparkPoints = rawSpark.ToInt32List(); //Int32 skip = 0; //if (useLast > 0) // skip = sparkPoints.Length - nd.Instances; //if (skip < 0) // skip = 0; //Int32 index = -1; foreach (Int32 i in sparkPoints)//.Skip(skip)) { nd.SparkSequence.Add((Int16)i); //index++; //if (i == 0) // continue; //if (!nd.SparkRange.ContainsKey(i)) // nd.SparkRange.Add(i, 0); //nd.SparkRange[i]++; } nd.SparkIndex = sparkPoints.Length; } #endregion #region scatter String rawScatter = fieldTokens[3]; if (!String.IsNullOrEmpty(rawScatter)) { Int32[] betSizes = rawScatter.ToInt32List(); //Int32 skip = 0; //if (useLast > 0) // skip = betSizes.Length - nd.Instances; //if (skip < 0) // skip = 0; //Int32 index = -1; foreach (Int32 i in betSizes)//.Skip(skip)) { nd.ScatterSequence.Add((Int16)i); //index++; if (i <= 0) continue; //ScatterPoint sp = new ScatterPoint(); //if (nd.Definition.IsSaveHistory) // sp.HandID = instances[index]; //if ((sp.HandID > 0 || !nd.Definition.IsSaveHistory) && // nd.SparkSequence.Count > index) //{ // sp.PotRatio = (Decimal)i / 100; // sp.Strength = nd.SparkSequence[index]; // nd.ScatterPoints.Add(sp); //} } nd.ScatterIndex = betSizes.Length; } #endregion #region timing points String rawTiming = fieldTokens[4]; if (!String.IsNullOrEmpty(rawTiming)) { Int32[] timings = rawTiming.ToInt32List(); //Int32 skip = 0; //if (useLast > 0) // skip = timings.Length - nd.Instances; //if (skip < 0) // skip = 0; //Int32 index = -1; foreach (Int32 i in timings)//.Skip(skip)) { nd.TimingSequence.Add((Int16)i); //index++; //if (i <= 0) // continue; //TimingPoint tp = new TimingPoint(); //tp.Action = TableActions.Bet; //if (nd.Definition.IsSaveHistory && instances.Count > index) // tp.HandID = instances[index]; //tp.TimingDelay = (Int16)i; //if (nd.SparkSequence.Count > index) // tp.Strength = nd.SparkSequence[index]; //tp.Street = nd.Definition.AutoDetectStreet(); //if (tp.TimingDelay > 0) // nd.TimingPoints.Add(tp); } nd.TimingIndex = timings.Length; } #endregion #region other variables String rawOther = fieldTokens[6]; if (!String.IsNullOrEmpty(rawOther)) { Int32[] othervarresults = rawOther.ToInt32List(); foreach (Int32 i in othervarresults) { nd.VariableResults.Add(i); } } #endregion #region player partition String rawPlayer = fieldTokens[8]; if (!String.IsNullOrEmpty(rawPlayer)) { Int16 id = Int16.Parse(rawPlayer); nd.PlayerPartitionID = id; PartitionRange guiltyPartition = nd.Definition.PlayerPartitionRanges .FirstOrDefault(p => p.ID == id); if (guiltyPartition == null) guiltyPartition = GlobalController.GlobalPartitions .FirstOrDefault(p => p.ID == id); if (guiltyPartition != null) { if (guiltyPartition.DisplayMinimum > 0) nd.MinimumPlayerRange = guiltyPartition.DisplayMinimum; else nd.MinimumPlayerRange = guiltyPartition.Minimum; if (guiltyPartition.DisplayMaximum > 0) nd.MaximumPlayerRange = guiltyPartition.DisplayMaximum; else nd.MaximumPlayerRange = guiltyPartition.Maximum; } else { switch (nd.GameSize) { case GameSizes.HeadsUp: nd.MinimumPlayerRange = 2; nd.MaximumPlayerRange = 2; break; case GameSizes.Medium: nd.MinimumPlayerRange = 3; nd.MaximumPlayerRange = 6; break; case GameSizes.Full: nd.MinimumPlayerRange = 7; nd.MaximumPlayerRange = 10; break; } } } else { switch (nd.GameSize) { case GameSizes.HeadsUp: nd.MinimumPlayerRange = 2; nd.MaximumPlayerRange = 2; break; case GameSizes.Medium: nd.MinimumPlayerRange = 3; nd.MaximumPlayerRange = 6; break; case GameSizes.Full: nd.MinimumPlayerRange = 7; nd.MaximumPlayerRange = 10; break; } } #endregion #region stack partition String rawStack = fieldTokens[9]; if (!String.IsNullOrEmpty(rawStack)) { Int16 id = Int16.Parse(rawStack); nd.StackSizePartitionID = id; PartitionRange guiltyPartition = nd.Definition.AverageStackPartitionRanges .FirstOrDefault(p => p.ID == id); if (guiltyPartition != null) { nd.MinimumAverageStackRange = guiltyPartition.Minimum; nd.MaximumAverageStackRange = guiltyPartition.Maximum; } } #endregion nd.NetBigBlinds = Decimal.Parse(fieldTokens[10]);</nowiki> For additional performance tips, please see [^NoteCaddy-speed-improvement|NoteCaddy speed improvement]
Meta Keywords:
Meta Description:
Change Comment:
ScrewTurn Wiki
version 3.0.6.630. Some of the icons created by
FamFamFam
.