Thread: Returning part of multidimensional array of pointer/data from function

  1. #1
    Registered User
    Join Date
    May 2015
    Posts
    65

    Returning part of multidimensional array of pointer/data from function

    What I'm doing in essence, is this:

    Code:
    class {
        char* marr[4][4][4];
    public:
        constr() {
            for(int y = 0; y < 4; y++)
                for(int x = 0; x < 4; x++)
                    marr[3][3-x][y] = marr[2][3-y][3-x] = marr[1][x][3-y] = marr[0][y][x] = new char;
        }
        ~destr() {
            for(int y = 0;y < 4; y++)
                for(int x = 0; x < 4; x++)
                    delete marr[0][y][x];
        }
    }
    What I need to do, but can't quite figure out, is to return the allocated data, or in essence:

    Code:
    return *marr[0]
    This example obviously doesn't work, but should pretty much explain what I need, except to say that I don't necessarily need the data in the form of an array, or even of type char.

    I suspect I will be able to find a solution, but it will almost certainly be very ugly, so I hope you can help.

    NB: I will also be interested to know if I'm deallocating correctly, or if it's even necessary.


    Best regards.
    Last edited by Zacariaz; 05-20-2015 at 08:43 PM.

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    use std::vector and return it without problem
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by vart View Post
    use std::vector and return it without problem
    That is of course an option, but I think for the time being, I'll simply change my approach, and return single field instead.

    Thanks for the reply.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Why are you being stubborn? The fact that you aren't using vector in the first place is troublesome.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by Elysia View Post
    Why are you being stubborn? The fact that you aren't using vector in the first place is troublesome.
    I'm not being stubborn, I've just come to the conclusion that a different approach is preferable. I would however be interest to know what you mean by it being "troublesome" that I'm not using std::vector in the first place. What's wrong with using the basic tools at your disposal when possible?

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Zacariaz View Post
    I would however be interest to know what you mean by it being "troublesome" that I'm not using std::vector in the first place. What's wrong with using the basic tools at your disposal when possible?
    Do you use your fists or a screwdriver to screw screws? Vector is a basic tool in your library that is suited for dynamic arrays that you're apparently using. It's made and tested. Why would you use more basic tools like your fists to do stuff when there's a perfectly usable tool that's tested and tried available?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by Elysia View Post
    Do you use your fists or a screwdriver to screw screws? Vector is a basic tool in your library that is suited for dynamic arrays that you're apparently using. It's made and tested. Why would you use more basic tools like your fists to do stuff when there's a perfectly usable tool that's tested and tried available?
    As far as I understand it, there's nothing 'dynamic' about what I'm doing. I'm simply representing a 4 by 4 data set, including possible rotations.

    And as for std::vector being a basic tool, in my mind, as long as I have to make an effort to include it, there's nothing basic about it.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Zacariaz View Post
    And as for std::vector being a basic tool, in my mind, as long as I have to make an effort to include it, there's nothing basic about it.
    So you'd rather spent many days designing, testing and debugging rather than take a little moment to include a simple header? Great way to do programming, I completely agree!
    ...Not.

    That is seriously the worst excuse I have ever heard.
    Are you going to reinvent the wheel every time you need to do something instead of refactoring it into a separate file and using it as a component too?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by Elysia View Post
    So you'd rather spent many days designing, testing and debugging rather than take a little moment to include a simple header? Great way to do programming, I completely agree!
    ...Not.

    That is seriously the worst excuse I have ever heard.
    Are you going to reinvent the wheel every time you need to do something instead of refactoring it into a separate file and using it as a component too?
    But I didn't spend many days designing and testing, not anything relevant to this discussions at least, and the few issues I did have, I would also have had using std::vector, only difference being of course, that I would have been able to return it without searching for an answer which I have yet to find.

    On the other hand, not using std::vector made me reconsider my position, and come to the correct conclusion that I taking the wrong approach anyway, which likely wouldn't have happened, had I been using std::vector from the start.


    It is not that I cannot understand your position. I'm sure many come here asking for help, and refuse to acknowledge when they're told that they're doing it wrong, I just don't agree that this is the case here.

    Also, regardless of any other relevant or irrelevant issues, I'd still like to know the answer to my original question, or if there even is an answer. It's not always about getting things done quickly and pain free. Sometimes learning , or even having a philosophical debate, is it's own reward.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, you know... what you wish to do is up to you. Doing stuff just for learning purposes is fine. I tend to reinvent the wheel sometimes too, just because I feel like doing it, and learn something in the process at times. That's not what I'm criticizing. What I'm criticizing is attitude: "as long as I have to make an effort to include it, there's nothing basic about it." Vector is basics of basics. There's nothing to it. Write an include and it can save you a ton of time, because it's just so simple. There are pretty complex stuff out there and frankly learning how to use those frameworks and whatnot can be very daunting, and in that case, it is indeed a question of whether putting all that time into actually learning it is worth it or not. So in that case, I'd agree that it's not basic. But you have to ask yourself: is this going to same me time and frustration or not?

    As for your question... you can't return an arrays from a function. Period. The language doesn't allow it. There are ways around that, of course, but they're mostly just workarounds or hacks. Ugly hacks. The clean way is just to use vector because it just works. It's natural. So. Options:
    - Wrap your array into a struct and return that struct (ugly workaround).
    - Return the array by taking an additional parameter to the function. The caller is responsible for creating the object or allocating space. Ugly. Makes sense if the function is going to work with an existing object, but in this case it's not. It's just returning internal data, and in that case, the recommended method is just to return the directly from the function. Except it doesn't work with C arrays.

    If the dimensions of the array is always fixed, you can also use std::array. IT works just fine with std::array too because it can be returned from a function as opposed to a C array.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by Elysia View Post
    Well, you know... what you wish to do is up to you. Doing stuff just for learning purposes is fine. I tend to reinvent the wheel sometimes too, just because I feel like doing it, and learn something in the process at times. That's not what I'm criticizing. What I'm criticizing is attitude: "as long as I have to make an effort to include it, there's nothing basic about it." Vector is basics of basics. There's nothing to it. Write an include and it can save you a ton of time, because it's just so simple. There are pretty complex stuff out there and frankly learning how to use those frameworks and whatnot can be very daunting, and in that case, it is indeed a question of whether putting all that time into actually learning it is worth it or not. So in that case, I'd agree that it's not basic. But you have to ask yourself: is this going to same me time and frustration or not?

    As for your question... you can't return an arrays from a function. Period. The language doesn't allow it. There are ways around that, of course, but they're mostly just workarounds or hacks. Ugly hacks. The clean way is just to use vector because it just works. It's natural. So. Options:
    - Wrap your array into a struct and return that struct (ugly workaround).
    - Return the array by taking an additional parameter to the function. The caller is responsible for creating the object or allocating space. Ugly. Makes sense if the function is going to work with an existing object, but in this case it's not. It's just returning internal data, and in that case, the recommended method is just to return the directly from the function. Except it doesn't work with C arrays.

    If the dimensions of the array is always fixed, you can also use std::array. IT works just fine with std::array too because it can be returned from a function as opposed to a C array.
    I already knew that I would have to return a pointer, if anything, but I suppose I should have been more specific. What I was interested to know what if it was possible not only to return a pointer to the whole array (return marr I suppose), but rather to a part of the array (something like return &marr[0]).

    As for my attitude, it is true that more often than not, I do things the hard way. It's who I am, I can't help it, and it has it's pros and cons.

    To take an example, just yesterday I needed to employ std::fstream, which at first seemed trouble free, but when it came to the point that I had to read from the file, apparently there was no way around also using std::string. I spend hours researching alternatives to no avail, and in the end I had to surrender to the facts of life. Still, while I was crying my self to sleep, I also learned a lot i the process, so it weren't all bad.
    It will come as not surprise to me that you and many other think this quite stupid (also the crying party was a joke), but think about it for a moment. I have to read 5 lines, one of which is to be put into a char array anyway, and might be saved as 16 int's instead, had it made a difference, and the rest of which are to be converted to ints. I didn't need no strings when saving to file, but when reading from file, apparently there's no way around it. How does that make sense?

    In any case, as so many times before and after having seriously considered just dumping the pretty oop and rewrite the whole thing in straight C, which wouldn't take a lot of work, I accepted it and got on with it.
    You can't always get what you wan't.

    I don't think I've ever looked in to std::array, so I will certainly do that.

    Lastly, thank you for your input. I think it was and interesting conversation for both of us.

    Also, I do apologize for the rant, but I'll leave it in just for the fun of it.


    Best regards.
    Last edited by Zacariaz; 05-22-2015 at 08:11 PM.

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Zacariaz View Post
    What I was interested to know what if it was possible not only to return a pointer to the whole array (return marr I suppose), but rather to a part of the array (something like return &marr[0]).
    It's possible, but you have to consider how the array is laid out in memory. You can take a dimension and pull it out (e.g. &MyArray[0], &MyArray[0][0]). If you want to go more advanced, you're going to have to copy out the data into a new array.

    To take an example, just yesterday I needed to employ std::fstream, which at first seemed trouble free, but when it came to the point that I had to read from the file, apparently there was no way around also using std::string.
    There is, but honestly, you shouldn't be doing it for anything other than quick non-production code. It's brittle and full of quirks. And don't think of trying to use C-strings for this. That's just silliness. std::string does all the work for you.

    I have to read 5 lines, one of which is to be put into a char array anyway
    Why? Why do you insist on using C arrays?

    and might be saved as 16 int's instead, had it made a difference, and the rest of which are to be converted to ints.
    Sounds like premature optimization to me.

    I didn't need no strings when saving to file, but when reading from file, apparently there's no way around it. How does that make sense?
    There is a way.

    std::fstream my_file(...);
    my_file >> my_int;

    But like I said, it's full of quirks.
    C++ I/O is not the best designed library out there exactly...

    Anyway, it sounds very much like "learning a new language" syndrome. You're used to another language and you're trying to learn a new one. Being new to it, you don't fully master its usage, so it doesn't always go so smooth. So when you hit a wall, you always consider just going back to what you know instead. I know of it. Heck, it happens to all of us when learning a new language. But honestly, if you're going to learn a language, you're just going to have to accept it and try and try again until you learn. Falling back to working code is a bad habit. Of course, if it's production code, then you're going to have to make a decision of whether it's worth investing enough time in learning the new way as opposed to just sticking with the old way.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    May 2015
    Posts
    65
    Quote Originally Posted by Elysia View Post
    It's possible, but you have to consider how the array is laid out in memory. You can take a dimension and pull it out (e.g. &MyArray[0], &MyArray[0][0]). If you want to go more advanced, you're going to have to copy out the data into a new array.


    There is, but honestly, you shouldn't be doing it for anything other than quick non-production code. It's brittle and full of quirks. And don't think of trying to use C-strings for this. That's just silliness. std::string does all the work for you.


    Why? Why do you insist on using C arrays?


    Sounds like premature optimization to me.


    There is a way.

    std::fstream my_file(...);
    my_file >> my_int;

    But like I said, it's full of quirks.
    C++ I/O is not the best designed library out there exactly...

    Anyway, it sounds very much like "learning a new language" syndrome. You're used to another language and you're trying to learn a new one. Being new to it, you don't fully master its usage, so it doesn't always go so smooth. So when you hit a wall, you always consider just going back to what you know instead. I know of it. Heck, it happens to all of us when learning a new language. But honestly, if you're going to learn a language, you're just going to have to accept it and try and try again until you learn. Falling back to working code is a bad habit. Of course, if it's production code, then you're going to have to make a decision of whether it's worth investing enough time in learning the new way as opposed to just sticking with the old way.
    1. Good to know.

    2. I know it's possible, anything is really, but as you said, there must be a limit to silliness.

    3. Again, the problem would be the same if I was using std::vector. Perhaps what you're misinterpreting is the fact that I'm using a char array, but that's simply a matter of using 16 bytes of memory instead of 64. Of course it makes no difference in the real worl, but my screwed up mind is what it is.

    4. hmm... No, but it could've been.

    5. GOTO 2

    6. Actually I've always preferred C for it's simplicity and C++ for OOP aspect. I did mess around with ASM a long time ago, when I was interested in OS programming for a while, but of course it didn't get me anywhere. That is not not to say that I haven't tried other languages too. Hell I started out with PHP, which I have long since forgotten, I've tried Java, because it's so popular, but I absolutely hated it. when I was still doing the MicroShaft (Windows) dance, I even checked out C#, which is actually nice in many way, but not really for me, and I've been doing some scripting of various sorts from time to time (python, bash, etc), when I needed such tools, but always I've come back to C/C++.

    In conclusion, I don't think I'm as inept at C/C++ as you suggest, but I have had a rather long break from it, so obviously I'm going to ask a few stupid questions, and even the questions that aren't really stupid, often appear so, due to me being rather inept at asking such questions. I tend to always leave out some important detail of something.

    In any case, my current project is actually done and it works very well as far as I can tell. It would be nice for someone to validate me in that assumption, but then I'd have to commend my code, and there isn't an appropriate forum section here anyway...

    Bah, I'm just rambling on as usual.

  14. #14
    Registered User
    Join Date
    May 2015
    Posts
    65
    So... I actually took the time to comment the code... Very unlike me.

    So, in case you're curious (I know I would be), here it is:

    Main.cpp (example use):
    Code:
    #include "Game.h"#include <curses.h>
    #include <ctime>
    
    
    int main() {
        // char font[][][] used for pretty output
        const char font[5][18][12] = {
    {"           ","         # ","      #### ","      #### ","      #  # ","      #### ","      #    ","      #### ","      #### ","      #### ","    # #### ","    #    # ","    # #### ","    # #### ","    # #  # ","    # #### ","    # #    ","    # #### "},
    {"           ","         # ","         # ","         # ","      #  # ","      #    ","      #    ","         # ","      #  # ","      #  # ","    # #  # ","    #    # ","    #    # ","    #    # ","    # #  # ","    # #    ","    # #    ","    #    # "},
    {"           ","         # ","      #### ","      #### ","      #### ","      #### ","      #### ","         # ","      #### ","      #### ","    # #  # ","    #    # ","    # #### ","    # #### ","    # #### ","    # #### ","    # #### ","    #    # "},
    {"           ","         # ","      #    ","         # ","         # ","         # ","      #  # ","         # ","      #  # ","         # ","    # #  # ","    #    # ","    # #    ","    #    # ","    #    # ","    #    # ","    # #  # ","    #    # "},
    {"           ","         # ","      #### ","      #### ","         # ","      #### ","      #### ","         # ","      #### ","         # ","    # #### ","    #    # ","    # #### ","    # #### ","    #    # ","    # #### ","    # #### ","    #    # "}};
    
    
        Game test;
        // initialize curses and all that.
        initscr();
        raw();
        curs_set(0);
        keypad(stdscr, TRUE);
        noecho();
        // if there is a game to load, load it, otherwise start new game.
        int ch = (test.LoadGame()) ? ('n') : (0);
        // catch various keys untill quit-
        do {
            switch(ch) {
                case 'w':
                case 'W':
                case KEY_UP:
                    test.MoveUp();
                    break;
                case 's':
                case 'S':
                case KEY_DOWN:
                    test.MoveDown();
                    break;
                case 'a':
                case 'A':
                case KEY_LEFT:
                    test.MoveLeft();
                    break;
                case 'd':
                case 'D':
                case KEY_RIGHT:
                    test.MoveRight();
                    break;
                case 'n':
                case 'N':
                    test.SetSeed(time(0));
                    test.NewGame();
                    break;
                default:
                {
                
                }
            }
            // print the board.
            mvprintw(0, 0, "+-----------+-----------+-----------+-----------+\n"); 
            for(int y = 0; y < 4; y++) {
                for(int n = 0; n < 5; n++)
                    printw("|%s|%s|%s|%s|\n", font[n][test.GetField(y, 0)], font[n][test.GetField(y, 1)], font[n][test.GetField(y, 2)], font[n][test.GetField(y, 3)]);
                printw("+-----------+-----------+-----------+-----------+\n");
            }
            printw("Score: %d\n", test.GetScore());
            printw("Moves: %d\n\n", test.GetMoves());
            printw("Press'n' for new game and 'q' for quits.\nUse the arrow keys or 'a, s, d, w' to play.\n");
            // get key;
            ch = getch();
        } while(ch != 'q' && ch != 'Q');
        // end curses.
        endwin();
        // save game.
        test.SaveGame();
        return 0;
    }
    Game.cpp:
    Code:
    #include "Game.h"
    
    Game::Game() {
        // Allocate memory and initialize rotated boards.
        for(int y = 0; y < 4; y++)
            for(int x = 0; x < 4; x++)
                board[3][3-x][y] = board[2][3-y][3-x] = board[1][x][3-y] = board[0][y][x] = new char;
    }
    
    
    Game::~Game() {
        // Deallocate memory.
        for(int y = 0;y < 4; y++)
            for(int x = 0; x < 4; x++)
                delete board[0][y][x];
    }
    
    
    void Game::NewGame() {
        // Initialize random number generator from seed.
        srand(seed);
        // Initialize/reset various variables.
        moves = score = rcount = 0;
        // Reset board.
        for(int y = 0; y < 4; y++)
            for(int x = 0; x < 4; x++)
                *board[0][y][x] = 0;
        // Call for the initial tiles.
        NewTile();
        NewTile();
    }
    // Move board[z] left. Return 1 if not possible.
    bool Game::Move(direction z) {
        // Initialize b to 1 / Assume failure.
        bool b = 1;
        // Move all fields left where possible, due to empty squares.
        // do not otherwise change anything.
        for(int y = 0; y < 4; y++)
            for(int n = 0; n < 3; n++)
                for(int x = 2; x >= 0; x--)
                    if(!*board[z][y][x] && *board[z][y][x+1]) {
                        *board[z][y][x] = *board[z][y][x+1];
                        *board[z][y][x+1] = 0;
                        // if board has changes, success! Set b to 0.
                        b = 0;
                    }
        // Row for Row.
        for(int y = 0; y < 4; y++) {
            // A whole lot of testing and moving about. Explanation difficult.
            if(*board[z][y][0] && *board[z][y][0] == *board[z][y][1]) {
                (*board[z][y][0])++;
                score += P2(*board[z][y][0]);
                if(*board[z][y][2] && *board[z][y][2] == *board[z][y][3]) {
                    *board[z][y][1] = *board[z][y][2]+1;
                    score += P2(*board[z][y][1]);
                    *board[z][y][2] = *board[z][y][3] = 0;
                }
                else {
                    *board[z][y][1] = *board[z][y][2];
                    *board[z][y][2] = *board[z][y][3];
                    *board[z][y][3] = 0;
                }
                // if board has changes, success! Set b to 0.
                b = 0;
            }
            else if(*board[z][y][1] && *board[z][y][1] == *board[z][y][2]) {
                (*board[z][y][1])++;
                *board[z][y][2] = *board[z][y][3];
                score += P2(*board[z][y][1]);
                *board[z][y][3] = 0;
                // if board has changes, success! Set b to 0.
                b = 0;
            }
            else if(*board[z][y][2] && *board[z][y][2] == *board[z][y][3]) {
                (*board[z][y][2])++;
                score += P2(*board[z][y][2]);
                *board[z][y][3] = 0;
                // if board has changes, success! Set b to 0.
                b = 0;
            }
        }
        // if b == 0, Success! Call NewTile and increment moves.
        if(!b) {
            NewTile();
            moves++;
        }
        // Return success or failure.
        return b;
    }
    
    
    bool Game::NewTile() {
        // Initialize b to 1 / Assume failure.
        bool b = 1;
        // Test for any empty squares.
        for(int y = 0; y < 4; y++) 
            for(int x = 0; x < 4; x++)
                if(!*board[0][y][x]) {
                    b = 0;
                    break;
                }
        // If no empty squares, failure. Return 1, else continue.
        if(b)
            return 1;
        // Initialize c and generate random 1 or 2, with 90% likelyhood of 1.
        char c = (rand() % 10)?(1):(2);
        // Initialize bp and generate random integer from 0 to 15.
        int bp = rand() % 16;
        // increase rcount by the number of times rand() hase been called.
        // The use for this will become apparent.
        rcount += 2;
        // While bp does not refar to an empty sqare, generate a new one.
        while(*board[0][bp/4][bp%4]) {
            bp = rand() % 16;
            rcount++;
        }
        // Assign c to the the relevant square.
        *board[0][bp/4][bp%4] = c;
        // NB: Al this randomness could be done a whole lot better.
        // Just haven't thought of a way yet.
    }
    // Avoid std::math.
    // return 2^n
    int Game::P2(char n) {
        int result = 1;
        for(; n > 0; n--)
            result *= 2;
        return result;
    }
    // Call  Move() with the relevant directional parameter.
    bool Game::MoveLeft() {
        return Move(LEFT);
    }
    
    
    bool Game::MoveDown() {
        return Move(DOWN);
    }
    
    
    bool Game::MoveRight() {
        return Move(RIGHT);
    }
    
    
    bool Game::MoveUp() {
        return Move(UP);
    }
    // Set a specific seed. Should be done prior to calling NewGame().
    void Game::SetSeed(unsigned int n) {
        seed = n;
    }
    // Return specific square.
    int Game::GetField(unsigned int y, unsigned int x) {
        return (y > 3 || x > 3) ? -1 : (int)*board[0][y][x];
    }
    // return score.
    int Game::GetScore() {
        return score;
    }
    // Return moves.
    int Game::GetMoves() {
        return moves;
    }
    // save game
    bool Game::SaveGame() {
        // Open file...
        std::ofstream file("game.save");
        // If file is open...
        if (file.is_open()) {
            // Save *board[0] in the form of a 16 letter string with values  ranging from 'A' to 'R'
            for(int y = 0; y < 4; y++)
                for(int x = 0; x < 4; x++)
                    file << char(*board[0][y][x] + 65);
            // Save seed, score, moves and rcount in the form of integer strings.
            file << "\n" << seed;
            file << "\n" << score;
            file << "\n" << moves;
            file << "\n" << rcount;
            // Close file and return 0.
            file.close();
            return 0;
        }
        // Something went wrong. Return 1.
        else
            return 1;
    }
    
    
    bool Game::LoadGame() {
        // We apparently need a string.
        std::string line;
        // As before. Open and test.
        std::ifstream file("game.save");
        if(file.is_open()) {
            // Get first line...
            getline(file, line);
            // Get single letters, return them to their original value and position.
            for(int y = 0; y < 4; y++)
                for(int x = 0; x < 4; x++)
                    *board[0][y][x] = line.at(y*4+x) - 65;
            // Get second line etc...
            getline(file, line);
            // Convert to int and return to original value and repeat...
            seed = std::stoi(line);
            getline(file, line);
            score = std::stoi(line);
            getline(file, line);
            moves = std::stoi(line);
            getline(file, line);
            rcount = std::stoi(line);
            // Close file.
            file.close();
            srand(seed);
            // NB: There must be a better way...
            // Call rand() the appropriate number of times to return to the original state.
            for(int n = 0; n < rcount; n++)
                rand();
            // We did it! Return 0.
            return 0;
        }
        // Something went wrong. Return 1.
        else
            return 1; 
    }
    Game.h:
    Code:
    #ifndef GAME_H#define GAME_H
    // std::cstdlib for random number necesities.
    #include <cstdlib>
    // std::fstream and std::string for file IO.
    #include <fstream>
    #include <string>
    
    
    // Should probably figure a better class name.
    class Game {
        // Variable declerations...
        unsigned int seed, moves, score, rcount;
        char* board[4][4][4];
        // Is enum an appropriate solution?
        enum direction {LEFT, DOWN, RIGHT, UP};
        // Private member functions
        // Move() return 0 for success and  for failure.
        bool Move(direction);
        // NewTile()() return 0 for success and  for failure.
        bool NewTile();
        // Return 2^n
        int P2(char);
    public:
        Game();
        ~Game();
        // Set new seed. Should be done prior to calling NewGame()
        void SetSeed(unsigned int);
        // Reset the relevant variables, empty the board and call for 2 new tiles.
        void NewGame();
        // Call Move(direction)
        bool MoveLeft();
        bool MoveDown();
        bool MoveRight();
        bool MoveUp();
        // Should probably be GetTile().
        // Takes 2 arguments (int)y, (int)x
        int GetField(unsigned int, unsigned int);
        // Return score.
        int GetScore();
        // Return Moves.
        int GetMoves();
        // Save game.
        bool SaveGame();
        //LoadGame
        bool LoadGame();
    };
    
    
    #endif
    Makefile (to make things easier... Maybe...):
    Code:
    all:
    	g++ main.cpp Game.cpp Game.h -l ncurses -std=c++11 -o game
    Obviously it isn't perfect, as I've also written in the comments, but still, I think I've done rather well, especially with the rotated boarda. The idea just hit me out of the blue. You should have seen my previous attempt. What a mess... I didn't even bother trying to find the mistake once I noticed that on rare occasions weird stuff happened.

    Anyway, enjoy, if you so desire, and should you have any insight I'm very interested.


    Other than that, until a reply pops up, I'll assume that we're all done and wish you a nice day or whatever it is where you're at.


    Best regards.

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I think this might be a simple misunderstanding. As declared in the class Game, the board is a 3d array. As a class member it has class scope, meaning that every function in game knows what board is and it can be accessed or modified. So, there is no reason to really return something. Especially not in the constructors or destructors. These are special member functions with no return type, so returning from them is not even an option.

    If you really do want to return the board or part of the board in some other member function, so that the rest of the program can do something with it, I would just tell you to make the board dynamic:
    Code:
    char *board = new char[DEPTH * COLS * ROWS];
    // assuming that succeeds you can access via board[depth][col][row]
    // using the formula:
    board[(depth_i * COLS + col_i) * ROWS + row_i]
    Convert the formula to a function for easy computation. It is far easier and (possibly) safer to return board this way.

    None of this is as safe as using a container like vector - though, I would prefer using a matrix object to help you represent a data cube.

    Also,
    Code:
    // Avoid std::math.
    // return 2^n
    return (1 << n);
    A single instruction is the fastest. I would be surprised if pow() doesn't do that for base 2 exponents, but you can also code it directly...
    Last edited by whiteflags; 05-23-2015 at 02:39 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 09-06-2012, 11:49 AM
  2. Replies: 2
    Last Post: 06-02-2009, 03:07 AM
  3. Replies: 0
    Last Post: 05-29-2009, 05:48 AM
  4. Pointer to multidimensional array
    By ejohns85 in forum C++ Programming
    Replies: 4
    Last Post: 03-24-2009, 11:17 AM
  5. pointer to multidimensional array
    By Bigbio2002 in forum C++ Programming
    Replies: 4
    Last Post: 02-05-2006, 10:29 PM