-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chris c2 #2
base: master
Are you sure you want to change the base?
Chris c2 #2
Conversation
(in particular (x & 1 == 0) <> (x % 2 == 0) due to C precedence rules)
And use LifeState *state consistently Also make the two operand Parse function the base implementation. Four operand Parse is now derived from it.
PRNG courtesy of Stebastian Vigna at http://xorshift.di.unimi.it
Previously no $ was printed if line ends in a live cell. Easy fix was to take numempty++ out of the "else" block but I rewrote as well. Also, GetCell should not have "val" as argument
I used std::stringstream and std::string for GetRLE. I've some issue with namespace std (it requires some lib/dll). I wanted to avoid std, also because it's known source of performance troubles (if you add benchmark - see how adding "using namespace std" will effect you, it's simply horrible). I know you used it correctly, just saying I want to keep it simple and out of troubles. Evolve(after, before, iters) is something I would like to go in. This is only another overload - so great. *a) - doesn't influence anything external. *b) - rename AreEqual to IsEqual - hmm ok. I think IsEqual is the standard, but I saw AreEqual few times. Anyway IsEqual is fine by me. I think it could be a good idea to move to separate LifeAPI.h and LifeAPI.cpp.
|
Thinking about it a little bit. We can have nice separation into .h and .cpp for coding. I'll write simple script that unifies all files together into one single .h file, to use #include LifeAPI.h alone, for external usage. What do you think? I think this can allow adding classes. If so LifeState could be converted to class. Let me see how complex this change is. |
I wanted to avoid std Ok, your choice. Actually I never head that std was difficult to find lib/dll for. Anyway, isn't the current GetRLE using O(n^2) memory? Lots of malloc's but no free's. Also it gives this warning a lot in g++: deprecated conversion from string constant to ‘char’* If we go to separate .cpp and .h only Just Another argument for separate .h and .cpp is that currently lots of stuff that should not be seen by the end user is leaking out, e.g. GlobalState, Temp, Temp1, Temp2, CirculateLeft, .... I'm sure there is more. |
I still want to give the end user only single "LifeAPI.h" with lots of code - including many classes inside single .h file. My idea is to "combine" LifeAPI.h from few smaller classes and methods, to make the development more systematic. As developers we can setup the compiler to compile .cpp hierarchically. But as the end user, I just want to add LifeAPI.h and have it all (maybe later we will have some additional includes, but for now I want to keep the usage of LifeAPI as simple as it gets). The compile time is pretty small, so the main reason for separating .h and .cpp (to allow modular development, and reduce compilation time) is not present in this project. As for allowing access to private members - I've started with c approach, without private - public option at all. If we will move into classes, we can hide stuff as privates, inside LifeAPI.h itself. |
Ok, your choice. But I don't think it's a great burden on the user to type
instead of
In windows it can't be much harder. PS. I just thought of this bit-hack style method for implementing BitIterator. x[64] should iterate through all subsets of mask[64].
|
Well think of computer science student. He wants to use #include < stdio.h > and to have printf and scanf functions immediately. No one wants to go into compiler flags and start tweaking them around after #include. I know it looks simple after you know it (and that stdio.h is actually using lib), but many times you just want to #include and forget. There are solution to this of course - like releasing .lib files together with .h etc. still I prefer to keep it as simple as #include<stdio.h> if possible. As I mentioned - let's have normal c++ project, I'll also post all compiler flags for it. But just have in mind that our "release" for the "clients", will consist from single LifeAPI.h - it's really not an issue to convert normal project into single .h, and as far as I understand it's exactly the same thing, it's just that the compilation time takes a bit longer. EDIT: There is another advantage of adding only .h file. One can tweak it around as he wishes. If someone finds a bug he could fix it in LifeAPI.h itself, without the need to download the project, and make it compile. EDIT2: I want to make some smarter BitIterator, that will work in amortized O(1) + will run in cols like lifesrc, and if some col failed it will continue from the place it failed without iterating further. But we can start from your piece of code - it's a good start. |
With a single .h file it seems impossible to shield the global variables GlobalState, Temp etc from the end user. Ok, you can put them in a class, but then that class still needs to be globally visible. That seems like an uglier situation than having separate LifeAPI.cpp and LifeAPI.h to me. Regarding the global Temp variables, they can be got rid of by putting Temp on the stack of the function. LifeState is fixed size so there should be no cost for doing this. I never looked at the lifesrc program. It sounds interesting. |
lifesrc is more know as WinLifeSearch (which is simply lifesrc with GUI). You have N columns with 3 states, life-dead-unknown. It has special rule that replace unknown to what would you get in life (like 4 neighbors + any unknowns will be dead, or 2 life + unknown will remain as is). Then the program iterates the unknown states, to try to figure out what can be flipped from unknown to known. It searches for oscillators and spaceships. You can also search for parents with it - it's the best way to find sparks that later become the pattern you need. This is how codeholic found the spark for the dart. This approach reduces a lot of brute force checking, as sometimes every unknown state will yield no results. But because it has three states it's sometimes slower than simple brute force, and as deeper you search the more unknowns you'll get, so the less efficient it becomes. This is why 8 generation is kinda the limit for this approach. Using LifeAPI "smart brute force" iterator that works fast and doesn't continue after contradiction has been found, might break this barrier (especially if we will have GPU accelerator). Using brute force and fast bit iterator, will allow iterate much deeper, because brute force doesn't care how deep you search the pattern, place 30 unknown bits - and iterate as much as you like. This would be great for smart parent search as well. If you want to practice BitIterators, just make a BitIterator that finds some of the small p2 spaceships. You can start from iterating on two columns of 10x2 and see what can move one cell after 2 generations. Then add another column to find another non-contradiction etc. do it iteratevlly, until you'll find p2 spaceship. As for .cpp and .h topic - The only useful way I see on how to release LifeAPI without headache, is to add LifeAPI.lib with LifeAPI.h - I don't like this idea for simple reason. Think that I have borland c++ compiler (or some other strange creature and strange OS), and it gives me 10 errors. With LifeAPI.h I can go and fix it pretty simply. With some pre- compiled library, or flags in compiler that will give me linker errors, or maybe my compiler has some other issues, or maybe I use some "smart" tool that configs the compiler flags, and this is not too friendly tool - It's just much harder. Keeping with the current simplicity, will allow people to enjoy LifeAPI without thinking too much about anything. If some "smart guy" wants to use Temp, or something of this sort, he's welcome to destroy his app as much as he wished. I just hope that people who want to write fast and simple apps would be able to do so. We can also give some "ugly" names to objects that we don't want the end users to use, to warn them. I don't like c++ too much, because it's sometimes VERY hard to find what is wrong, while something stupid using std can kill your performance. So I want to keep it simple for the "end-user" which we should assume is not "stupid" as he writes c++ app, but also let's keep our requirements of him to the bare minimum. Some more advanced users can always peek into the more "systematic" part of the project, with classes hierarchically divided. LifeAPI.h will be the "plug and play" version of the project. |
Ok, it's just a difference of opinion. As an end user I would find it not so simple that LifeAPI.h is introducing a lot of variables and functions that I don't need. I am lazy and would prefer to see just 20-30 lines of clean function declarations in LifeAPI.h and all the implementation in LifeAPI.cpp. But never mind, we can't keep talking about this forever :) |
We do agree about the best way to maintain the project, the question is how to release it to the "clients". So the release which happens once in a while anyway, can have two options:
We will give the users advice to first try the Plug & Play to see what LifeAPI is all about. You just #include LifeAPI.h and play around with it. If you like the concept, you can "install" much cleaner version of LifeAPI. |
Here are a few more patches. I used std::stringstream and std::string for GetRLE. Memory management is much easier and g++ gives a load of warning about plain char * otherwise. Evolve(after, before, iters) is something I would like to go in. It seems to suit my way of working better. What do you think?
Also I have some ideas for more changes:
First, Rename the three comparison functions as follows so that everything is the same between functions for GlobalState and the rest:
a) Get rid of Contains(main, spark) and AreDisjoint(main, spark) and rename AllOn(main, subset) and AllOff(main, subset) like in the Global case.
b) Rename AreEqual to IsEqual in both cases. I think that the global version AreEqual(pat) with one argument sounds bad so better to rename both. IsEqual(pat1, pat2) sounds ok I think.
Second, I think it could be a good idea to move to separate LifeAPI.h and LifeAPI.cpp. I think it would be a very attractive feature for users if LifeAPI.h was a super clean and super concise file that explains 90% of the functionality of LifeAPI without even needing to read the documentaion.
Thoughts?