Duoas 1,025 Postaholic Featured Poster

If you are not on windows, or you just want something more cross-platform, you'll need to use a GUI toolkit. The universal favorites are (in no particular order):

Trolltech Qt
GTK+ (and a nice C++ wrapper: GTK++)
wxWidgets
FLTK
FOX Toolkit

You may also want to take a look through The GUI Toolkit, Framework Page.

With the exception of Qt, all those I listed are GPL or better. Qt requires strict non-commercial use (now and in the future) for programs written with the free version.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Dynamic or static linkage?

You should probably spend some time looking through your Delphi documentation's "Components and Packages" section.

Your package must register the component (the Frame) when it is loaded, and deregister it when unloaded.

You must also specify the package unit's name in the uses clause. If it is a static package, you must also make sure it is listed in the Project|Options|Packages option. Also make sure that the "Build with Runtime Packages" checkbox (on the same tab) is enabled.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

If you are going to be using buttons with pixel images (like a GIF) you will need to do pixel-hit testing yourself.

Use the OnMouseDown event's X and Y values (which are relative to the button) to index a pixel in the image. Check that pixel's color against the transparent color to see if the user has clicked outside or inside the button's image.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Geez, Ed, are you trying to miss the point now? Or just pushing my buttons?

People can decide that a newline is only a terminator for their applications all they want, that doesn't make functional software. A person can believe the sky is orange, but that doesn't change the fact that it is also blue. You must consider both options when writing code.

If you only consider a line to be text terminating with a newline, you've missed half the possibilities in your code, and sooner or later someone is going to pass a file that has just one line (no newline) or no blank line at the end of the file (no newline at EOF).

(It is only common because it is convenient. Not the other way around. Console input is line-buffered --making it convenient input, and writing text files is convenient if you just stick a newline after every line of text you write.)

However, if you consider all possible lines of text, your code will work flawlessly with any text file, no matter how the newline was considered (or not considered) when writing it.

The only difference it will ever make is that a line-counting algorithm will tell you that you have one more line than you think you do. As I already noted, this difference is purely point-of-view. In this instance we are indeed both right. I am not wrong to count lines as (newlines+1).

To summarize sound software strategy: …

Duoas 1,025 Postaholic Featured Poster

It is complaining because readln is not a constant expression that matches the case type (n is an integer), and then it is complaining that it found a semicolon after the readln() instead of a colon, as case expressions should.

Remember, multiple statements must be enclosed in a begin..end block:

case n of
  1: begin
     writeln( 'Enter fake disk name: ' );
     readln( fname );
     assign( f, fname );
     ...
     end;
  2: ...
  end;
Duoas 1,025 Postaholic Featured Poster

In addition, you should have a removeBook() (or some such named) method(s) for the user's convenience.

Undertech commented: It's a good idea although I wouldn't be able to implement it for this particular assignment. +1
Duoas 1,025 Postaholic Featured Poster

I am really dismayed at the confusion here on how a plain-text file is organized. There is only one rule: A newline sequence [i]separates[/i] lines of text. (Typically, the file may also be understood to contain only newlines, horizontal tabs, and printable characters, but this is not always true; the file may contain binary data and/or other control characters specific to some application or device, such as a printer or an application's configuration data.)

In the Unix world, the newline sequence is just an ASCII LF.
In Windows, it is ASCII CR followed by ASCII LF.
In Mac, it is just an ASCII CR.
(On some old IBM dinosaurs, EBCDIC gives you a choice. :) )

In all cases, the presence of a newline sequence is to separate lines of text. The Unix terminology is telling: it is called a new line --meaning that it introduces a new line of text. Likewise in other old texts it is called a line break --again a separator.

While it is common (and convenient) to consider it a line terminator, it is not. It is a SEPARATOR.

So, let us list the possibilities:

  1. The file does not exist: it has zero lines of text.
  2. The file exists, but has zero length: it has one line of text. Granted, an empty line of text, but one never the less. (This by the definition of a plain text file --a file containing plain text. Since there are …
Duoas 1,025 Postaholic Featured Poster

Yes, replace the argument red's type with a HWND handle to your Rich Edit control and all the lines with red.Perform(...) with a call to SendMessage(): if (SendMessage( red, EM_FINDTEXTEX, flags, (LPARAM)&ftinfo ) == -1) ... etc.
Sorry for the Borland stuff again.

Duoas 1,025 Postaholic Featured Poster

???

If there are N lines of text in a file, there are N-1 newlines. The code I posted returns the same number as vijayan's shell script.

[edit] And it doesn't play with dynamic memory for every line of text.[/edit]

Duoas 1,025 Postaholic Featured Poster

Please use [code] [/code] tags.

It looks like you are off to a fairly good start, but you are missing a couple things.

Remember, in Pascal multiple statements must be enclosed in a begin..end block.

Also, make sure you get a good reference. It looks to me like you are using an old Borland Turbo Pascal, which doesn't have the openf procedure.

You must define the dat type before you can specify the file of dat type.

type
  dat: record
       block_count: longint;
       ... { however you have your file defined }
       end;
  DatFile: file of dat;
var
  f: DatFile;
  d: dat;
...

case n of
  1: begin
     writeln('Enter fake disk name: ');
     readln(fname);
     assign(f,fname);
     reset(f,sizeof(dat));
     if IOResult <> 0
       then writeln('No such file: cannot open ',fname)
       else begin
            read(f,d);
            writeln('Disk has ', d.block_count, ' blocks of ' ... );
            close(f)
            end;
  2: ...
  end;

I would also suggest you split your code up into procedures and functions.

type
  TUserChoice: (ucOpenDisk, ucReadBlock, ucWriteBlock, ucCloseDisk, ucExit);
var
  user_choice: TUserChoice;

procedure show_menu;
  begin
  writeln( 'Main Menu' );
  writeln;
  writeln( ucOpenDisk:2, '. Open fake disk' );
  writeln( ucReadBlock:2, '. Read block to file' );
  ...
  end;

procedure open_fake_disk;
  begin
  ...
  end;

...

begin
repeat
  show_menu;
  readln( user_choice );

  case user_choice of
    ucOpenDisk:   open_fake_disk;
    ucReadBlock:  read_block_to_file;
    ucWriteBlock: write_block_from_file;
    ucCloseDisk:  close_fake_disk;
    ucExit:
    else writeln( 'Invalid choice!' )
    end

until user_choice = ucExit;

writeln( 'Good-bye.' )
end.

Hope this helps get you going.

Duoas 1,025 Postaholic Featured Poster

Use a commercial library. It is worth the $$.
There are also some good free ones.

DTK Software
Zebra Barcode Library (sourceforge)
VCL Components Delphi Barcode Scanners page

You can google around for more if you like. Be aware that not all scanners are equal. Know what equipment you intend to target, and select a library that can handle it.

Good luck!

Duoas 1,025 Postaholic Featured Poster

I'm afraid not.

I've been running the DAEMON Tools Lite CD/DVD emulator and I noticed that it ran full-speed when running the ISO from the emulator.

My current "best guess" is that the IDE (and DT) causes the program to be loaded entirely into memory (no paging) and so it runs faster. But I have no proof of that.

Since my program currently runs with a high-enough framerate to avoid choppy animation I've not tried to figure this out entirely.

The code that does the drawing is double-buffered, and it essentially redraws about a fifth to a third of the display (depending on the user's resolution) each frame, by pasting a background image and then linking through some highly-optimized blitting operations for each scrolling icon.

Your problem has nothing to do with video update? It is a database query problem?

Duoas 1,025 Postaholic Featured Poster

Use the STL

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
using namespace std;

int main( int argc, char** argv )
  {
  if (argc < 2)
    {
    cout << "usage:\n  countlines FILENAME\n";
    return 0;
    }

  ifstream file( argv[ 1 ] );
  if (!file)
    {
    cerr << "Could not open file \"" << argv[ 1 ] << "\"\n";
    return 1;
    }

  file >> noskipws;
  cout << count(
            istream_iterator <char> ( file ),
            istream_iterator <char> (),
            '\n'
            )
          +1  // the last line is not terminated by NL
       << endl;

  return 0;
  }

Hope this helps.

Ancient Dragon commented: I like it -- although slightly obscure. +35
Duoas 1,025 Postaholic Featured Poster

It is because you are using a const-string initializer but your ctor argument is not const. Use the following instead: Exception( const string& msg ) Sorry I didn't catch that earlier.

Duoas 1,025 Postaholic Featured Poster

The best way to solve it is to provide a custom allocator for your _memory_map object that would use malloc() and free() directly and skip the overloaded new and delete operators.

If you aren't worried about thread safety, you can also just add a flag that the overloaded new and delete operators check to see whether they should mess with the memory_tracker.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

For whom? Me? Or dmlandrum? Please respond via PM to the person of interest.

Duoas 1,025 Postaholic Featured Poster

Heh heh, after a while you'll begin to understand the messages --even really long hairy ones. Then you start to wonder if you've been staring at this stuff too long... :)

Duoas 1,025 Postaholic Featured Poster

Use a stringstream to get stuff out of a string.

#include <fstream>
#include <sstream>
#include <string>
...

ifstream inf( "fooey.txt" );
string line;
while (getline( inf, line ))
  {
  // if the line is blank, ignore it
  if (line.find_first_not_of( " \t" ) == line.end()) continue;
  // get the first integer off the line
  stringstream linestream( line );
  int n;
  if (!(linestream >> n))
    that_was_not_an_integer();
  else 
    dosomething( n );
  }

This gets one line at a time from the file, and endeavors to get the first item on the line (if any) as an integer number.

Hope this helps.

[edit] hmm... I'm slow...

Duoas 1,025 Postaholic Featured Poster

The Win32 GDI abstracts a DC over the printer, so using the printer is very much like drawing a form.

Here's the MSDN Printing and Print Spooler reference.

It includes all the information you need to know about the printer GDI and provides a number of good examples.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

You have to define the destructor. Change line 15 to ~Exception() throw() { } Hope this helps.

Duoas 1,025 Postaholic Featured Poster

I didn't mention it before, but personally I would be inclined to use a compile-time #define to decide whether that verbose function gets used or not. Calling the function takes time, even if it doesn't do anything.

#ifndef VERBOSE
  #define myVerbosePrintf( ... )
#endif

...

#ifdef VERBOSE
  for (...)
    myVerbosePrintf( "fooey: %d\n", foonum );
#endif

...

myVerbosePrintf( "..." );

When you compile, if you don't specify -DVERBOSE then all that verbose stuff doesn't get compiled into the executable and you avoid the overhead of checking and calling stuff.
Oh, notice how the VERBOSE define supplants the 'verbose' variable.

That's what I'd do...

Duoas 1,025 Postaholic Featured Poster

With just a very quick glance, that notOptimized() function needs some help. A bitvector (or vector<bool> ) is not a good choice in such a function. Sad, but it was optimized for space, not speed.

If each point of a quad is always optimized or unoptimized, you can reduce it to a single bit. I don't know if you can do that though.

The other way would be to make yourself an array of bytes that are themselves bit fields representing the points of a quad. The overhead of handling it that way wouldn't be much different than the overhead of your bitvector (since each quad stores its own copy of the vertex's optimization state anyway), but your function could then just directly index the quad's optimization byte and compare that to 0x0F. If equal, all are optimized. If not, then at least one is not optimized.

That function is called so often that it is worth every millisecond you can squeeze out of it.

The rotateFour() function is pretty good as-is, but believe it or not you might get better results if you were to use the <cstring> memmove(), or just as good (I think) but easier to use,

register int n = x[ 3 ];
char_traits <int> ::move( x+1, x, 3 );
x[ 0 ] = n;

If that is unsatifactory, it might be worth writing it in assembly yourself.

Finally, I don't know why you are using new so much, but …

Alex Edwards commented: Very interesting post. Gave me something to think about =) +3
Duoas 1,025 Postaholic Featured Poster

STL fun:

#include <algorithm>
#include <fstream>
#include <iterator>
#include <string>

bool file_compare(
  const std::string& filenameA,
  const std::string& filenameB,
  bool is_binary
  ) {
  std::ios::openmode mode = is_binary ? std::ios::binary : std::ios::in;
  std::ifstream fileA( filenameA.c_str(), mode );
  std::ifstream fileB( filenameB.c_str(), mode );
  if (!fileA or !fileB) return false;

  if (is_binary)
    {
    fileA >> std::noskipws;
    fileB >> std::noskipws;
    }

  return std::equal(
    std::istream_iterator <char> ( fileA ),
    std::istream_iterator <char> (),
    std::istream_iterator <char> ( fileB )
    );
  }

(Any open files are automatically closed when the ifstream goes out of scope.)

For binary comparison, every byte of the files must match.
For non-binary, whitespace is ignored (including at EOF).

Have fun!

Duoas 1,025 Postaholic Featured Poster

Don't use Word to write your programs. Use a plain-text editor, or the Pascal IDE. If you are using Turbo Pascal, it has a very nice IDE.

Next, make your program compile before you post asking questions.

To use random numbers, somewhere at the beginning of your program say: randomize; and to get a random number say num := random( N ); where N is the range. The random number returned is in 0..(N-1).

Don't forget to terminate your program with end. You should work on your indentation. It is causing you a little confusion. A good rule of thumb is that statements that belong to another statement should be indented under that statement. For example:

if x = y
  then celebrate
  else complain_something_fierce;

while quuxxing( x ) do
  begin
  x := frobnicate( knob[ x ] );
  writeln( neutrino_value( x ) )
  end;

Here you can instantly see that lines 2 and 3 belong to line 1, and that lines 6..9 belong to line 5.

You really shouldn't play with input like you are. I suggest you make yourself a function to get the word to guess out of a file:

function get_word_to_guess( filename: string ): string;
  var
    f: file;
  begin
  assign( f, filename );
  reset( f );
  if IOResult = 0 then
    begin
    readln( f, result );
    close( f )
    end
  end;

Personally, I would make the file have a lot of words, one word per line, and have the function choose one at random.

Duoas 1,025 Postaholic Featured Poster

There isn't really any clean solution.

Remember, a template class is an incomplete type. It is only when you parameterize it that it becomes a complete, concrete, usable, valid type.

So vector <> * pvec_of_anything; just can't work. Such a type doesn't exist.

However, vector <int> * pvec_of_int; is a complete type.
As is vector <double> * pvec_of_double; . The obvious problem is that double and int are distinct types, so vectors of them are also distinct types. There is really no way of getting around that using generic programming --that isn't the problem it was intended to solve.

A common answer is to use a union and implement a "variant" datatype. Or, if you just have a special need, add a tag field to your container class that identifies the type of T.

Alas, sorry there isn't a simpler answer.

Duoas 1,025 Postaholic Featured Poster

Hmm, right you are. (I misread it as a newbie mistake, which he didn't actually make...)

I guess what I was trying to say is that there is no need to use a pointer.

The pointer is never initialized to point to valid memory, so trying to dereference it is like firing random bullets toward the propane shed. Better just to use the integer directly than incur the overhead of allocating and dereferencing a pointer.

Duoas 1,025 Postaholic Featured Poster

1 and 3:
All graphics operations in Windows are done using a "device context", or DC. If you want to draw lines or pictures or images or icons or whatever, you must have a valid DC to do it. Delphi's VCL provides a pretty powerful abstraction over the Win32 GDI ("Graphics Device Interface", which gives you the DC, etc), so you don't usually have to mess with the GDI directly.

2:
Everything in Windows is identified by a "handle". Each window has a handle. The desktop window, which is the window that contains all other windows you'll ever see (or not see), is created and managed by the system, but you can still get its handle and do stuff with it. The desktop window is the parent of all top-level windows.

In Delphi, you can access your own application's windows by using the Handle property of each TForm or the TApplication. You don't typically need to because the VCL abstracts all that stuff away for you.

If you want to find the handle of another application's window(s), you have two choices:

  1. If you know the name and/or class of the target window, you can use the FindWindow() function --so long as there is only one matching window to find.
  2. If you don't know the name or class of the target window(s), you must use the EnumWindows() Win32 function.

Both those functions are for finding top-level windows. Child windows …

Duoas 1,025 Postaholic Featured Poster

You know, I thought I had responded to this thread yesterday, but now I remember I was called away before I could finish typing.

'Bitfields', in the sense of using individual bits in an integer value, are very useful.

'Bitfields', in the sense of the C++ foo:1; syntax, have a very limited use. That is because the standard inexplicably fails to define the order in which the bitfields are to be packed. Hence, you just don't know. Using them is only useful when they are managed abstractly and when they are explicitly tallied when reading and writing to file (or anything else: integers or video memory or whatever).


However, I don't think anyone has addressed the original design problem. While having a 'nibble' class would be cool, it is impractical. The basic problem is that the smallest unit of reference (in most modern computers) is the byte: eight bits together. It is true that you can manipulate individual bits, but they don't stand alone. Each bit is always associated with a minimum of seven other bits. Thus, a single nibble is convenient until you have to use it somewhere.

Trying to read and write a nibble from file illustrates the problem quite nicely. You have to read or write at least two nibbles at a time. So what do you do with the second nibble? You probably don't want to just throw it away.

What I would recommend instead of a nibble class …

Duoas 1,025 Postaholic Featured Poster

The rand() function does not return a pointer to an int. It just returns the int. (reference)

So attempting to delete it is causing your error.


Also, while % does precede + in precedence, the way you have it written looks scary to me. Personally, I always tend to use () whether or not they are needed, just to be explicit. (I have often tried to debug another's code where he didn't use parentheses in a complicated expression and I have to wonder if he really meant it to do what it does.) drawn = (rand() % 52) + 1; That'll get you your card number in 1..52. Be careful: the notdraw[] array takes subscripts of 0..51. I would just make it a 53 element array and ignore the 0th element.

Watch your indentation too. Looks like a good start. Personally, I would also make the deck of cards a class. :) (But there you certainly don't have to.)

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Without even looking at your code, I will make a wild stab in the dark and say that you are using a Windows console to run your program?

If you are, right-click the icon on the console's title bar and select "properties" from the drop-down menu. Click the "Layout" tab and play with the items in the "Screen Buffer Size" panel until you are content. My own console windows are set to have a buffer Height of 300 lines. Once done, click "OK" and click "Modify shortcut that started this window", and hit "OK" once more.

If that wasn't the problem... let me know.

William Hemsworth commented: Good guess >.< +3
Duoas 1,025 Postaholic Featured Poster

semicolons
A semicolon by itself is considered a null statement, and has no meaning. Modern compilers will typically complain about them unless they explicitly terminate a statement. For example int number_of_lightbulbs_to_change; ; That second semicolon, while probably not an error, is also not useful, so the compiler will complain. It could be an error: if (foo == mane) padme(); ; else hum(); For counter-example for (int n = 0; quux( n ); n++); This last semicolon is in fact a null statement, but it has a purpose: it expresses an empty loop body.

data initializers
Whether or not you can specify an initializer depends on whether or not the file is #included in another.

// foo.hpp
#ifndef FOO_HPP
#define FOO_HPP
namespace foo
  {
  extern const int fooey;
  }
#endif
// foo.cpp
#include "foo.hpp"
namespace foo
  {
  const int fooey = 42;
  }

This is to obey the One Definition Rule.

when to use using
The difference between header files and object source files is important also when using namespaces. In a header file, you should never (and yes, this is one of those rules), never add stuff to the global namespace. It is not your perogative to decide what the person using your library permits in his namespaces. Example:

// bar.hpp
#ifndef BAR_HPP
#define BAR_HPP

#include <iostream>
#include "bazlib.hpp"

using namespace std;  // <-- WRONG! JUST SAY NO!

using baz::buzz;  // <-- WRONG! JUST SAY NO!

#endif

The reason should …

VernonDozier commented: Good summary +5
William Hemsworth commented: Thats a nice big post :) +3
Prabakar commented: Yes, Really nice:) +1
Duoas 1,025 Postaholic Featured Poster

Certainly you can, but the way to do it varies depending on where the pixel you want is.

You can get a specific pixel thus:

function GetPixelColor( win: HWND; x, y: integer ): tColor;
  var
    dc: HDC;
  begin
  if win = 0  // entire screen
    then begin
         win := GetDesktopWindow;
         dc  := GetDC( win )
         end
    else dc := GetWindowDC( win );
  result := GetColor( dc, x, y )
  end;

If you know what window you want to get the pixel from, pass it as the first argument.
If you want the pixel from anywhere on the display specify 0 as the first argument.

The x and y arguments are always relative to the target window (or the whole screen if win is zero).

If x or y are invalid the color returned is CLR_INVALID.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Since no one is responding to this...

I have always found the TTrackBar to be a bit cluncky. You can write your own from scratch (which I usually do), or simply derive a new one where you implement the OnMouseUp method, or (most simply) just check to see if the mouse button is down in your OnChange handler.

function IsButtonPressed( button: integer ): boolean;
  // button is VK_LBUTTON, VK_RBUTTON, or VK_MBUTTON
  var swapped: boolean;
  begin
  if GetSystemMetrics( SM_SWAPBUTTON ) <> 0 then
    case button of
      VK_LBUTTON: button := VK_RBUTTON;
      VK_RBUTTON: button := VK_LBUTTON
      end;
  result := (GetAsyncKeyState( button ) and $8000) <> 0
  end;

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Here's the proper fix. 'Twas another stupidism that messed things up. The complete (working) code:

// boggle-solver.cpp
// Copyright (c) 2008 Michael Thomas Greer
// <http://www.boost.org/LICENSE_1_0.txt>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
using namespace std;

char gameboard[ 4 ][ 4 ];

bool validate_word( const string& word, int row, int col, int index, int touched )
  {
  if ((unsigned)index == word.length()) return true;
  for (int r = -1; r < 2; r++)
  for (int c = -1; c < 2; c++)
    {
    if (((row +r) < 0) or ((row +r) > 3) or ((col +c) < 0) or ((col +c) > 3)) continue;
    int mask = 1 << (((row +r) *4) +col +c);
    if (((touched & mask) == 0)
    &&  (gameboard[ row +r ][ col +c ] == word[ index ]))
      if (validate_word( word, row +r, col +c, (word[ index ] == 'q') ? index +2 : index +1, touched | mask ))
        return true;
    }
  return false;
  }

void process_word( const string& word )
  {
  if ((3 > word.length()) or (word.length() > 17)) return;
  for (int row = 0; row < 4; row++)
  for (int col = 0; col < 4; col++)
    if (gameboard[ row ][ col ] == word[ 0 ])
      if (validate_word( word, row, col, (word[ 0 ] == 'q') ? 2 : 1, (1 << ((row *4) +col)) ))
        cout << word << '\n';
  }

int main()
  {
  cerr << "Enter the gameboard. Use just 'Q' for 'Qu'.\n";
  for (int …
Duoas 1,025 Postaholic Featured Poster

Argh! I'm a total idiot!

I forgot to check wrap-around bounds...

I always regret it when I hack something out in 30 mins. I'll post back with a proper fix.

Duoas 1,025 Postaholic Featured Poster

I'm really embarrassed about these little goofs!

Line 23 should read

if (validate_word( word, row +r, col +c, (word[ index ] == 'q') ? index +2 : index +1, touched | mask ))

and line 35 should read

if (validate_word( word, row, col, (word[ 0 ] == 'q') ? 2 : 1, (row *4) +col ))

Now it works right. You can test 'Qu's it with the gameboards:

QICK
ABCD
EFGH
IJKL
(produces "quick" as the last word)

ACEQ
NAIB
CDEF
GHIJ
(produces "aquacade" as the fourteenth word)

Too bad I can't edit my above post so people checking this out won't have to cut and paste the corrections...

Fooey.

[edit]
That list has two words each line. "bog dew" is two words.
I use the most basic rule. Each die can only be used once, and successive letters must be on one of the eight adjacent dice.

Duoas 1,025 Postaholic Featured Poster

Yep. Those are all the possible solutions for the given gameboard. (Your post is missing the first 39 answers though.) There are 338 solutions for that board using the default "word.lst" file.

Believe it or not those are all valid English words. :-O

(The fourth one you posted is even an olde potty word. :scared: )

My old Parker Brothers Boggle game box has the following puzzle pictured:

SGHB
TAIM
EURO
DCLA

...which produces 350 solutions out of "word.lst".

It seems I goofed when handling Qu... let me fix that...

Duoas 1,025 Postaholic Featured Poster

No good reason. Either works.

Duoas 1,025 Postaholic Featured Poster

I've used '\r' plenty of times to implement a little timer or progress indicator.
The '\b' unfortunately doesn't always work... but it should on all modern terminals and emulators.

The formfeed and vertical tab are carryovers from line printers. They used to be used a bit more with plain-text documents than they are today...

Duoas 1,025 Postaholic Featured Poster

this is a special pointer that points to the active object. For example:

#include <iostream>
#include <string>
using namespace std;

class WhoAmI
  {
    string name;
  public:
    WhoAmI( const string& name ): name( name ) { }
    void print( const WhoAmI& other )
      {
      cout << "I am " << this->name << endl;
      if (this == &other)
        cout << "I am beside myself.\n";
      else
        cout << "I am with " << other.name << endl;
      }
  };

int main()
  {
  WhoAmI george( "George" );
  WhoAmI alannah( "Alannah" );

  george.print( george );
  alannah.print( george );

  return 0;
  }

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Heh heh heh -- I couldn't resist iamthwee's challenge (sorry conan --look below for where to get a dictionary).

// boggle-solver.cpp
// Copyright (c) 2008 Michael Thomas Greer
// <http://www.boost.org/LICENSE_1_0.txt>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
using namespace std;

char gameboard[ 4 ][ 4 ];

bool validate_word( const string& word, int row, int col, int index, int touched )
  {
  if ((unsigned)index == word.length()) return true;
  for (int r = -1; r < 2; r++)
  for (int c = -1; c < 2; c++)
    {
    int mask = 1 << (((row +r) *4) +col +c);
    if (((touched & mask) == 0)
    &&  (gameboard[ row +r ][ col +c ] == word[ index ]))
      if (validate_word( word, (word[ index ] == 'q') ? index +2 : index +1, row +r, col +c, touched | mask ))
        return true;
    }
  return false;
  }

void process_word( const string& word )
  {
  if ((3 > word.length()) or (word.length() > 17)) return;
  for (int row = 0; row < 4; row++)
  for (int col = 0; col < 4; col++)
    if (gameboard[ row ][ col ] == word[ 0 ])
      if (validate_word( word, row, col, 1, (row *4) +col ))
        cout << word << '\n';
  }

int main()
  {
  cerr << "Enter the gameboard. Use just 'Q' for 'Qu'.\n";
  for (int n = 0; n < 16; n++)
    *((char*)gameboard +n) = tolower( (cin >> ws).get() );

  ifstream words( "word.lst" );
  if (!words) return 1;
  for_each( istream_iterator <string> ( …
iamthwee commented: I challenge you to solve Riemann's Hypothesis next. +15
Duoas 1,025 Postaholic Featured Poster

Why gets() is black, unpropitious, immoral, and wrong. (click me)

Well, since you asked ;) , I personally suggest

#include <iostream>
#include <limits>

...

std::cout << "Press ENTER to continue...";
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );

But that's not the only good solution. I didn't say "never use system()". I just said "know what you are doing".

The reason the console window closes immediately has nothing to do with the program. Your IDE is too stupid to keep it open until you explicitly close it. A common affliction, alas.
:sad: :)

Duoas 1,025 Postaholic Featured Poster

I hope you know a lot of math. Writing a compression schemata is not a trivial task.

You could just use a standard compression library (like zlib) and store the resulting data in a different file format than normal.

Good luck!

Duoas 1,025 Postaholic Featured Poster

Why would I need a map? You suggested using the associative array. It can be useful during scoring, at least.

"Pre-sorted" implies that something has been sorted before it is needed or used.

And no, I did not say that. I said a binary search can be written in under 20 lines of code. But that's moot because I forgot that the STL provides the std::binary_search() <algorithm> anyway...

Remember, you don't have to know every solution --just the ones that the user(s) suggest.

But if you really want to know, a boggle solve (every solution) probably could be written in under 20 lines of code. Maybe 30.

;)

Duoas 1,025 Postaholic Featured Poster

Actually, putting that system pause in there contributed to my low opinion. You said that was an example of when he uses <cstring>.

gets() is pure evil and should be lynched at every opportunity.

Using c-strings in a C++ program, outside of any need to interface with legacy code, is considered anachronistic and silly. It is kind of like building your own car to drive to the grocery --when a premade vehicle would cost less and be more convenient.

system( "anything" ) is resource heavy and a big security hole. It should not be taught as a convenience to do stupid or trivial stuff. I've nothing against using it in your own code, temporarily, to subdue your IDE, but it shouldn't ever find its way into production code. In the case of "pause", "cls", "title", etc, it also puts surprise restrictions on your program. Stream applications shouldn't demand human attention to operate.

Alas. C++ is a big world. And a lot of it is still stuck in C on MSDOS.

Duoas 1,025 Postaholic Featured Poster

Yoinks! I think the author is a crackpot.

Take a look at the C++ Books thread.

Duoas 1,025 Postaholic Featured Poster

The reason I suggested the STL is because it is the simplest possible answer.

Doing all that stuff you recommended would require considerably more than ~30 lines of code, it would cost extra time to enumerate and check every possible word --even with optimizations.

The use of an associative array is good, but again the STL provides one: std::map.

Personally, I'd avoid it's overhead just for space considerations in a large dictionary, and just use a deque to read a pre-sorted dictionary file (which is normal), and write my own binary search algorithm to find a word quickly. It can be done in log(N) time, with a usual successful search taking only a few iterations even if your dictionary is 10,000 elements or more.

The algorithm itself is is very simple and can be done in under 20 lines of code.

Duoas 1,025 Postaholic Featured Poster

<cstring> is the old C <string.h> library: strlen(), strchr(), memcpy(), etc.
<string> is the C++ STL strings library: std::basic_string<> and descendants (string, wstring).

The latest version of that book is five years old... but I have no clue why he is dinking around with stuff in <cstring> anyway... Perhaps he just wants you to understand what is going on behind the scenes.

STL containers exist to do a lot of the dirty work for you. A "string" in C and C++ is always just an array of characters. However, in C++, you can use the std::string class to manage that array dynamically and transparently.

That is why in the examples above I noted that the string object has no maximum size (well, it does, but you'll never have a string that large), because it will make sure its char array is always big enough to hold the entire string. cin >> str; works by using a trick called operator overloading. What actually happens is a special function gets called depending on what type of thing str is.

char s[ 100 ];
cin >> s;
// same as
operator >> ( (istream)cin, (char*)s );

string s;
cin >> s;
// same as
operator >> ( (istream)cin, (string&)s );

In each case there is a function named " operator >> ". It is indeed an odd name for a function --normally functions are named " read_string " or something like that. But the next thing to notice …

Duoas 1,025 Postaholic Featured Poster

Ah, yes, the venerable old atoi(). ;)

You know you can use a stringstream instead?

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
  {
  string s;
  cout << "Enter a number> ";
  getline( cin, s );
  long n;
  if (!(stringstream( s ) >> n))
    cout << "That wasn't a very good number\n";
  else
    cout << n << " * 2 = " << (n * 2) << endl;
  return 0;
  }

:)

Duoas 1,025 Postaholic Featured Poster

How is your dictionary stored? If, like iamthwee suggests, it is a file with words in it, you can just search the file for the given word.

You can even use the STL for that:

#include <algorithm>
#include <fstream>
#include <iterator>
#include <string>

// findword()
//   Determine whether or not a given word exists in a file.
//   This routine assumes that no word has spaces in it.
// returns
//   True if the word was found. False for any other reason.
//
bool findword( const std::string& filename, const std::string& word )
  {
  bool result = false;
  std::ifstream file( filename.c_str() );
  std::istream_iterator <std::string> end;

  result =
    std::find(
      std::istream_iterator <std::string> ( file ),
      end,
      word
      )
    != end;

  result &&= file.good();

  file.close();
  return result;
  }

However, this requires a large file access every time. You could open the file elsewhere and just seekg( 0 ); before each search, or you could load the file into memory (into a std::deque or some other container) and search it there.

#include <deque>

std::deque <std::string>
loadwords( const std::string& filename )
  {
  std::deque <std::string> result;
  ifstream file( filename.c_str() );
  std::copy(
    std::istream_iterator <std::string> ( file ),
    std::istream_iterator <std::string> (),
    std::back_inserter( result )
    );
  file.close();
  return result;
  }

bool findword(
  std::deque <std::string> words,
  const std::string& word
  ) {
  return
    std::find(
      words.begin(),
      words.end(),
      word
      )
    != words.end();
  }

(Use a deque over a vector for this kind of thing.)

Hope this helps.