Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Yes. In any case, almost all time goes to the simulation regardless; the move decision part is just a for loop that takes a dozen microseconds at most.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Lunar Ball has this interesting feature, that on the configuration screen, its friction setting can be arbitrarily selected from integer values 0 to 255.
The default value is 32.
The value 0 in particular is very interesting: It literally means "no friction whatsoever".
[img_right]http://bisqwit.iki.fi/kala/snap/newtoncradle.gif[/img_right] A pool game played in completely frictionless setup is a very different game from a normal pool game. In a frictionless game, it is more than possible, that a careless shot makes the game completely unwinnable. Indeed, it is easy to demonstrate such a shot that will leave the game into an infinite loop, much resembling the effect that happens in the popular gadget, "Newton's cradle". In such a loop, there is no choice but to reset the console, terminating the game.
From a computer player's viewpoint, this means that the searching space for valid moves is drastically smaller than it is for a regular game: most shots produce either an infinite loop, or they result in the eventual demise of the cue ball. Due to the law of conservation of energy, so called "preparation shots" simply cannot be done, either. This also means that unless you "suicide" once in a while (intentionally pocket the cue ball), you get a "PERFECT" message in all boards, and that the scores skyrocket. Also, the timeout for shots should be set considerably longer than in a default-friction game, because the balls can be gliding for a long time before they eventually find a pocket.
The question is... Would this be interesting to see?
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
NrgSpoon wrote:
My only guess is that the bug on stage 40 could have something to do with the sprite limit per line? Since it has all the balls lined up horizontally, plus all those obstacles added in. Possibly a lag factor involved in the checks.
Noting the fact that the music was also affected, and the moment it was, I think it was something like that the number of collisions was too high and it overflowed some buffer. This demands investigation! Dejavu. Hmmm…
http://bisqwit.iki.fi/jutut/lunarball.lst -- disassembly
http://bisqwit.iki.fi/jutut/lunarball.map -- ram map
If someone wants to do research.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
mklip2001 wrote:
Very nice! By the way, what the heck happened with stage 40? Why did the balls disappear in that spot?
That's what I would like to know, too! Somehow, the game generated spontaneously a few black holes to the board.
EDIT 2010-02-02: Oh, I now watched it with sounds. Apparently the music was affected too!
mklip2001 wrote:
Also, you got a Perfect on that stage with the single ball (I think it's stage 27). It's quite impressive, but is it faster to beat that stage in 2 shots to avoid getting the Perfect bonus?
It has been almost two years since that stage was played, but I remember that this was indeed the solution the bot ended up with ― and it did test shooting a dummy shot first. It did offer a number of ways of pocketing a few balls instead of all of them, but I think I was quite happy of keeping this shot in the movie (it's not that common a sight, don't you think!) instead of exploring a way to pocket balls in more rounds.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Nach wrote:
Bisqwit wrote:
I can't even think of those posts looking funny 1 month after the movie has been published.
Well, now it's some years later, and I still find it funny.
It seems your opinion, which you mistakenly believe you're entitled to, is in fact - Wrong!
As memory goes, even after reading those posts again, I have no idea what was going on, and I now don't even see the alleged funny.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
L-Spiro wrote:
I should say that the correct answer is only correct between 32-bit and 64-bit machines.
Sorry for insisting, but even given what you wrote, are there no platforms where "long" size may be 64-bit but pointer size is 32-bit? I would imagine that many 64-bit platforms have no need for 64-bit pointers...
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
So the "tiny consideration" was regarding the relative placement of the void* and the long, in that on 64-bit Windows, void* and long are not the same size because "long" is still 32 bits?
I see. How about platforms where long is larger than void*? Such as 16-bit Borland C++. Your "best" selection would lead into the following memory layoutexcept that BC aligns at 2, never at 4:
You yourself said that you are programming for various non-PC platforms, such as the Nintendo DS, so you cannot exclude 16-bit platforms, since those are used often for microcontrollers.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Status: Board 40 is about to be completed within a day or three.
Apparently, turns out that the bot figured out a way to create stable black holes.
I'll post a WIP after this board is completed.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
L-Spiro wrote:
As such, the answer for #7 is also based on simplicity, and I am at least willing to tell you that it is similar to #3 and #4.
If I give any more hints than that then it may become too simple to solve, so I have to stop there.
Well, this is pointless, but here goes.
#7:
for ( int I = iTotal; I-- > 0; ) {
// Do something.
}
#1: Dost thou mean: CallFunction(fX * 0.0625, fY * 0.0625)?
Falls to the category "redundant". See, here's what GCC produces for the original code at -O1:
_Z1gv:
movsd .LC0(%rip), %xmm1
movapd %xmm1, %xmm0
mulsd fY(%rip), %xmm1
mulsd fX(%rip), %xmm0
jmp CallFunction
<...>
.LC0: .long 0, 1068498944
At most, this is a pessimization, because it hides the purpose of the code. Remember, the source code is also a documentation ― first and moremostly, it should document the intended purpose of the code, and only next, convey the practical means used to accomplish the purpose, in the simplest and easiest to maintain manner possible. At least that is the view I hold firmly and dearly.
If you have got SSE2, you can also go with:
#include <emmintrin.h>
<...>
__m128d tmp2 = _mm_mul_pd(_mm_set_pd(fX,fY), _mm_set1_pd(1.0 / 16.0));
CUtils::CallFunction(_mm_cvtsd_f64(tmp2), _mm_cvtsd_f64(_mm_unpackhi_pd(tmp2,tmp2)) );
>:-B , producing this assembly code:
_Z1gv:
movsd fY(%rip), %xmm0
movhpd fX(%rip), %xmm0
mulpd .LC0(%rip), %xmm0
movapd %xmm0, %xmm1
unpckhpd %xmm1, %xmm1
jmp CallFunction
<...>
.LC0: .long 0, 1068498944, 0, 1068498944
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
L-Spiro wrote:
#7: These are all not bad at improving speed, but is there something else you can do? Less duffy.
It's not the same as #3 and #4? Eh. I'll pass if that's the case.
#8: struct SOMEstruct {
int_least64_t i64Member2;
void* pvMember1;
long lMember0;
char padding[ (sizeof(void*)*4) - sizeof(int_least64_t) - sizeof(void*) - sizeof(long) ];
};
I wouldn't use something such unportable as __int64. Rather, int_least64_t which can be found in stdint.h.
The padding is here to make it properly aligned when stored in an array. On 32-bit, this pads to 16 bytes (otherwise 8+4+4 = 16 bytes) if the compiler does not choke on the zero-length array. On 64-bit, this pads to 32 bytes (otherwise 8+8+8 = 24 bytes).
I was also thinking of possible limitations on various addressing modes and whether it makes sense to place some particular element at zero offset in order to make the access opcode shorter, but I cannot think f any reason why one of those elements should be prioritized over another.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
L-Spiro wrote:
#2: In this quiz, all of the code produces the desired output.
Maybe then you want to do vVec.z = ::sin(fA); vVec.y = -vVec.z; which is something the compiler should be able to do anyway; CSE is not exactly rocket science.
Or maybe you want sincos(fA, &vVec.z, &vVec.x); vVec.y = -vVec.z;, which incidentally is more or less exactly what GCC 4.3.4 produces of the original code (ICC 11.1, too), sans redundant memory reads.
L-Spiro wrote:
#5: That being said, your code IS the best strict replacement for the example code; if we can not assume that the value will always be either 0 or 1, then your code is the best answer. And you are also the only person so far to give that answer.
Not exactly, ulSwitch = (~ulSwitch) & 1 may be even better. It was nowhere indicated that it should be assumed that the values of ulSwitch are 0 or 1 beforehand. If they are, one should use bool and the ! operator instead (since you are already going with C++). :) At least on GCC, ! for bool value becomes a xor by 1 on some platforms. If you insist, I can spell it here: ulSwitch ^= 1;
#7: Oh you've got to be kidding me.
If iTotal is never negative (apologies for missing indents, code and spoiler doesn't work together):
do { unsigned n = iTotal >> 3;
switch( iTotal & 7 )
{
case 0: while(n-- > 0) {
/* do something */;
case 7: /* do something */;
case 6: /* do something */;
case 5: /* do something */;
case 4: /* do something */;
case 3: /* do something */;
case 2: /* do something */;
case 1: /* do something */; }
} } while(0);
If iTotal may be negative:
#ifdef __GNUC__
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
do { int i = 0; if(likely((i < iTotal))) { unsigned n = (iTotal+7) >> 3;
switch( (iTotal) & 7 )
{
case 0: do { /* do something */;
case 7: /* do something */;
case 6: /* do something */;
case 5: /* do something */;
case 4: /* do something */;
case 3: /* do something */;
case 2: /* do something */;
case 1: /* do something */;} while(--n > 0));
} } } while(0);
You may also be looking for a less duffy solution:
{ int i=0; for(; i+4 <= iTotal; i += 4) { /* code, code, code, code */ }
switch(iTotal-i) { case 3: /* code */ case 2: /* code */ case 1: /* code */ default:break; } }
But beware that manual loop unrolling, which the compilers are often capable of doing themselves, robs the compiler of its oversight on opportunities for loop vectorization.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
#1: Hard to guess what you are going for here. Maybe it's related to the fact that the variables are still going to be passed as doubles, and you think double division would be more efficient than float division? I shrug.
#2. My guess is that this is not the proper formula for whatever vector calculation you are going for in here. Maybe you want a sin(fA)-cos(fA) somewhere.
#3: Casting after subtracting 1UL? Well that's weird. I'd do -1 after the cast. That is highly suspect. In fact, if I want to loop backwards, I prefer this: for(size_t s = vvector.size(); s-- > 0; )
#4: Initializing I to 0UL probably is not a problem, but it's weird. Is vVector a vector of unsigned longs? Also, you haven't considered the case of the vector being empty -- in that case you see, 0 is not the maximum; NaN is. :)
#5: "wrong"? eh. Well, if this is what you want... ulSwitch = (ulSwitch & 1)^1;
#6: "wrong"? eh. Do you want anding and shifting? I'll pass. The compiler can do that. If you want to imply that you wanted :16 bit fixed-point math, just replace 16 with 65536.
#7: I'd use lowercase for i.
#8: I wouldn't use hungarian notation. Oh, and you may want to rearrange the elements so that int64 comes first and the others come last; this saves some space on 32-bit platforms, but not on 64-bit ones.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Derakon wrote:
One question: how is subtracting '0' equivalent to bitwise-anding 7? '0' is 48, or 110000 in binary; 7 is 111 in binary. Let's try 57, or 111001. Subtracting off '0' gives 1001 (9); bitwise-anding 7 gives 001 (1).
Characters 0123456789 are in the ASCII range 0x30 .. 0x39. In this program, only characters 01234 (0x30..0x34) were used.
'4' - '0' gives the value 4. 0x34 & 0x07 gives the value 4.
'0' - '0' gives the value 0. 0x30 & 0x07 gives the value 0.
0x39 (57, '9') is outside the set of '0', '1', '2', '3' and '4' for which the expression was written to work and give proper values. It would also work for '5', '6' and '7', but not for '8' or '9'.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
As I wrote, you don't need to set any path variables (unless your svn executable is not in any of the directories indicated by your PATH variable, and even then, you can refer to the svn binary by its full/relative pathname).
Also, you're now consistently mixing up repository paths with executable paths.
If your svn executable is found without problem without any path setting (i.e. svn help shows a message from svn), you do not need to touch your PATH setting.
What it is that you want to checkout?
Just put that repository address on the svn commandline, after the word "co", and you're accomplishing the checkout.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
PATH is meant for listing those paths from which executables (i.e. programs) are to be looked for when you type a program's name without its pathname.
However, your use of %SVN% suggests that what you want to do is to add repository paths to some common variable.
Please explain carefully what it is you actually want to accomplish.
In general, if you want to checkout some remote repository, you don't need to set up any variables. Just do this:
svn co <repository address here> <object name here>
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Bisqwit wrote:
I first wrote the program in a clean manner, then compressed it by reducing all variable names and using the operators in a funny way
Let me post an example of such an iterative process.
Here's a C program which produces season's greetings ― a different greeting depending on time of day.
#include <sys/time.h>
#include <stdio.h>
int main(void)
{
time_t t;
struct tm* tm;
t = time(NULL); /* Get current time in seconds */
tm = localtime(&t); /* Transform a timestamp to broken-down time, relative to user's timezone */
switch(tm->tm_hour) /* Choose action from the hour value */
{
case 4:case 5:case 6:case 7:
case 8:case 9:case 10:case 11:
printf("Good morning!\n");
break;
case 12:case 13:case 14:
printf("Good day!\n");
break;
case 15:case 16:case 17:
printf("Good afternoon!\n");
break;
case 18:case 19:case 20:case 21:
printf("Good evening!\n");
break;
default:
printf("Good night!\n");
break;
}
return 0;
}
This is revision 1. Anyone who knows the basic syntax of C can read exactly what happens here without strain.
Now, to make it shorter by using data as a substitute for working logic:
#include <sys/time.h>
int main()/* revision 7*/{time_t t=time(0);return printf("Good %s!\n",
"morning\0day\0afternoon\0evening\0night"-194+2*"ppppaaaaaaaaeeegggllllppp"[localtime(&t)->tm_hour]);}/* 194 comes from 'a'*2 */
Or:
#include <sys/time.h>
int main()/* revision 7b*/{time_t t=time(0);return printf("Good %s!\n",
"day\0night\0morning\0evening\0afternoon"-64+"DDDDJJJJJJJJ@@@ZZZRRRRDD"[localtime(&t)->tm_hour]);}
Or:
#include <sys/time.h>
char*d="''''--------###===5555'' Good %s!\n\0day\0night\0morning\0evening\0afternoon";
int main()/* revision 8*/{time_t t=time(0);return printf(d+25,d+d[localtime(&t)->tm_hour]);}
If you rely on the fact that time() returns an int (or a long), and that the value measures seconds since 1970-01-01 00:00 GMT, and you know your timezone, you can discard localtime() and simply calculate the hour from the time() return value by modulo mathematics, and you could discard the one #include. For the sake of portability, we'll skip that.
Anyway, this is how such messy source code is produced. It has its uses in IOCCC, novelty and code generation, but not when it is meant to be maintained by humans.
Editor, Experienced Forum User, Published Author, Active player
(296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
nfq wrote:
I watched your youtube video too, and you write really fast. Do you use a normal "qwerty" keyboard layout?
Thanks for watching. I do type fast, but the recording process was lagged somewhat, which artificially increased my apparent typing speed by a noticeable percentage. Which is good, because just like with TASes, it improved the entertainment (quality/quantity ratio). I use qwerty.
Dromiceius> The article you linked to does not talk about QBasic's tokenization, though. That is closer to what C64 did. QBasic does not allow the meaning of program to change by tokenization/whitespace removal. (ANDY is a legal variable name in QB.)
Arflech> That code was not really meant to be human-read, either. It is autogenerated by a program I wrote. (I.e. I first wrote the program in a clean manner, then compressed it by reducing all variable names and using the operators in a funny way, and then I fit it into C strings to be outputted by this intgen program, whose output you see here.)
I posted it to provide contrast to the other post.