-
-
Save Eibwen/e8fec52e0f5927108d86 to your computer and use it in GitHub Desktop.
Dancing Links http://lanl.arxiv.org/pdf/cs/0011047
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DancingLinks | |
{ | |
public DancingLinkHeader HEAD { get; private set; } | |
public List<DancingLinkHeader> Columns { get; private set; } | |
Stack<DancingLinkNode> SolutionSet = new Stack<DancingLinkNode>() | |
public DancingLinks(int ColumnCount) | |
{ | |
HEAD = new DancingLinkHeader(); | |
Columns = new List<DancingLinkHeader>(ColumnCount); | |
DancingLinkHeader current = HEAD; | |
DancingLinkHeader next; | |
for (int i = 0; i < ColumnCount; ++i) | |
{ | |
//Create a header and insert it in the linked list | |
next = new DancingLinkHeader(); | |
Columns.Add(next); | |
current.East = next; | |
next.West = current; | |
current = next; | |
} | |
//Finish the wrapping around | |
HEAD.West = next; | |
next.East = HEAD; | |
} | |
//Is this depth??? | |
public void Search(int depth) | |
{ | |
if (HEAD.East == HEAD) | |
{ | |
"SOLUTION FOUND".Dump(); | |
} | |
DancingLinkHeader column = FindColumnToCover(); | |
Cover(column); | |
foreach (DancingLinkNode node in EnumeratePath(column, (f) => f.South)) | |
{ | |
//Recurse this step | |
SolutionSet.Push(node); | |
foreach (DancingLinkNode child in EnumeratePath(node, (f) => f.East)) | |
{ | |
Cover(child.Header); | |
} | |
Search(depth + 1); | |
//Backtrack this step | |
/*node =*/ SolutionSet.Pop(); //Remove node from it, redundant? | |
//column = node.Header; //Also redundant? | |
foreach (DancingLinkNode child in EnumeratePath(node, (f) => f.West)) | |
{ | |
Uncover(child.Header); | |
} | |
} | |
Uncover(column); | |
return; | |
} | |
public DancingLinkHeader FindColumnToCover() | |
{ | |
} | |
public IEnumerable<DancingLinkNode> EnumeratePath(DancingLinkNode start, Func<DancingLinkNode, DancingLinkNode> nextNode) | |
{ | |
DancingLinkNode node = start; | |
while (node = nextNode(node) != start) | |
{ | |
yield return node; | |
} | |
} | |
} | |
public class DancingLinkNode | |
{ | |
public DancingLinkHeader Header { get; set; } | |
public DancingLinkNode North { get; set; } | |
public DancingLinkNode South { get; set; } | |
public DancingLinkNode West { get; set; } | |
public DancingLinkNode East { get; set; } | |
} | |
public class DancingLinkHeader : DancingLinkNode | |
{ | |
public int Count { get; set; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#define STACKON | |
//The idea here is to use single byte array to store all the values needed in a logical fashion | |
// So making my own very vasic objects and pointers | |
void Main() | |
{ | |
// (1 << 12).Dump(); | |
// (1 << 10).Dump(); | |
// (2916*2*5).Dump(); | |
// (324*2*2).Dump(); | |
// (2916*2*5 + 324*2*2).Dump(); | |
try | |
{ | |
//DancingLinksArray dla = new DancingLinksArray(@"C:\Documents and Settings\Netbook\My Documents\LINQPad Queries\Suduku\DancingLinksTable.Binary.bin", | |
// @"C:\Documents and Settings\Netbook\My Documents\LINQPad Queries\Suduku\DancingLinksTable.Columns.txt"); | |
var dla = new DancingLinksArray(); | |
dla.BuildTableFull(); | |
//dla.TEST_Output(); | |
//string board = "-5------1---934------------86-2-914-94---5-6-1-------2------7---1-6-2-84---38---9"; | |
var board = "85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4."; | |
dla.DumpNodeIds(); | |
dla.LoadSudoku(board); | |
dla.DumpNodeIds(); | |
dla.Search(); | |
// DancingLinksArray dla = new DancingLinksArray(); | |
// dla.TEST_DataStore(); | |
} | |
catch (Exception ex) | |
{ | |
DUMPSTACK(); | |
DEBUG.Dump("Debug Str"); | |
ex.ToString().Dump(); | |
throw; | |
} | |
} | |
static string DEBUG; | |
static Stack<string> DEBUG_STACK = new Stack<string>(); | |
static int DEBUG_COUNT = 0; | |
[Conditional("STACKON")] | |
[DebuggerStepThrough] | |
public static void ADDMESSAGE(string message) | |
{ | |
DEBUG_STACK.Push(message); | |
++DEBUG_COUNT; | |
// if (DEBUG_COUNT % 10 == 0) | |
// { | |
// (DEBUG_COUNT + " -- " + DEBUG_STACK.Count).Dump(); | |
// } | |
// if (DEBUG_COUNT % 50 == 0) | |
// { | |
// DEBUG_STACK.Dump(); | |
// //throw new NoNullAllowedException(); | |
// } | |
message.Dump(); | |
if (DEBUG_COUNT > 1000) throw new NoNullAllowedException(); | |
} | |
[Conditional("STACKON")] | |
[DebuggerStepThrough] | |
public static void ENDMESSAGE(string message) | |
{ | |
string msg = DEBUG_STACK.Pop(); | |
if (msg != message) throw new DivideByZeroException("MISMATCH: " + msg + " == " + message); | |
} | |
[Conditional("STACKON")] | |
[DebuggerStepThrough] | |
public static void DUMPSTACK() | |
{ | |
DEBUG_STACK.Dump(); | |
} | |
/* | |
TODO For full project, to convertion to mirc script | |
--1. Output solution result | |
2. Generate full table so i don't need an attachment | |
3. Write converter to do most of the conversion for me | |
Also any have calc(int i) return i; function to ease conversion | |
I think most other things should be fairly straight forward... | |
*/ | |
public class DancingLinksArray | |
{ | |
public DancingLinksArray() | |
{ | |
//324 column headers needed, 729 rows... | |
//2916 nodes (Not sure if this includes heads or not) | |
// SO I think i need 12 bits per pointer... Does mirc support bitshifting? | |
//For ease, lets say 16 bits per pointer... | |
// Each node has: 5 pointers | |
// Headers add: 1 pointer + count (10 bits) | |
// --WAIT WHAT POINTER?? Just a Name and a Count | |
//SO: | |
// Nodes need 5*2 bytes | |
// Headers need 7*2 bytes | |
//Approx 29,160 bytes (maybe plus 1,296) | |
DATA = new ArrayDataStore(); | |
//So Ids 1 - 324 are columns | |
} | |
public DancingLinksArray(string binaryFilename, string columnsFilename) | |
{ | |
DATA = new ArrayDataStore(binaryFilename, columnsFilename); | |
} | |
short HEAD = 1; | |
IDataStores DATA; | |
public void Search() | |
{ | |
Search(0); | |
} | |
private void Search(int depth) | |
{ | |
ADDMESSAGE("Search-" + depth); | |
if (DATA.GetNodePointer(HEAD, 'e') == HEAD) | |
{ | |
"SOLUTION FOUND".Dump(); | |
("Depth: " + depth).Dump(); | |
//SolutionSet.Dump(1); | |
// if (SolutionFound != null) | |
// { | |
// //TODO if this returns false, stop the searching... | |
// SolutionFound(SolutionSet.AsEnumerable()); | |
// } | |
DATA.OutputSolutionSet().Dump(); | |
return; | |
} | |
short column = FindColumnToCover(); | |
Cover(column); | |
var southPointer = DATA.GetNodePointer(column, 's'); | |
while (southPointer != column) | |
{ | |
ADDMESSAGE("Search-" + depth + "-#" + southPointer); | |
//Recurse this step | |
DATA.PushToSolutionSet(southPointer); | |
var eastPointer = DATA.GetNodePointer(southPointer, 'e'); | |
while (eastPointer != southPointer) | |
{ | |
Cover(DATA.GetNodePointer(eastPointer, 'h')); | |
eastPointer = DATA.GetNodePointer(eastPointer, 'e'); | |
} | |
Search(depth + 1); | |
//Backtrack this step | |
//Remove node from it, redundant? | |
DATA.PopFromSolutionSet(); | |
//column = node.Header; //Also redundant? | |
var westPointer = DATA.GetNodePointer(southPointer, 'w'); | |
while (westPointer != southPointer) | |
{ | |
Uncover(DATA.GetNodePointer(westPointer, 'h')); | |
westPointer = DATA.GetNodePointer(westPointer, 'w'); | |
} | |
ENDMESSAGE("Search-" + depth + "-#" + southPointer); | |
southPointer = DATA.GetNodePointer(southPointer, 's'); | |
} | |
Uncover(column); | |
ENDMESSAGE("Search-" + depth); | |
return; | |
} | |
public short FindColumnToCover() | |
{ | |
ADDMESSAGE("FindColumnToCover"); | |
short targetColumn = -1; | |
int lowestSize = 9000; | |
var eastPointer = DATA.GetNodePointer(HEAD, 'e'); | |
while (eastPointer != HEAD) | |
{ | |
ADDMESSAGE("FindColumnToCover-#" + eastPointer); | |
////"find".Dump(); | |
////eastPointer.Dump(); | |
var count = DATA.GetHeaderCount(eastPointer); | |
if (count < lowestSize) | |
{ | |
ADDMESSAGE("FindColumnToCover-Set-" + count + "-#" + eastPointer); | |
lowestSize = count; | |
targetColumn = eastPointer; | |
ENDMESSAGE("FindColumnToCover-Set-" + count + "-#" + eastPointer); | |
} | |
ENDMESSAGE("FindColumnToCover-#" + eastPointer); | |
eastPointer = DATA.GetNodePointer(eastPointer, 'e'); | |
} | |
ENDMESSAGE("FindColumnToCover"); | |
return targetColumn; | |
} | |
private void Cover(short column) | |
{ | |
ADDMESSAGE("Cover-#" + column); | |
DEBUG = DATA.GetNodeString(column); | |
DATA.SetNodePointer(DATA.GetNodePointer(column, 'e'), 'w', | |
DATA.GetNodePointer(column, 'w')); | |
DATA.SetNodePointer(DATA.GetNodePointer(column, 'w'), 'e', | |
DATA.GetNodePointer(column, 'e')); | |
////"cover".Dump(); | |
var southPointer = DATA.GetNodePointer(column, 's'); | |
while (southPointer != column) | |
{ | |
var eastPointer = DATA.GetNodePointer(southPointer, 'e'); | |
while (eastPointer != southPointer) | |
{ | |
DATA.SetNodePointer(DATA.GetNodePointer(eastPointer, 'n'), 's', | |
DATA.GetNodePointer(eastPointer, 's')); | |
DATA.SetNodePointer(DATA.GetNodePointer(eastPointer, 's'), 'n', | |
DATA.GetNodePointer(eastPointer, 'n')); | |
DATA.DecreaseHeaderCount(DATA.GetNodePointer(eastPointer, 'h')); | |
eastPointer = DATA.GetNodePointer(eastPointer, 'e'); | |
} | |
southPointer = DATA.GetNodePointer(southPointer, 's'); | |
} | |
ENDMESSAGE("Cover-#" + column); | |
} | |
public void Uncover(short column) | |
{ | |
ADDMESSAGE("Uncover-#" + column); | |
////"uncover".Dump(); | |
var northPointer = DATA.GetNodePointer(column, 'n'); | |
while (northPointer != column) | |
{ | |
var westPointer = DATA.GetNodePointer(northPointer, 'w'); | |
while (westPointer != northPointer) | |
{ | |
DATA.IncreaseHeaderCount(DATA.GetNodePointer(westPointer, 'h')); | |
DATA.SetNodePointer(DATA.GetNodePointer(westPointer, 'n'), 's', | |
westPointer); | |
DATA.SetNodePointer(DATA.GetNodePointer(westPointer, 's'), 'n', | |
westPointer); | |
westPointer = DATA.GetNodePointer(westPointer, 'w'); | |
} | |
northPointer = DATA.GetNodePointer(northPointer, 'n'); | |
} | |
DATA.SetNodePointer(DATA.GetNodePointer(column, 'e'), 'w', | |
column); | |
DATA.SetNodePointer(DATA.GetNodePointer(column, 'w'), 'e', | |
column); | |
ENDMESSAGE("Uncover-#" + column); | |
} | |
//Id 1 is head... | |
private short NextNodeId = 2; | |
private void SetupColumns() | |
{ | |
int offset = 2; | |
for (int i = 0; i < 81; ++i) | |
{ | |
DATA.SetHeaderName(i + offset, "p" + i); | |
DATA.SetHeaderName(81 + i + offset, "r" + (i/9+1) + "v" + (i%9+1)); | |
DATA.SetHeaderName(81*2 + i + offset, "c" + (i/9+1) + "v" + (i%9+1)); | |
DATA.SetHeaderName(81*3 + i + offset, "b" + (i/9+1) + "v" + (i%9+1)); | |
} | |
for (int i = 0; i < (81*4); ++i) | |
{ | |
DATA.SetHeaderCount(NextNodeId, 0); | |
DATA.SetNodePointer(NextNodeId, 'w', (short)(NextNodeId-1)); | |
DATA.SetNodePointer((short)(NextNodeId-1), 'e', NextNodeId); | |
NextNodeId += 1; | |
} | |
DATA.SetNodePointer(1, 'w', (short)(NextNodeId-1)); | |
DATA.SetNodePointer((short)(NextNodeId-1), 'e', 1); | |
Debug.Assert(NextNodeId == 326, "ERROR AFTER COLUMNS NEXT NODE SHOULD BE 326, but is: " + NextNodeId); | |
} | |
public void BuildTableFull() | |
{ | |
SetupColumns(); | |
short offset = 2; | |
//Build the exact cover matrix | |
for (int index = 0; index < 81; ++index) | |
{ | |
for (short CellValue = 1; CellValue <= 9; ++CellValue) | |
{ | |
//AddRow(GetIndexes_SudokuConstraint(j, i)); | |
int Row = index / 9; | |
int Col = index % 9; | |
int Block = (index / 27)*3 + (index % 9 / 3); | |
var columns = new [] { (index + offset), | |
(81*1 + (Row*9 + CellValue-1) + offset), | |
(81*2 + (Col*9 + CellValue-1) + offset), | |
(81*3 + (Block*9 + CellValue-1) + offset) }; | |
AddRow(columns); | |
} | |
} | |
} | |
public void AddRow(params int[] row) | |
{ | |
//"Add row".Dump(); | |
short start = -1; | |
short prev = -1; | |
foreach (short cell in row) | |
{ | |
short node = NextNodeId; | |
NextNodeId += 1; | |
//Columns[i].Dump("Pre", 1); | |
DATA.InsertNode(cell, 'n', 's', node); | |
DATA.SetNodePointer(node, 'h', cell); | |
DATA.IncreaseHeaderCount(cell); | |
//Columns[i].Dump("Post", 1); | |
if (start == -1) start = node; | |
if (prev != -1) | |
{ | |
DATA.SetNodePointer(node, 'w', prev); | |
DATA.SetNodePointer(prev, 'e', node); | |
} | |
prev = node; | |
} | |
DATA.SetNodePointer(start, 'w', prev); | |
DATA.SetNodePointer(prev, 'e', start); | |
} | |
public void LoadSudoku(string board) | |
{ | |
ADDMESSAGE("LoadSudoku"); | |
short offset = 2; | |
for (int i = 0; i < 81; ++i) | |
{ | |
char c = board[i]; | |
if ('1' <= c && c <= '9') | |
{ | |
short CellValue = (short)(c - '0'); | |
short index = (short)i; | |
Cover((short)(index + offset)); | |
int Row = index / 9; | |
int Col = index % 9; | |
Cover((short)(81*1 + (Row*9 + CellValue-1) + offset)); | |
Cover((short)(81*2 + (Col*9 + CellValue-1) + offset)); | |
int Block = (index / 27)*3 + (index % 9 / 3); | |
Cover((short)(81*3 + (Block*9 + CellValue-1) + offset)); | |
DATA.PushToSolutionSet(index, CellValue); | |
} | |
} | |
ENDMESSAGE("LoadSudoku"); | |
} | |
[Conditional("STACKON")] | |
public void DumpNodeIds() | |
{ | |
DumpHeaderCounts(); | |
" ==== ALL NODES ==== ".Dump(); | |
foreach (var node in AllNodes()) | |
{ | |
("NodeId:#" + node.ToString()).Dump(); | |
} | |
" ==== ALL NODES ==== ".Dump(); | |
} | |
public void DumpHeaderCounts() | |
{ | |
" ==== HEADERS ==== ".Dump(); | |
var column = DATA.GetNodePointer(HEAD, 'e'); | |
while (column != HEAD) | |
{ | |
("Count-#" + column | |
+ "-" + DATA.GetHeaderCount(column) | |
+ "-" + DATA.GetHeaderName(column)).Dump(); | |
column = DATA.GetNodePointer(column, 'e'); | |
} | |
" ==== HEADERS ==== ".Dump(); | |
} | |
private IEnumerable<short> AllNodes() | |
{ | |
var column = DATA.GetNodePointer(HEAD, 'e'); | |
while (column != HEAD) | |
{ | |
yield return column; | |
column = DATA.GetNodePointer(column, 'e'); | |
} | |
column = DATA.GetNodePointer(HEAD, 'e'); | |
while (column != HEAD) | |
{ | |
var southPointer = DATA.GetNodePointer(column, 's'); | |
while (southPointer != column) | |
{ | |
yield return southPointer; | |
southPointer = DATA.GetNodePointer(southPointer, 's'); | |
} | |
column = DATA.GetNodePointer(column, 'e'); | |
} | |
} | |
public void TEST_DataStore() | |
{ | |
DATA.SetNodePointer(1, 'h', 2); | |
DATA.SetNodePointer(1, 'n', 3); | |
DATA.SetNodePointer(1, 's', 4); | |
DATA.SetNodePointer(1, 'e', 5); | |
DATA.SetNodePointer(1, 'w', 6); | |
//DATA.SetHeaderCount(1, 43); | |
Debug.Assert(DATA.GetNodePointer(1, 'h') == 2, "h pointer"); | |
Debug.Assert(DATA.GetNodePointer(1, 'n') == 3, "n pointer"); | |
Debug.Assert(DATA.GetNodePointer(1, 's') == 4, "s pointer"); | |
Debug.Assert(DATA.GetNodePointer(1, 'e') == 5, "e pointer"); | |
Debug.Assert(DATA.GetNodePointer(1, 'w') == 6, "w pointer"); | |
Debug.Assert(DATA.GetHeaderCount(1) == 43, "count"); | |
DATA.OutputStorageView(); | |
} | |
public void TEST_Output() | |
{ | |
DATA.OutputStorageView(); | |
} | |
} | |
public interface IDataStores | |
{ | |
short GetNodePointer(short nodeId, char direction); | |
void SetNodePointer(short nodeId, char direction, short pointer); | |
void InsertNode(short nodeId, char direction, char oppositeDir, short pointer); | |
short GetHeaderCount(int column); | |
void SetHeaderCount(int column, short count); | |
void IncreaseHeaderCount(int column); | |
void DecreaseHeaderCount(int column); | |
string GetHeaderName(int column); | |
void SetHeaderName(int column, string name); | |
void PushToSolutionSet(short nodeId); | |
void PushToSolutionSet(short index, short CellValue); | |
void PopFromSolutionSet(); | |
string OutputSolutionSet(); | |
void LoadFromFile(string filename); | |
void OutputStorageView(); | |
string GetNodeString(short column); | |
} | |
public class ArrayDataStore : IDataStores | |
{ | |
public ArrayDataStore() | |
{ } | |
public ArrayDataStore(string filename, string columnsFilename) | |
{ | |
LoadFromFile(filename); | |
LoadHeadersFromFile(columnsFilename); | |
} | |
MircBvar bvar = new MircBvar(); | |
MircHashTable hash = new MircHashTable(); | |
string SolutionSet = ""; | |
public short GetNodePointer(short nodeId, char direction) | |
{ | |
int ptr = GetBinaryPos(nodeId, direction); | |
return new ShortUnion(bvar.bvar(ptr, ptr+1)).Short; | |
} | |
public void SetNodePointer(short nodeId, char direction, short pointer) | |
{ | |
int ptr = GetBinaryPos(nodeId, direction); | |
bvar.bset(ptr, new ShortUnion(pointer).Array); | |
} | |
public void InsertNode(short nodeId, char direction, char oppositeDir, short node) | |
{ | |
SetNodePointer(node, oppositeDir, nodeId); | |
short ptr = GetNodePointer(nodeId, direction); | |
if (ptr == 0) ptr = nodeId; | |
SetNodePointer(ptr, oppositeDir, node); | |
SetNodePointer(node, direction, ptr); | |
SetNodePointer(nodeId, direction, node); | |
// setOpposite(node, this); | |
// setOpposite(getPosition(this) ?? this, node); | |
// setPosition(node, getPosition(this) ?? this); | |
// setPosition(this, node); | |
} | |
private int GetBinaryPos(short nodeId, char direction) | |
{ | |
int ptr = (nodeId - 1) * 2 * 5; | |
switch (direction) | |
{ | |
case 'h': | |
return ptr; | |
case 'n': | |
return ptr + 2; | |
case 's': | |
return ptr + 4; | |
case 'e': | |
return ptr + 6; | |
case 'w': | |
return ptr + 8; | |
} | |
return -1; | |
} | |
//Using a hash table for the column properties | |
public short GetHeaderCount(int column) | |
{ | |
return short.Parse(hash.hget(column + "count")); | |
} | |
public void SetHeaderCount(int column, short count) | |
{ | |
hash.hset(column + "count", count.ToString()); | |
} | |
public void IncreaseHeaderCount(int column) | |
{ | |
short count = (short)(GetHeaderCount(column) + 1); | |
hash.hset(column + "count", count.ToString()); | |
} | |
public void DecreaseHeaderCount(int column) | |
{ | |
short count = (short)(GetHeaderCount(column) - 1); | |
hash.hset(column + "count", count.ToString()); | |
} | |
public string GetHeaderName(int column) | |
{ | |
return hash.hget(column + "header"); | |
} | |
public void SetHeaderName(int column, string name) | |
{ | |
hash.hset(column + "header", name); | |
} | |
public void PushToSolutionSet(short nodeId) | |
{ | |
SolutionSet += " " + nodeId; | |
} | |
public void PopFromSolutionSet() | |
{ | |
SolutionSet = SolutionSet.Substring(0, SolutionSet.LastIndexOf(' ')); | |
} | |
Dictionary<string, string> outputCache = new Dictionary<string, string>(); | |
public void PushToSolutionSet(short index, short CellValue) | |
{ | |
outputCache.Add(index.ToString(), CellValue.ToString()); | |
} | |
public string OutputSolutionSet() | |
{ | |
//foreach token in SolutionSet | |
//get header, get name, check if "^p" | |
//If does, parse number out of that, that is the cell index | |
// then go west from cell, and get the name of that, and parse out 'v(\d)$' | |
//If it doesn't, go west from the cell, and repeat options | |
//Construct this into a string somehow | |
//maybe throw everything in a hash table, then read out of that by cell number | |
//Or could use a small bvar, since i can set those values by position!! | |
foreach (string s in SolutionSet.Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries)) | |
{ | |
bool notFound = true; | |
short atPointer = short.Parse(s); | |
string position = null; | |
string value = null; | |
while (notFound) | |
{ | |
var header = GetNodePointer(atPointer, 'h'); | |
string name = GetHeaderName(header); | |
var m = Regex.Match(name, @"^[prcb](\d+)(v(\d)|)$"); | |
if (m.Groups[2].Value == "") | |
{ | |
position = m.Groups[1].Value; | |
} | |
else | |
{ | |
value = m.Groups[3].Value; | |
} | |
notFound = position == null || value == null; | |
atPointer = GetNodePointer(atPointer, 'w'); | |
} | |
outputCache.Add(position, value); | |
} | |
string output = ""; | |
for (int i = 0; i < 81; ++i) | |
{ | |
output += outputCache[i.ToString()]; | |
} | |
return output; | |
} | |
public void LoadFromFile(string filename) | |
{ | |
bvar.SetByteArray(File.ReadAllBytes(filename)); | |
} | |
public void LoadHeadersFromFile(string filename) | |
{ | |
//TODO THIS IS NOT CONVERTABLE | |
var lines = File.ReadAllLines(filename); | |
for (int i = 0; i < lines.Length; ++i) | |
{ | |
if (string.IsNullOrEmpty(lines[i])) continue; | |
string[] sa = lines[i].Split('\t'); | |
SetHeaderName(i+2, sa[0]); | |
SetHeaderCount(i+2, short.Parse(sa[1])); | |
} | |
} | |
public void OutputStorageView() | |
{ | |
hash.OutputStorageView(); | |
bvar.OutputStorageView(); | |
} | |
public string GetNodeString(short column) | |
{ | |
return "Id: " + column + " " | |
+ "h" + GetNodePointer(column, 'h').ToString("0000 ") | |
+ "n" + GetNodePointer(column, 'n').ToString("0000 ") | |
+ "s" + GetNodePointer(column, 's').ToString("0000 ") | |
+ "e" + GetNodePointer(column, 'e').ToString("0000 ") | |
+ "w" + GetNodePointer(column, 'w').ToString("0000 "); | |
} | |
[StructLayout(LayoutKind.Explicit)] | |
struct ShortUnion | |
{ | |
public ShortUnion(short value) | |
{ | |
byte0 = 0; | |
byte1 = 0; | |
Short = value; | |
} | |
public ShortUnion(byte[] array) | |
{ | |
Short = 0; | |
byte0 = array[0]; | |
byte1 = array[1]; | |
} | |
[FieldOffset(0)] | |
public byte byte0; | |
[FieldOffset(1)] | |
public byte byte1; | |
[FieldOffset(0)] | |
public short Short; | |
public byte[] Array | |
{ | |
get | |
{ | |
return new byte[] { byte0, byte1 }; | |
} | |
set | |
{ | |
byte0 = value[0]; | |
byte1 = value[1]; | |
} | |
} | |
} | |
} | |
public class MircBvar | |
{ | |
byte[] Storage = new byte[1024*32]; | |
public void bset(int address, byte[] values) | |
{ | |
for (int i = 0; i < values.Length; ++i) | |
{ | |
Storage[address+i] = values[i]; | |
} | |
} | |
public byte[] bvar(string range) | |
{ | |
if (!range.Contains('-')) | |
return bvar(Int32.Parse(range)); | |
if (range.EndsWith("-")) | |
return bvar(Int32.Parse(range.Substring(0, range.Length-1))); | |
var m = Regex.Match(range, @"^(\d)-(\d)$"); | |
return bvar(Int32.Parse(m.Groups[1].Value), Int32.Parse(m.Groups[2].Value)); | |
} | |
public byte[] bvar(int pos) | |
{ | |
return bvar(pos, pos); | |
} | |
public byte[] bvar(int start, int end) | |
{ | |
//start = start-1; | |
int len = end-start+1; | |
var output = new byte[len]; | |
for (int i = 0; i < len; ++i) | |
{ | |
output[i] = Storage[start + i]; | |
} | |
return output; | |
} | |
public void SetByteArray(byte[] array) | |
{ | |
Storage = array; | |
array.Length.Dump(); | |
} | |
public void OutputStorageView() | |
{ | |
BitConverter.ToString(Storage).Replace("-", "").Dump(); | |
} | |
} | |
//public class HashTableDataStore : IDataStores | |
//{ | |
//} | |
public class MircHashTable | |
{ | |
Dictionary<string, string> Storage = new Dictionary<string, string>(); | |
public void hset(string key, string value) | |
{ | |
Storage[key] = value; | |
} | |
public string hget(string key) | |
{ | |
return Storage[key]; | |
} | |
public void OutputStorageView() | |
{ | |
Storage.Dump(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment