Jump to content

  • Log In with Google      Sign In   
  • Create Account


Josh Petrie

Member Since 11 Jun 2003
Offline Last Active Aug 29 2014 09:06 PM

Posts I've Made

In Topic: C# While Statement

15 August 2014 - 11:57 AM

What exactly are the errors?

 

The first line of code won't compile because "myPokemon[int parse(myChoice) - 1]" isn't a valid expression. You probably mean "int.Parse(myChoice)" not "int parse(myChoice)."


In Topic: Bashing my face against the ArcSynthesis.org brick wall.

14 August 2014 - 03:45 PM

What is the purpose of a tutorial that just assumes you know what to do?

 

That's, um, exactly what a tutorial is for. It demonstrates how to do a specific thing, but assumes you are familiar with the supporting knowledge. It's why tutorials can very often be horrible ways to learn things.

 

That said, the Arcsynthesis site is a little broader than a tutorial. However, it's focus is still to teach you things about OpenGL, and not the subtle rigors of cross-platform C++ projects (which can be exceedingly complicated and a subject for their very own book). Providing source code and compilation instructions seems to be done more as a cursory favor than a really dedicated effort.

 

The errors you are listing are linker errors, not compiler errors. They indicate that the references libraries (glloadD and so on, which appear to be part of that Unofficial OpenGL tutorial) aren't being found in the linker search paths. You should do two things next:

 

First, verify that you actually have files named "gllloadD" and so on (probably with .lib or similar extensions) somewhere. Perhaps you acquired a bad copy of the tutorial source archive that is missing these files (the website claims they should be included in the distribution and do not need to be externally downloaded).

 

Then, look at the (premake-generated, it sounds like) project file in your IDE: specifically look for the section that defines the library search paths for the linker. Verify that one of the paths is the directory containing the glloadD, et cetera, files.

 

Nowadays: You have to convert sourcecode into an IDE-freindly format (because they're all read c++ in different ways), you have to compile OpenGL source code into a an ide freindly version that it can use. You also apparently have to have about 5 different versions of OpenGL (glew, gltut, freegl, glib and god knows what else) You then, presumably have to tell the IDE where this version is.... and who knows what crazy unintuitive stuff beyond that

 

You don't have to do that at all. The author has provided a premake-based setup for you to allow you to generate projects for your preferred IDE; this is hardly required for C++ and is done so as a convenience for you. In this case you've run into an issue with the convenience, but that doesn't mean you wouldn't run into different issues if the author just gave you the source code and told you to compile it and resolve the dependencies yourself.

 

The OpenGL issues are simply the way OpenGL works -- all of those things you mentioned are not, incidentally, OpenGL -- they are utilities for making OpenGL easier to deal with. If they were there, you'd have even more problems. I appreciate that you are frustrated because things aren't working right, but in this case the author has done a fairly commendable job of trying to simplify your life (cross-platform, cross-toolchain C++ is complicated), especially given that the purpose of his/her site is not to teach you about all the complex issues surrounding distributing C++ to an unknown target environment.


In Topic: My first Win32 Game

06 August 2014 - 04:48 PM

For what is otherwise just POD, move semantics will have no affect on performance. Moving at its absolute fastest is just copying bits which is the same as the copy operation does for POD. The const reference may or may not actually be necessary here even in C++98 since a point is so small (two ints) and with some ABIs using the const reference even in C++98 would be a deoptimization.

 

 

Yeah, good point (I updated that point to try to de-emphasize points specifically). In particular it's noteworthy that on Apple's later iOS platforms, the entire GLKit API passes 4x4 matrices around by value because they are plain data and the hardware/toolchain is capable enough to do the fast thing -- knowing something is passed by value also means you can know it cannot be aliased elsewhere, which can help optimization.

 

(But points aren't the only thing the OP is passing around by value in the above code.)


In Topic: My first Win32 Game

06 August 2014 - 11:52 AM

Here are some comments:

  • You are missing some opportunities for const-correctness. For example, your accessor methods (like GetScore) could be declared "int GetScore() const;" since they do not require mutating the invoking object.
  • You should use constructor initializer lists; instead of setting mScore inside the body of the constructor, do "Player::Player() : mScore(0) { }" This is a good habit to get into because it is faster for some types (and certainly never slower) and required for some other types (such as references).
  • Use an enumeration for the field content instead of #define macros; in general, enumerations or const variables are preferable for constants. Macros should be used sparingly.
  • Use consistent naming. If "sign" in GetSign/SetSign refers to the field content (as I suspect it does just from looking at the header), adjust the names so "sign" and the "field content" enumeration are in sync (i.e., use one or the other).
  • You don't need to provide empty constructors/destructors, they will be generated for you by default (unless you do something to disable that, which are you not in these cases).
  • A common convention for "output parameters" (the results of GetCornerPoints) is to pass those parameters as pointers. That way, it is clearer at the call site that the parameters are potentially-modified (GetCornerPoints(&p1, &p2)). It also allows you to make some output parameters optional, in the case where the caller may not care about that particular parameter (and thus can pass a null pointer). Using non-const reference parameters is often a bad idea, because it can result in the violation of the principle of least-surprise.
  • Prior to C++11, "larger" non-POD types (possibly including point types, though not your specific point type) should be passed by const-reference, rather than by value (as in SetCornerPoints). This avoided extra copies. In C++11, move semantics alter this guidance: you can pass by value if you're just going to store, as you do in SetCornerPoints, since the compiler can use a move there. Otherwise, you may still want to consider passing by const-reference.
  • The corner points of the field are something you could mandate be provided by the constructor of Field; it's probably not a good idea to allow them to be mutated after the field is constructed, since that makes it easy to create nonsense boards. APIs should be easy to use in the correct fashion and hard to use in the incorrect fashion.
  • The field constructor should at least initialize the field to a good state (set the initial size, zero-out the points if you're not going to require them as constructor parameters).
  • DO NOT put "using namespace std;" in header files. This pollutes the global namespace for ever more, since you cannot undo a using declaration. Fully-qualify items in headers, or put the appropriate using directives in a tighter scope if necessary.
  • A tic-tac-toe board is a 2D grid. Consider altering the interface of your board to refer to cells by an row and column index, since that's more natural. You can still internally use a linear array of nine fields by doing some simple math on the row/column indices.
  • Try to avoid "dumb pass through" APIs when possible. An example of this is Board's GetFieldSign/SetFieldSign methods, which just forward to the field APIs to do the actual work. This technique can create a lot of boilerplate code that's not easy to maintain. Consider instead a design where the board can simply get a reference to a field at a given row and column: Field & GetField(std::size_t row, std::size_t column). Then you can leverage the API that is already present on the field class.
  • In a project this small, it's not too big of a deal, but in the future consider how you might separate game logic from rendering (your board class conflates them now). Keeping independent, single responsibilities allows for better maintainability and reusability.
  • Similarly, in a project this small it's not a big deal, but in larger projects consider looking at how you can hide implementation details against things like Windows and GDI. I don't mean stuffing things in the private access section of a class, I mean removing the header references to Windows and GDI entirely (thus preventing your clients from acquiring the build-time dependency of such a header. Things like the "private implementation" or "pimpl" pattern might be worth looking into once your projects get larger.
  • Use forward declarations when appropriate to avoid unnecessary header dependencies. You can, for example, forward-declare "class Player" in the Board header, and then you can avoid the player header include there (moving it to the .cpp file, where it's better because it won't cause as many files to recompile if it changes).
  • You can avoid the call to ResetFields in the board constructor if you instead ensure that a field default-constructs itself into a sane state (as above).
  • A tic-tac-toe board is a grid. You can do the initial computation of all the grid points in a loop, rather than nine individual manual sets.
  • The naming convention of the board member variables does not match that of the field member variables (no "m" prefix on the former). Consistency is important.
  • The board drawing function creates new GDI objects every call; this will eventually exhaust GDI handle resources and you'll crash. You should either create/destroy them every draw call, or create them once (in the board constructor), since you're also trying to destroy them in the destructor (which only actually cleans up the last pen and brush.
  • Your local member variable naming convention is also inconsistent.
  • There are lots of magic numbers in your drawing method; consider using named constants instead.
  • This: static_cast<ostringstream*>(&(ostringstream() << player[0].GetScore()))->str();  is horrible. Use std::to_string in C++11, or create a single stringstream on the stack and re-use it to do (stream << score; stream.str()) (or better yet, make it a utility function).
  • Think about how you can do many of the drawing steps -- the board lines, for example -- in fewer lines of code using loops and other ways to exploit the fact that you have a grid. It will make for fewer magic numbers and fewer places to adjust code when you want to change the overall look of the board.
  • The if statements in SetFieldSign are unnecessary. Just do: Fields[field_id].SetSign(sign); Check sign for validity prior to that if desired (if you switch to using an enumeration for the sign, it would be clearer).
  • Consider returning a field pointer out of GetClickedFieldID, so the user doesn't have to go re-lookup the field.
  • In your Game class, you pass the entire board by value to CheckWin. Pass it by constant reference.
  • "CheckWin" is a cumbersome name. Consider something like "CheckForWin" instead.
  • You can increase maintainability by factoring out entire-column and entire-row checking into utility functions (especially easy once you change the board API to do row/column queries). This reduces duplicate code.
  • You return magic numbers from CheckWin. Use an enumeration to indicate result state.
  • In SwitchActivePlayer, pass the objects by const reference. Consider a design that does not require passing seemingly-unrelated parameters to a function that sounds like it should just toggle internal state. What you have now produces a bad abstraction.
  • It's unclear to me why you need the "ghost player."
  • It does not make sense to call AllocConsole inside WM_PAINT. Move it to an initialization call site.

In Topic: Python IDE

31 July 2014 - 05:04 PM

Not really the case. IDEs include compilers which may or may not differ. If they differ then it matters a lot.

 

 

IDEs do not always include compilers. Python IDEs in particular do not (as you note), since Python is interpreted, and toolsets that work with or extend Python often simply use your installed version of Python (or have the option to, in addition to a built-in version).\

 

What is the best IDE to use to start learning python on?

 

Personally I use vim for all my Python work. You can pretty easily just use your favorite text editor to get started -- if you have seven languages under your belt you should have already developed a favorite. Then maybe try out all the IDEs you can find and pick one that suits you the best.


PARTNERS