recursive sudoku solver (asap)

Please support our C++ advertiser: Intel Parallel Studio Home
Reply

Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

recursive sudoku solver (asap)

 
0
  #1
Feb 14th, 2009
hello everyone.. thx for droppin'

i need to write a program, a recursive sudoku solver
and this is what i have so far...

main.cpp
#include <iostream>
#include <vector>
#include "sudoku.h"

using namespace std;

int main()
{
    vector< vector<char> > rows;

    // Load grid
    rows=load();
    // Check if grid is consistent.
    if (checkall(rows))
    {
        cout << "Valid grid." << endl;
    }
    else
    {
        cout << "Invalid grid; exiting";
        return 0;
    }

    // Print initial grid
    print(rows);

    // Solve grid.
    solve(rows);

    // Check solution.
    cout << "Checking solution... "<<endl;
    if (checkall(rows))
    {
        cout << "valid!" << endl;
    }
    else
    {
        cout << "not valid!" << endl;
    }
    return 0;
}

sudoku.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "sudoku.h"
using namespace std;

// Read grid from file sudoku.dat
vector< vector<char> > load()
{
    char line;
    int o;
    ifstream data("sudoku.dat");
    cout << "Loading grid..." << endl;
    vector <char> nums;
    vector < vector<char> > rows;
    for (int i=0; i!=9; i++)
    {
        for (int j=0; j!=9; j++)
        {
            data>>line;
            nums.push_back(line);
        }
        rows.push_back(nums);
        nums.resize(0);
    }
    return rows;
}

// Print grid with nice format
void print(vector< vector<char> > rows)
{
    for (int i=0; i!=9; i++)
    {
        for (int j=0; j!=9; j++)
        {
            cout << rows[i][j];
            if (j==2 || j==5)
            {
                cout << "  ";
            }
            else if (j==8)
            {
                cout << endl;
                if (i==2 || i==5)
                {
                    cout << endl;
                }
            }
            else
            {
                cout << " ";
            }
        }
    }
}

// Returns a string containing the center of the block
// to which position i,j belongs.
string block(int i, int j)
{
    char x,y;
    string result = "00";
    switch (i)
    {
    case 1:
    case 2:
    case 3:
        x='2';
        break;
    case 4:
    case 5:
    case 6:
        x='5';
        break;
    case 7:
    case 8:
    case 9:
        x='8';
        break;
    }
    switch (j)
    {
    case 1:
    case 2:
    case 3:
        y='2';
        break;
    case 4:
    case 5:
    case 6:
        y='5';
        break;
    case 7:
    case 8:
    case 9:
        y='8';
        break;
    }
    result[0] = x;
    result[1] = y;
    return result;
}

// Checks whether value num can be placed at position i,j.
bool check(int num, int i, int j, vector< vector<char> > rows)
{
    char value = (char)(num+48);
    string center;
    int x,y;
    if (value == '-')
    {
        return true;
    }
    // check row
    for (int k=0; k!=9; k++)
    {
        if (rows[i][k]==value && k!=j)
        {
            return false;
        }
    }
    // check column
    for (int k=0; k!=9; k++)
    {
        if (rows[k][j]==value && k!=i)
        {
            return false;
        }
    }
    // check region
    center = block(i,j);
    x = center[0]-48;
    y = center[1]-48;
    for (int m=-1; m<=1; m++)
    {
        for (int n=-1; n<=1; n++)
        {
            if (rows[x+m][y+n]==value && !((x+m)==i && (y+n)==j))
            {
                return false;
            }
        }
    }
    return true;
}

// Recursive Sudoku solver
void solve(vector< vector<char> > rows)
{
	bool solved;
    int i,j;
    if (solved)
    {
        return;
    }

    // Find next empty value
    for (i=0; i!=9; i++)
    {
        for (j=0; j!=9; j++)
        {
            if (rows[i][j] == '-')
            {
                break;
            }
        }
        if (rows[i][j] == '-')
        {
            break;
        }
    }
    // If no empty value is found, grid is solved
    if (i==8 && j==8)
    {
        cout << "Grid solved!" << endl;
        solved = true;
        print(rows);
        return;
    }

    // Try next possible number and solve the rest recursively
    for (int a=1; a<=9; a++)
    {
        if (check(a,i,j,rows))
        {
            rows[i][j] = (char)(a+48);
            solve(rows);
        }
    }
    rows[i][j] = '-';

    return;
}

//Check all values on grid for consistency (ignores empty values)
bool checkall(vector< vector<char> > rows)
{
    int i,j;
    char value;
    for (i=0; i!=9; i++)
    {
        for (j=0; j!=9; j++)
        {
            if (rows[i][j] != '-')
            {
                value = rows[i][j];
                if (!(check((int)value,i,j,rows)))
                {
                    return false;
                }
            }
        }
        return true;
    }
    return true;
}

sudoku.h
#include <vector>

using namespace std;

vector< vector<char> > load();
void print(vector< vector<char> > rows);
string block(int i, int j);
bool check(int num, int i, int j, vector< vector<char> > rows);
void solve(vector< vector<char> > rows);
bool checkall(vector< vector<char> > rows);

when i run it,, there's an error on the recursive function solve
and i don't understand why... i'm really stuck..

really need help asap(to be submitted after several hours).. thx!
I am living in a mere program...
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

Re: recursive sudoku solver (asap)

 
0
  #2
Feb 14th, 2009
sorry for double post
this is what inside the sudoku.dat:

3 - 6 5 - 8 4 - -
5 2 - - - - - - -
- 8 7 - - - - 3 1
- - 3 - 1 - - 8 -
9 - - 8 6 3 - - 5
- 5 - - 9 - 6 - -
1 3 - - - - 2 5 -
- - - - - - - 7 4
- - 5 2 - 6 3 - -

thx for helping,, need this really asap..
I am living in a mere program...
Reply With Quote Quick reply to this message  
Join Date: Dec 2005
Posts: 5,850
Reputation: Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute 
Solved Threads: 749
Team Colleague
Salem's Avatar
Salem Salem is offline Offline
Void main'ers are DOOMed

Re: recursive sudoku solver (asap)

 
0
  #3
Feb 14th, 2009
> for (int i=0; i!=9; i++)
1. Define a constant for the size, say
const int squareSize = 9;
2. Using < is more usual for a for loop. As in
for ( int i = 0; i < squareSize ; i++ )
> bool check(int num, int i, int j, vector< vector<char> > rows)
You're passing by value. Which means anything you do to update this will NOT be reflected in the caller. Meaning main() gets no results. Use a reference.
Ditto for calling yourself recursively.

> if (i==8 && j==8)
Are you sure? The values reach 9 at the end?
Reply With Quote Quick reply to this message  
Join Date: Nov 2008
Posts: 392
Reputation: StuXYZ is a glorious beacon of light StuXYZ is a glorious beacon of light StuXYZ is a glorious beacon of light StuXYZ is a glorious beacon of light StuXYZ is a glorious beacon of light StuXYZ is a glorious beacon of light 
Solved Threads: 72
StuXYZ StuXYZ is offline Offline
Posting Whiz

Re: recursive sudoku solver (asap)

 
0
  #4
Feb 14th, 2009
Additionally, to the errors above: Errors on initialization.

  1.  
  2. bool solved;
  3. int i,j;
  4. if (solved) // ERROR: Un-initialized variable
  5. {
  6. return;
  7. }

You have a faliure to limit range on
line
  1. // Find next empty value
  2. for (i=0; i!=9; i++)
  3. {
  4. for (j=0; j!=9; j++)
  5. {
  6. if (rows[i][j] == '-')
  7. break;
  8. }
  9. if (rows[i][j] == '-') // ERROR j == 9 here and is out of range
  10. {
  11. break;
  12. }
  13. }

You call block() with i=0, j=0 but your switch [Very UGLY] takes 1-9 and has no default to tell you you have an error.

That results in a memory violation later.

There are others, but please please (a) use -warning-all or (-Wall for gcc). ie. put the warnings in and assume all warnings are errors.
(b) run through a debugger.
experience is the most expensive way to learn anything
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

Re: recursive sudoku solver (asap)

 
0
  #5
Feb 14th, 2009
thx for the great helps...

these are the new codes

main.cpp
#include <iostream>
#include <vector>
#include "sudoku.h"

using namespace std;

int main()
{
	vector< vector<char> > rows;

    // Load grid
    rows=load();
    // Check if grid is consistent.
    if (checkall(&rows))
    {
        cout << "Valid grid." << endl;
    }
    else
    {
        cout << "Invalid grid; exiting";
        return 0;
    }

    // Print initial grid
    print(&rows);

    // Solve grid.
    solve(&rows);

    // Check solution.
    cout << "Checking solution... "<<endl;
    if (checkall(&rows))
    {
        cout << "valid!" << endl;
    }
    else
    {
        cout << "not valid!" << endl;
    }
	return 0;
}

sudoku.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "sudoku.h"
using namespace std;

// Read grid from file sudoku.dat
vector< vector<char> > load()
{
    char line;
    ifstream data("sudoku.dat");
    cout << "Loading grid..." << endl;
    vector <char> nums;
    vector < vector<char> > rows;
    for (int i=0; i<squaresize; i++)
    {
        for (int j=0; j<squaresize; j++)
        {
            data>>line;
            nums.push_back(line);
        }
        rows.push_back(nums);
        nums.resize(0);
    }
    return rows;
}

// Print grid with nice format
void print(vector< vector<char> > *rows)
{

    for (int i=0; i<squaresize; i++)
    {
        for (int j=0; j<squaresize; j++)
        {
            cout << (*rows)[i][j];
            if (j==2 || j==5)
            {
                cout << "  ";
            }
            else if (j==8)
            {
                cout << endl;
                if (i==2 || i==5)
                {
                    cout << endl;
                }
            }
            else
            {
                cout << " ";
            }
        }
    }
}

// Returns a string containing the center of the block
// to which position i,j belongs.
string block(int i, int j)
{
    char x,y;
    string result = "00";
    switch (i)
    {
		case 0:
		case 1:
		case 2:
			x='2';
			break;
		case 3:
		case 4:
		case 5:
			x='5';
			break;
		case 6:
		case 7:
		case 8:
			x='8';
			break;
    }
    switch (j)
    {
		case 0:
		case 1:
		case 2:
			y='2';
			break;
		case 3:
		case 4:
		case 5:
			y='5';
			break;
		case 6:
		case 7:
		case 8:
			y='8';
			break;
    }
    result[0] = x;
    result[1] = y;
    return result;
}

// Checks whether value num can be placed at position i,j.
bool check(int num, int i, int j, vector< vector<char> > *rows)
{

    char value = (char)(num+48);
    string center;
    int x,y;
    if (value == '-')
    {
        return true;
    }
    // check row
    for (int k=0; k<squaresize; k++)
    {
        if ((*rows)[i][k]==value && k!=j)
        {
            return false;
        }
    }
    // check column
    for (int k=0; k<squaresize; k++)
    {
        if ((*rows)[k][j]==value && k!=i)
        {
            return false;
        }
    }
    // check region
    center = block(i,j);
    x = center[0]-48;
    y = center[1]-48;
    for (int m=-1; m<=1; m++)
    {
        for (int n=-1; n<=1; n++)
        {
            if ((*rows)[x+m][y+n]==value && !((x+m)==i && (y+n)==j))
            {
                return false;
            }
        }
    }
    return true;
}

// Recursive Sudoku solver
void solve(vector< vector<char> > *rows)
{
	bool solved;
    int i,j;
    if (solved)
    {

        return;
    }

    // Find next empty value
    for (i=0; i<squaresize; i++)
    {
        for (j=0; j<squaresize; j++)
        {
            if ((*rows)[i][j] == '-')
            {
                break;
            }
        }
        if ((*rows)[i][j] == '-')
        {
            break;
        }
    }
    // If no empty value is found, grid is solved
    if (i==9 && j==9)
    {
        cout << "Grid solved!" << endl;
        solved = true;
        print((rows));
        return;
    }

    // Try next possible number and solve the rest recursively
    for (int a=1; a<=9; a++)
    {
        if (check(a,i,j,rows))
        {
            (*rows)[i][j] = (char)(a+48);
            solve(rows);
        }
    }
    (*rows)[i][j] = '-';

    return;
}

//Check all values on grid for consistency (ignores empty values)
bool checkall(vector< vector<char> > *rows)
{
    int i,j;
    char value;
    for (i=0; i<squaresize; i++)
    {
        for (j=0; j<squaresize; j++)
        {
            if ((*rows)[i][j] != '-')
            {
                value = (*rows)[i][j];
                if (!(check((int)value,i,j,rows)))
                {
                    return false;
                }
            }
        }
        return true;
    }
    return true;
}

sudoku.h
#include <vector>

using namespace std;
const int squaresize=9;
vector< vector<char> > load();
void print(vector< vector<char> > *);
string block(int i, int j);
bool check(int num, int i, int j, vector< vector<char> > *);
void solve(vector< vector<char> > *);
bool checkall(vector< vector<char> > *);

my problem now is: the program doesn't print the solved grid..
and i can't find why.... really sorry

thx again.. sorry for this program,, i just don't have much time now
thx for helping.. if possible, i would appreciate a fixed revised code of mine..
I am living in a mere program...
Reply With Quote Quick reply to this message  
Join Date: Dec 2005
Posts: 5,850
Reputation: Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute 
Solved Threads: 749
Team Colleague
Salem's Avatar
Salem Salem is offline Offline
Void main'ers are DOOMed

Re: recursive sudoku solver (asap)

 
0
  #6
Feb 14th, 2009
Why are you using a pointer, and not a reference?

You're still not initialising solved.

You're still running off the end of an array.
Reply With Quote Quick reply to this message  
Join Date: Mar 2008
Posts: 675
Reputation: Sky Diploma is a splendid one to behold Sky Diploma is a splendid one to behold Sky Diploma is a splendid one to behold Sky Diploma is a splendid one to behold Sky Diploma is a splendid one to behold Sky Diploma is a splendid one to behold 
Solved Threads: 99
Sky Diploma's Avatar
Sky Diploma Sky Diploma is offline Offline
Practically a Master Poster

Re: recursive sudoku solver (asap)

 
0
  #7
Feb 14th, 2009
too late
Last edited by Sky Diploma; Feb 14th, 2009 at 12:12 pm.
1. Please Mark Your Thread as Solved After Getting Your Answers.
2. Please Use CODE TAGS .
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

Re: recursive sudoku solver (asap)

 
0
  #8
Feb 14th, 2009
Originally Posted by Salem View Post
Why are you using a pointer, and not a reference?

You're still not initialising solved.

You're still running off the end of an array.
thx salem.. really sorry
here's the current solve function..
void solve(vector< vector<char> > &rows)
{
	bool solved=false;
    int i,j;
    if (solved)
    {

        return;
    }

    // Find next empty value
    for (i=0; i<squaresize; i++)
    {
        for (j=0; j<squaresize; j++)
        {
            if (rows[i][j] == '-')
            {
                break;
            }
        }
        if (rows[i][j-1] == '-')
        {
            break;
        }
    }
    // If no empty value is found, grid is solved
    if (i==9 && j==9)
    {
        cout << "Grid solved!" << endl;
        solved = true;
        print(rows);
        return;
    }

    // Try next possible number and solve the rest recursively
    for (int a=1; a<=9; a++)
    {
        if (check(a,i,j,rows))
        {
            rows[i][j] = (char)(a+48);
            solve(rows);
        }
    }
    rows[i][j] = '-';

    return;
}

but there's still problems in memory while running the program.. is the rows still incorrect? please fix my code.... i really don't understand why there's memory problem,, and why it doesn't print the solved grid..
I am living in a mere program...
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

Re: recursive sudoku solver (asap)

 
0
  #9
Feb 14th, 2009
i think the problem is here:

in solve function:
for (int a=0; a<9; a++)
    {
		if (i==9)
		{
			if (check(a,i-1,j,rows))
			{
				rows[i-1][j] = (char)(a+48);

				solve(rows);
			}
		}
		if (check(a,i,j,rows))
			{

				rows[i][j] = (char)(a+48);

				solve(rows);
			}
    }
    rows[i][j] = '-';

    return;
in check function,,
center = block(i,j);
    x = center[0]-48;
    y = center[1]-48;
    for (int m=0; m<=2; m++)
    {
        for (int n=0; n<=2; n++)
        {
            if (rows[x+m][y+n]==value && !((x+m)==i && (y+n)==j))
            {
                return false;
            }
        }
    }
    return true;

and in block function
string block(int i, int j)
{
    char x,y;
    string result = "00";
    switch (i)
    {
		case 0:
		case 1:
		case 2:
			x='1';
			break;
		case 3:
		case 4:
		case 5:
			x='4';
			break;
		case 6:
		case 7:
		case 8:
			x='7';
			break;
    }
    switch (j)
    {
		case 0:
		case 1:
		case 2:
			y='1';
			break;
		case 3:
		case 4:
		case 5:
			y='4';
			break;
		case 6:
		case 7:
		case 8:
			y='7';
			break;
    }
    result[0] = x;
    result[1] = y;
    return result;
}

i don't know how to fix the problem in the debugger.. pls help
thx!
I am living in a mere program...
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 21
Reputation: azwraith69 is an unknown quantity at this point 
Solved Threads: 0
azwraith69's Avatar
azwraith69 azwraith69 is offline Offline
Newbie Poster

Re: recursive sudoku solver (asap)

 
0
  #10
Feb 15th, 2009
sorry,, now i'm triple posting... time trouble

this is my latest sudoku.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "sudoku.h"
using namespace std;

// Read grid from file sudoku.dat
vector< vector<char> > load()
{
    char line;
    ifstream data("sudoku.dat");
    cout << "Loading grid..." << endl;
    vector <char> nums;
    vector < vector<char> > rows;
    for (int i=0; i<squaresize; i++)
    {
        for (int j=0; j<squaresize; j++)
        {
            data>>line;
            nums.push_back(line);
        }
        rows.push_back(nums);
        nums.resize(0);
    }
    return rows;
}

// Print grid with nice format
void print(vector< vector<char> > &rows)
{

    for (int i=0; i<squaresize; i++)
    {
        for (int j=0; j<squaresize; j++)
        {
            cout << rows[i][j];
            if (j==2 || j==5)
            {
                cout << "  ";
            }
            else if (j==8)
            {
                cout << endl;
                if (i==2 || i==5)
                {
                    cout << endl;
                }
            }
            else
            {
                cout << " ";
            }
        }
    }
}

// Returns a string containing the center of the block
// to which position i,j belongs.
string block(int i, int j)
{
    char x,y;
    string result = "00";
    switch (i)
    {
		case 0:
		case 1:
		case 2:
			x='1';
			break;
		case 3:
		case 4:
		case 5:
			x='4';
			break;
		case 6:
		case 7:
		case 8:
			x='7';
			break;
    }
    switch (j)
    {
		case 0:
		case 1:
		case 2:
			y='1';
			break;
		case 3:
		case 4:
		case 5:
			y='4';
			break;
		case 6:
		case 7:
		case 8:
			y='7';
			break;
    }
    result[0] = x;
    result[1] = y;
    return result;
}

// Checks whether value num can be placed at position i,j.
bool check(int num, int i, int j, vector< vector<char> > &rows)
{

    char value = (char)(num+48);
    string center;
    int x,y;
    if (value == '-')
    {
        return true;
    }
    // check row
    for (int k=0; k<squaresize; k++)
    {
        if (rows[i][k]==value && k!=j)
        {
            return false;
        }
    }
    // check column
    for (int k=0; k<squaresize; k++)
    {
        if (rows[k][j]==value && k!=i)
        {
            return false;
        }
    }
    // check region
    center = block(i,j);
    x = center[0]-48;
    y = center[1]-48;
    for (int m=0; m<=2; m++)
    {
        for (int n=0; n<=2; n++)
        {
        	if(x==7 && y==7)
        	{
        		for (int m=-1; m<=1; m++)
                            {
                                   for (int n=-1; n<=1; n++)
                                   {
        	                          if(x==-1 && y==-1)
        	                         {
        		                          if (rows[x+m+1][y+n+1]==value && !((x+m+1)==i && (y+n+1)==j))
				                  {
					               return false;
				                   }
        	                         }
        	                         else if(x==-1)
        	                         {
        		                          if (rows[x+m+1][y+n]==value && !((x+m+1)==i && (y+n)==j))
				                  {
					               return false;
				                  }
        	                         }
        	                         else if(y==-1)
        	                         {
        		                         if (rows[x+m][y+n+1]==value && !((x+m)==i && (y+n+1)==j))
				                  {
					             return false;
				                  }
        	                          }
                                          else if(rows[x+m][y+n]==value && !((x+m)==i && (y+n)==j))
                                         {
                                               return false;
                                          }
              }
    }
    return true;
}

// Recursive Sudoku solver
void solve(vector< vector<char> > &rows)
{
	bool solved=false;
    int i,j;
    if (solved)
    {
        return;
    }
    // Find next empty value
    for (i=0; i<squaresize; i++)
    {
        for (j=0; j<squaresize; j++)
        {
            if (rows[i][j] == '-')
            {
                break;
            }
        }
        if (rows[i][j-1] == '-')
        {
            break;
        }
    }

    // If no empty value is found, grid is solved
    if (i==9 && j==9)
    {
        cout << "Grid solved!" << endl;
        solved = true;
        print(rows);
		return;
    }
    // Try next possible number and solve the rest recursively
    for (int a=1; a<=9; a++)
    {
		if (i==9)
		{
			if (check(a,i-1,j,rows))
			{
				rows[i-1][j] = (char)(a+48);
				solve(rows);
			}
		}
		else
		{
			if (check(a,i,j,rows))
			{
				rows[i][j] = (char)(a+48);
				solve(rows);
			}
		}
    }
}

//Check all values on grid for consistency (ignores empty values)
bool checkall(vector< vector<char> > rows)
{
    int i,j;
    char value;
    for (i=0; i<squaresize; i++)
    {
        for (j=0; j<squaresize; j++)
        {
            if (rows[i][j] != '-')
            {
                value = rows[i][j];
                if (!(check((int)value,i,j,rows)))
                {
                    return false;
                }
            }
        }
        return true;
    }
    return true;
}

it's working except in printing the solved grid.. the last row is what only printed correctly... pls help me modify the bolded part.. i think it's there... thx.. really need asap!
Last edited by azwraith69; Feb 15th, 2009 at 1:24 am.
I am living in a mere program...
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Other Threads in the C++ Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC