diff options
author | Wohlstand <admin@wohlnet.ru> | 2017-11-08 00:24:04 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2017-11-08 00:24:04 +0300 |
commit | 9e529f121f5e19720e14f77cce65aed9ecf0ecf7 (patch) | |
tree | f2ad05b12864405cd7d6771848c66d93cdb14d66 /utils | |
parent | e3fa4e69e09f8a475a5fcca6916532014e5b2338 (diff) | |
download | libADLMIDI-9e529f121f5e19720e14f77cce65aed9ecf0ecf7.tar.gz libADLMIDI-9e529f121f5e19720e14f77cce65aed9ecf0ecf7.tar.bz2 libADLMIDI-9e529f121f5e19720e14f77cce65aed9ecf0ecf7.zip |
Fixed Windows MSVC build (adlmidi2 and gen_adldata)
Diffstat (limited to 'utils')
-rw-r--r-- | utils/adlmidi-2/midiplay.cc | 88 | ||||
-rwxr-xr-x | utils/adlmidi-2/puzzlegame.hpp | 1704 | ||||
-rw-r--r-- | utils/gen_adldata/file_formats/load_jv.h | 2 | ||||
-rw-r--r-- | utils/gen_adldata/ini/ini_processing.cpp | 4 | ||||
-rw-r--r-- | utils/gen_adldata/measurer.cpp | 4 | ||||
-rw-r--r-- | utils/gen_adldata/progs_cache.h | 1 |
6 files changed, 913 insertions, 890 deletions
diff --git a/utils/adlmidi-2/midiplay.cc b/utils/adlmidi-2/midiplay.cc index 8ede11b..ddfa030 100644 --- a/utils/adlmidi-2/midiplay.cc +++ b/utils/adlmidi-2/midiplay.cc @@ -11,7 +11,9 @@ #include <ctime> #include <cstdarg> #include <cmath> +#ifndef _WIN32 #include <unistd.h> +#endif #include <stdarg.h> #include <cstdio> #include <vector> // vector @@ -20,22 +22,30 @@ #include <assert.h> +#ifndef _WIN32 #define SUPPORT_VIDEO_OUTPUT #define SUPPORT_PUZZLE_GAME +#endif -#ifdef __WIN32__ +#if !defined(_WIN32) || !defined(_MSC_VER) +#define ATTRIBUTE_FORMAT_PRINTF(x, y) __attribute__((format(printf, x, y))) +#else +#define ATTRIBUTE_FORMAT_PRINTF(x, y) +#endif + +#ifdef _WIN32 # include <cctype> # define WIN32_LEAN_AND_MEAN +# define NOMINMAX //To don't damage std::min and std::max # include <windows.h> # include <mmsystem.h> #endif -#if defined(__WIN32__) || defined(__DJGPP__) +#if defined(_WIN32) || defined(__DJGPP__) typedef unsigned char Uint8; typedef unsigned short Uint16; typedef unsigned Uint32; #else - #define SDL_MAIN_HANDLED #include <SDL2/SDL.h> @@ -69,7 +79,7 @@ public: #include <stdlib.h> #define BIOStimer _farpeekl(_dos_ds, 0x46C) static const unsigned NewTimerFreq = 209; -#elif !defined(__WIN32__) || defined(__CYGWIN__) +#elif !defined(_WIN32) || defined(__CYGWIN__) # include <termios.h> # include <fcntl.h> # include <sys/ioctl.h> @@ -118,7 +128,7 @@ static unsigned WinHeight() return result; } -#if (!defined(__WIN32__) || defined(__CYGWIN__)) && defined(TIOCGWINSZ) +#if (!defined(_WIN32) || defined(__CYGWIN__)) && defined(TIOCGWINSZ) extern "C" { static void SigWinchHandler(int); } @@ -141,19 +151,19 @@ static void GuessInitialWindowHeight() static class Input { - #ifdef __WIN32__ + #ifdef _WIN32 void *inhandle; #endif - #if (!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__) + #if (!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__DJGPP__) struct termio back; #endif public: Input() { - #ifdef __WIN32__ + #ifdef _WIN32 inhandle = GetStdHandle(STD_INPUT_HANDLE); #endif - #if (!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__) + #if (!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__DJGPP__) ioctl(0, TCGETA, &back); struct termio term = back; term.c_lflag &= ~(ICANON | ECHO); @@ -164,7 +174,7 @@ public: } ~Input() { - #if (!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__) + #if (!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__DJGPP__) if(ioctl(0, TCSETA, &back) < 0) fcntl(0, F_SETFL, fcntl(0, F_GETFL) & ~ O_NONBLOCK); #endif @@ -179,7 +189,7 @@ public: return c ? c : getch(); } #endif - #ifdef __WIN32__ + #ifdef _WIN32 DWORD nread = 0; INPUT_RECORD inbuf[1]; while(PeekConsoleInput(inhandle, inbuf, sizeof(inbuf) / sizeof(*inbuf), &nread) && nread) @@ -195,7 +205,7 @@ public: } } #endif - #if (!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__) + #if (!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__DJGPP__) char c = 0; if(read(0, &c, 1) == 1) return c; #endif @@ -248,7 +258,7 @@ public: bool DirtyCells[TxWidth * TxHeight] = {false}; unsigned NDirty = 0; #endif - #ifdef __WIN32__ + #ifdef _WIN32 void *handle; #endif int x, y, color, txtline, maxy; @@ -268,7 +278,7 @@ public: maxy(0), cursor_visible(true) { GuessInitialWindowHeight(); - #ifdef __WIN32__ + #ifdef _WIN32 handle = GetStdHandle(STD_OUTPUT_HANDLE); GotoXY(41, 13); CONSOLE_SCREEN_BUFFER_INFO tmp; @@ -285,7 +295,7 @@ public: //SetConsoleScreenBufferSize(handle,size); } #endif - #if (!defined(__WIN32__) || defined(__CYGWIN__)) && defined(TIOCGWINSZ) + #if (!defined(_WIN32) || defined(__CYGWIN__)) && defined(TIOCGWINSZ) std::signal(SIGWINCH, SigWinchHandler); #endif #ifdef __DJGPP__ @@ -294,7 +304,9 @@ public: std::memset(slots, '.', sizeof(slots)); std::memset(background, '.', sizeof(background)); std::memset(backgroundcolor, 1, sizeof(backgroundcolor)); + #ifndef _WIN32 setbuffer(stderr, stderr_buffer, sizeof(stderr_buffer)); + #endif RawPrn("\r"); // Ensure cursor is at the x=0 we imagine it being Print(0, 7, true, "Hit Ctrl-C to quit"); } @@ -302,7 +314,7 @@ public: { if(!cursor_visible) return; cursor_visible = false; - #ifdef __WIN32__ + #ifdef _WIN32 if(handle) { const CONSOLE_CURSOR_INFO info = {100, false}; @@ -328,7 +340,7 @@ public: cursor_visible = true; GotoXY(0, maxy); Color(7); - #ifdef __WIN32__ + #ifdef _WIN32 if(handle) { const CONSOLE_CURSOR_INFO info = {100, true}; @@ -422,7 +434,7 @@ public: #endif void PutC(char c) { - #ifdef __WIN32__ + #ifdef _WIN32 if(handle) WriteConsole(handle, &c, 1, 0, 0); else #endif @@ -440,13 +452,16 @@ public: #ifdef __DJGPP__ # define RawPrn cprintf #else - static void RawPrn(const char *fmt, ...) __attribute__((format(printf, 1, 2))) + static void RawPrn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2) { // Note: should essentially match PutC, except without updates to x va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); + #ifdef _WIN32 + fflush(stderr); + #endif } #endif @@ -487,7 +502,7 @@ public: return nchars; } - int Print(unsigned beginx, unsigned color, bool ln, const char *fmt, ...) __attribute__((format(printf, 5, 6))) + int Print(unsigned beginx, unsigned color, bool ln, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(5, 6) { va_list ap; va_start(ap, fmt); @@ -495,7 +510,7 @@ public: va_end(ap); return r; } - int PrintLn(const char *fmt, ...) __attribute__((format(printf, 2, 3))) + int PrintLn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3) { va_list ap; va_start(ap, fmt); @@ -608,7 +623,7 @@ public: y += 1; x = 0; } - #ifdef __WIN32__ + #ifdef _WIN32 if(handle) { CONSOLE_SCREEN_BUFFER_INFO tmp; @@ -656,7 +671,7 @@ public: { if(color != newcolor) { - #ifdef __WIN32__ + #ifdef _WIN32 if(handle) SetConsoleTextAttribute(handle, newcolor); else @@ -863,7 +878,7 @@ static struct MyReverbData } } reverb_data; -#ifdef __WIN32__ +#ifdef _WIN32 namespace WindowsAudio { static const unsigned BUFFER_COUNT = 16; @@ -1095,7 +1110,7 @@ static void SendStereoAudio(unsigned long count, short *samples) //static unsigned counter = 0; if(++counter < 8000) return; - #if defined(__WIN32__) && 0 + #if defined(_WIN32) && 0 // Cheat on dosbox recording: easier on the cpu load. { count *= 2; @@ -1107,7 +1122,7 @@ static void SendStereoAudio(unsigned long count, short *samples) } #endif - #ifdef __WIN32__ + #ifdef _WIN32 std::vector<short> AudioBuffer(count * 2); const size_t pos = 0; #else @@ -1217,6 +1232,7 @@ static void SendStereoAudio(unsigned long count, short *samples) // raise(SIGINT); } + #ifdef SUPPORT_VIDEO_OUTPUT if(WriteVideoFile) { static constexpr unsigned framerate = 15; @@ -1258,7 +1274,9 @@ static void SendStereoAudio(unsigned long count, short *samples) } } } - #ifndef __WIN32__ + #endif + + #ifndef _WIN32 AudioBuffer_lock.Unlock(); #else if(!WritePCMfile) @@ -1445,7 +1463,7 @@ static void SendStereoAudio(unsigned long count, short *samples) // NextGM(+1); // break; // case 3: -// #if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) +// #if !((!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__DJGPP__)) // case 27: // #endif // return false; @@ -1468,7 +1486,7 @@ static void TidyupAndExit(int) raise(SIGINT); } -#ifdef __WIN32__ +#ifdef _WIN32 /* Parse a command line buffer into arguments */ static void UnEscapeQuotes(char *arg) { @@ -1589,6 +1607,7 @@ int main(int argc, char **argv) // The lag between visual content and audio content equals // the sum of these two buffers. + #ifndef _WIN32 WritingToTTY = isatty(STDOUT_FILENO); if(WritingToTTY) { @@ -1600,6 +1619,9 @@ int main(int argc, char **argv) #endif ); } + #else + WritingToTTY = true; + #endif if(WritingToTTY) { UI.Print(0, 3, true, "(C) -- http://iki.fi/bisqwit/source/adlmidi.html"); @@ -1726,7 +1748,7 @@ int main(int argc, char **argv) #ifndef __DJGPP__ - #ifndef __WIN32__ + #ifndef _WIN32 static SDL_AudioSpec spec, obtained; spec.freq = PCM_RATE; spec.format = AUDIO_S16SYS; @@ -1861,7 +1883,7 @@ int main(int argc, char **argv) //const double maxdelay = MaxSamplesAtTime / (double)PCM_RATE; - #ifdef __WIN32 + #ifdef _WIN32 WindowsAudio::Open(PCM_RATE, 2, 16); #else SDL_PauseAudio(0); @@ -1933,7 +1955,7 @@ int main(int argc, char **argv) //fprintf(stderr, "Enter: %u (%.2f ms)\n", (unsigned)AudioBuffer.size(), // AudioBuffer.size() * .5e3 / obtained.freq); - #ifndef __WIN32__ + #ifndef _WIN32 const SDL_AudioSpec &spec_ = (WritePCMfile ? spec : obtained); for(unsigned grant = 0; AudioBuffer.size() > spec_.samples + (spec_.freq * 2) * OurHeadRoomLength; ++grant) { @@ -2007,7 +2029,7 @@ int main(int argc, char **argv) #else - #ifdef __WIN32__ + #ifdef _WIN32 WindowsAudio::Close(); #else SDL_CloseAudio(); diff --git a/utils/adlmidi-2/puzzlegame.hpp b/utils/adlmidi-2/puzzlegame.hpp index e003f6b..551d4bb 100755 --- a/utils/adlmidi-2/puzzlegame.hpp +++ b/utils/adlmidi-2/puzzlegame.hpp @@ -1,853 +1,853 @@ -/* A block puzzle game.
- * Most of the source code comes from https://www.youtube.com/watch?v=V65mtR08fH0
- * Copyright (c) 2012 Joel Yliluoma (http://iki.fi/bisqwit/)
- * License: MIT
- */
-
-// Standard C++ includes:
-#include <cstdio> // for std::puts
-#include <cstdlib> // for std::rand
-#include <cstring> // for std::memcpy
-#include <algorithm> // for std::abs, std::max, std::random_shuffle
-#include <utility> // for std::pair
-#include <vector> // for std::vector
-#include <cstdint>
-#include <chrono>
-
-// Coroutine library. With thanks to Simon Tatham.
-#define ccrVars struct ccrR { int p; ccrR() : p(0) { } } ccrL
-#define ccrBegin(x) auto& ccrC=(x); switch(ccrC.ccrL.p) { case 0:;
-#define ccrReturn(z) do { ccrC.ccrL.p=__LINE__; return(z); case __LINE__:; } while(0)
-#define ccrFinish(z) } ccrC.ccrL.p=0; return(z)
-
-namespace ADLMIDI_PuzzleGame
-{
- // Field & rendering definitions
- const auto Width = 18, Height = 25; // Width and height, including borders.
- const auto SHeight = 12+9;
-
- const auto Occ = 0x10000u;
- const auto Empty = 0x12Eu, Border = Occ+0x7DBu, Garbage = Occ+0x6DBu;
-
- static unsigned long TimerRead()
- {
+/* A block puzzle game. + * Most of the source code comes from https://www.youtube.com/watch?v=V65mtR08fH0 + * Copyright (c) 2012 Joel Yliluoma (http://iki.fi/bisqwit/) + * License: MIT + */ + +// Standard C++ includes: +#include <cstdio> // for std::puts +#include <cstdlib> // for std::rand +#include <cstring> // for std::memcpy +#include <algorithm> // for std::abs, std::max, std::random_shuffle +#include <utility> // for std::pair +#include <vector> // for std::vector +#include <cstdint> +#include <chrono> + +// Coroutine library. With thanks to Simon Tatham. +#define ccrVars struct ccrR { int p; ccrR() : p(0) { } } ccrL +#define ccrBegin(x) auto& ccrC=(x); switch(ccrC.ccrL.p) { case 0:; +#define ccrReturn(z) do { ccrC.ccrL.p=__LINE__; return(z); case __LINE__:; } while(0) +#define ccrFinish(z) } ccrC.ccrL.p=0; return(z) + +namespace ADLMIDI_PuzzleGame +{ + // Field & rendering definitions + const auto Width = 18, Height = 25; // Width and height, including borders. + const auto SHeight = 12+9; + + const auto Occ = 0x10000u; + const auto Empty = 0x12Eu, Border = Occ+0x7DBu, Garbage = Occ+0x6DBu; + + static unsigned long TimerRead() + { static std::chrono::time_point<std::chrono::system_clock> begin = std::chrono::system_clock::now(); - return 519 * std::chrono::duration<double>( std::chrono::system_clock::now() - begin ).count();
- }
- #define Timer TimerRead()
- static void Sound(unsigned/*freq*/, unsigned/*duration*/)
- {
- }
- static void PutCell(int x, int y, unsigned cell);
- static void ScreenPutString(const char* str, unsigned attr, unsigned column, unsigned row)
- {
- for(; *str; ++column, ++str)
- {
- PutCell(column, row, ((unsigned char)(*str & 0xFF)) | (attr << 8));
- }
- }
- static char peeked_input = 0;
- static bool kbhit()
- {
- if(peeked_input) return true;
- peeked_input = Input.PeekInput();
- return peeked_input != 0;
- }
- static char getch()
- {
- char r = peeked_input;
- peeked_input = 0;
- return r;
- }
-
- // Game engine
- using uint64_t = std::uint_fast64_t;
- struct Piece
- {
- struct { uint64_t s[4]; } shape;
- int x:8, y:8, color:14;
- unsigned r:2;
-
- template<typename T> // walkthrough operator
- inline bool operator>(T it) const
- {
- uint64_t p = 1ull, q = shape.s[r];
- for(int by=0; by<8; ++by)
- for(int bx=0; bx<8; ++bx)
- {
- if((q & p) && it(x+bx, y+by)) return true;
- //p >>= 1ull;
- p <<= 1ull;
- }
- return false;
- }
- template<typename T> // transmogrify operator
- inline Piece operator*(T it) const { Piece res(*this); it(res); return res; }
- };
-
- template<bool DoDraw>
- struct TetrisArea
- {
- int Area[Height][Width];
- unsigned RenderX;
- unsigned n_full, list_full, animx;
- unsigned long timer;
- struct { ccrVars; } cascadescope;
- public:
- TetrisArea(unsigned x=0) : RenderX(x) { }
-
- bool Occupied(int x,int y) const
- { return x<1 || (x>Width-2) || (y>=0 && (Area[y][x] & Occ)); }
-
- template<typename T>
- inline void DrawRow(unsigned y, T get)
- {
- for(int x=1; x<Width-1; ++x) DrawBlock(x,y, get(x));
- }
-
- inline bool TestFully(unsigned y, bool state) const
- {
- for(int x=1; x<Width-1; ++x) if(state != !!(Area[y][x]&Occ)) return false;
- return true;
- }
-
- void DrawBlock(unsigned x,unsigned y, int color)
- {
- if(x < (unsigned)Width && y < (unsigned)Height) Area[y][x] = color;
- if(DoDraw) PutCell(x+RenderX, y, color);
- }
-
- void DrawPiece(const Piece& piece, int color)
- {
- piece>[&](int x,int y)->bool { this->DrawBlock(x,y,color); return false; };
- }
-
- bool CollidePiece(const Piece& piece) const
- {
- return piece>[&](int x,int y) { return this->Occupied(x,y); };
- }
- bool CascadeEmpty(int FirstY)
- {
- if(DoDraw)
- {
- ccrBegin(cascadescope);
-
- // Count full lines
- n_full = list_full = 0;
- for(int y = std::max(0,FirstY); y < Height-1; ++y)
- if(TestFully(y,true))
- {
- ++n_full;
- list_full |= 1u << y;
- }
- if(n_full)
- {
- // Clear all full lines in Tengen Tetris style.
- for(animx = 1; animx < Width-1; ++animx)
- {
- for(timer=Timer; Timer<timer+6; ) ccrReturn(true);
- auto label =
- " SINGLE "
- " DOUBLE "
- " TRIPLE "
- " TETRIS "
- "QUADRUPLE "
- "QUINTUPLE "
- " SEXTUPLE "
- " SEPTUPLE "
- " OCTUPLE "+(n_full-1)*10;
- for(int y = FirstY; y < Height-1; ++y)
- if(list_full & (1u << y))
- DrawBlock(animx,y, label[(animx%10)] + 0x100);
- if(DoDraw) Sound(10 + animx*n_full*40, 2);
- }
- if(DoDraw) Sound(50, 15);
- // Cascade non-empty lines
- int target = Height-2, y = Height-2;
- for(; y >= 0; --y)
- if(!(list_full & (1u << y)))
- DrawRow(target--, [&](unsigned x) { return this->Area[y][x]; });
- // Clear the top lines
- for(auto n=n_full; n-- > 0; )
- DrawRow(target--, [](unsigned) { return Empty; });
- }
- ccrFinish(false);
- }
- else
- {
- // Cascade non-empty lines
- int target = Height-2, y = Height-2;
- n_full = 0;
- for(int miny = std::max(0,FirstY); y >= miny; --y)
- if(TestFully(y, true))
- {
- ++n_full;
- miny = 0;
- }
- else
- {
- if(target != y)
- memcpy(&Area[target], &Area[y], sizeof(Area[0][0])*Width);
- --target;
- }
- // Clear the top lines
- for(auto n=n_full; n-- > 0; )
- DrawRow(target--, [](unsigned) { return Empty; });
- return false;
- }
- }
- };
-
- template<bool DoReturns = true>
- class TetrisAIengine: TetrisArea<false>
- {
- public://protected:
- typedef std::pair<int/*score*/, int/*prio*/> scoring;
- struct position
- {
- // 1. Rotate to this position
- int rot;
- // 2. Move to this column
- int x;
- // 3. Drop to ground
- // 4. Rotate to this position
- int rot2;
- // 5. Move maximally to this direction
- int x2;
- // 6. Drop to ground again
- };
-
- std::vector<position> positions1, positions2;
-
- struct Recursion
- {
- // Copy of the field before this recursion level
- decltype(Area) bkup;
- // Currently testing position
- unsigned pos_no;
- // Best outcome so far from this recursion level
- scoring best_score, base_score;
- position best_pos;
- Recursion() : best_pos( {1,5, 1,0} ) { }
- } data[8];
- unsigned ply, ply_limit;
-
- bool restart; // Begin a new set of calculations
- bool confident; // false = Reset best-score
- bool resting; // true = No calculations to do
- bool doubting;
- struct { ccrVars; } aiscope;
-
- public:
- void AI_Signal(int signal)
- {
- // any = piece moved; 0 = new piece, 2 = at ground
- switch(signal)
- {
- case 0: // new piece
- // do full scan and reset score
- confident = false;
- restart = true;
- resting = false;
- doubting = false;
- break;
- case 1: // piece moved
- // keep scanning (low prio), no resets
- resting = false;
- break;
- case 2: // now at ground
- // do full scan without resetting score
- resting = false;
- restart = true;
- doubting = true;
- break;
- }
- }
- int AI_Run(const decltype(Area)& in_area, const Piece* seq)
- {
- std::memcpy(Area, in_area, sizeof(Area));
-
- // For AI, we use Pierre Dellacherie's algorithm,
- // but extended for arbitrary ply lookahead.
- enum {
- landingHeightPenalty = -1, erodedPieceCellMetricFactor = 2,
- rowTransitionPenalty = -2, columnTransitionPenalty = -2,
- buriedHolePenalty = -8, wellPenalty = -2/*,
- occlusionPenalty = 0*/ };
-
- ccrBegin(aiscope);
-
- positions1.clear();
- positions2.clear();
- for(int x=-1; x<Width; ++x)
- for(unsigned rot=0; rot<4; ++rot)
- for(unsigned rot2=0; rot2<4; ++rot2)
- for(int x2=-1; x2<=1; ++x2)
- {
- positions1.push_back( std::move<position> ( {int(rot),x,int(rot2),x2} ) );
- if(rot2 == rot && x2 == 0)
- positions2.push_back( std::move<position> ( {int(rot),x,int(rot2),x2} ) );
- }
-
- confident = false;
- doubting = false;
- Restart:
- restart = false;
- resting = false;
-
- /*std::random_shuffle(positions1.begin(), positions1.end());*/
- std::random_shuffle(positions2.begin(), positions2.end());
-
- ply = 0;
-
- Recursion:
- // Take current board as testing platform
- std::memcpy(data[ply].bkup, Area, sizeof(Area));
- if(!confident || ply > 0)
- {
- data[ply].best_score = {-999999,0};
- if(ply == 0)
- {
- //int heap_room = 0;
- //while(TestFully(heap_room,false)) ++heap_room;
- ply_limit = 2;
- }
- }
- for(;;)
- {
- data[ply].pos_no = 0;
- do {
- if(DoReturns)
- {
- ccrReturn(0);
- if(restart) goto Restart;
- }
- if(ply > 0)
- {
- // Game might have changed the the board contents.
- std::memcpy(data[0].bkup, in_area, sizeof(Area));
-
- // Now go on and test with the current testing platform
- std::memcpy(Area, data[ply].bkup, sizeof(Area));
- }
-
- // Fix the piece in place, cascade rows, and analyze the result.
- { const position& goal = (/*ply==0&&!doubting ? positions1 :*/ positions2)
- [ data[ply].pos_no ];
- Piece n = seq[ply];
- n.x = goal.x;
- n.r = goal.rot;
- if(ply) n.y = 0;
-
- // If we are analyzing a mid-fall maneuver, verify whether
- // the piece can be actually maneuvered into this position.
- //if(ply==0 && n.y >= 0)
- for(Piece q,t=*seq; t.x!=n.x && t.r!=n.r; )
- if( (t.r == n.r || (q=t, ++t.r, CollidePiece(t)&&(t=q,true)))
- && (t.x <= n.x || (q=t, --t.x, CollidePiece(t)&&(t=q,true)))
- && (t.x >= n.x || (q=t, ++t.x, CollidePiece(t)&&(t=q,true))))
- goto next_move; // no method of maneuvering.
-
- // Land the piece if it's not already landed
- do ++n.y; while(!CollidePiece(n)); --n.y;
- if(n.y < 0 || CollidePiece(n)) goto next_move; // cannot place piece?
-
- /*
- // Rotate to ground-rotation
- if(n.r != goal.rot2 || goal.x2 != 0)
- {
- while(n.r != goal.rot2)
- {
- ++n.r;
- if(CollidePiece(n)) goto next_move;
- }
- if(goal.x2 != 0)
- {
- do n.x += goal.x2; while(!CollidePiece(n));
- n.x -= goal.x2;
- }
-
- do ++n.y; while(!CollidePiece(n)); --n.y;
- if(n.y < 0 || CollidePiece(n)) goto next_move; // cannot place piece?
- }
- */
-
- DrawPiece(n, Occ); // place piece
-
- // Find out the extents of this piece, and how many
- // cells of the piece contribute into full (completed) rows.
- char full[4]={-1,-1,-1,-1};
- int miny=n.y+9, maxy=n.y-9, minx=n.x+9, maxx=n.x-9, num_eroded=0;
- n>[&](int x,int y) -> bool
- { if(x < minx) {minx = x;} if(x > maxx) {maxx = x;}
- if(y < miny) {miny = y;} if(y > maxy) {maxy = y;}
- if(full[y - n.y] < 0) full[y - n.y] = this->TestFully(y,true);
- num_eroded += full[y - n.y];
- return false; };
-
- CascadeEmpty(n.y);
-
- // Analyze the board and assign penalties
- int penalties = 0;
- for(int y=0; y<Height-1; ++y)
- for(int q=1,r, x=1; x<Width; ++x, q=r)
- if(q != (r = Occupied(x,y)))
- penalties += rowTransitionPenalty;
- for(int x=1; x<Width-1; ++x)
- for(int ceil=0/*,heap=0*/,q=0,r, y=0; y<Height; ++y,q=r)
- {
- if(q != (r = Occupied(x,y)))
- {
- penalties += columnTransitionPenalty;
- /*if(!r) { penalties += heap * occlusionPenalty; heap = 0; }*/
- }
- if(r) { ceil=1; /*++heap;*/ continue; }
- if(ceil) penalties += buriedHolePenalty;
- if(Occupied(x-1,y) && Occupied(x+1,y))
- for(int y2=y; y2<Height-1 && !Occupied(x,y2); ++y2)
- penalties += wellPenalty;
- }
-
- data[ply].base_score = {
- // score
- (erodedPieceCellMetricFactor * int(n_full) * num_eroded +
- penalties +
- landingHeightPenalty * ((Height-1) * 2 - (miny+maxy))) * 16,
- // tie-breaker
- 50 * std::abs(Width-2-minx-maxx) +
- (minx+maxx < Width-2 ? 10 : 0) - n.r
- - 400*(goal.rot != goal.rot2)
- - 800*(goal.x2 != 0)
- };
- }
- if(ply+1 < ply_limit)
- { ++ply; goto Recursion;
- Unrecursion: --ply; }
-
- /*fprintf(stdout, "ply %u: [%u]%u,%u gets %d,%d\n",
- ply,
- data[ply].pos_no,
- positions[data[ply].pos_no].x,
- positions[data[ply].pos_no].rot,
- data[ply].base_score.first,
- data[ply].base_score.second);*/
-
- if(data[ply].best_score < data[ply].base_score)
- {
- data[ply].best_score = data[ply].base_score;
- data[ply].best_pos = (/*ply==0&&!doubting ? positions1 :*/ positions2) [ data[ply].pos_no ];
- }
- next_move:;
- } while(++data[ply].pos_no < (/*ply==0&&!doubting ? positions1 :*/ positions2).size());
-
- if(ply > 0)
- {
- int v = data[ply].best_score.first;
- v /= 2;
- //if(ply_limit == 4) v /= 2; else v *= 2;
- data[ply-1].base_score.first += v;// >> (2-ply);
- goto Unrecursion;
- /*
- parent += child / 2 :
- Game 0x7ffff0d94ce0 over with score=91384,lines=92
- Game 0x7ffff0d96a40 over with score=153256,lines=114
- parent += child :
- Game 0x7fff4a4eb8a0 over with score=83250,lines=86
- Game 0x7fff4a4ed600 over with score=295362,lines=166
- parent += child * 2 :
- Game 0x7fff000a2e00 over with score=182306,lines=131
- Game 0x7fff000a10a0 over with score=383968,lines=193
- parent += child * 4 :
- Game 0x7fff267867b0 over with score=62536,lines=75
- Game 0x7fff26788510 over with score=156352,lines=114
- */
- }
- // all scanned; unless piece placement changes we're as good as we can be.
- confident = true;
- resting = true;
- doubting = false;
- while(resting) ccrReturn(0);
- if(restart) goto Restart;
- } // infinite refining loop
- ccrFinish(0);
- }
- };
-
- class Tetris: protected TetrisArea<true>
- {
- public:
- Tetris(unsigned rx) : TetrisArea(rx), seq(),hiscore(0),hudtimer(0) {}
- virtual ~Tetris() { }
-
- protected:
- // These variables should be local to GameLoop(),
- // but because of coroutines, they must be stored
- // in a persistent wrapper instead. Such persistent
- // wrapper is provided by the game object itself.
- Piece seq[4];
- unsigned hiscore, score, lines, combo, pieces;
- unsigned long hudtimer;
- bool escaped, dropping, ticked, kicked, spinned, atground, first;
-
- struct { ccrVars; } loopscope;
- public:
- unsigned incoming;
-
- int GameLoop()
- {
- Piece &cur = *seq;
- ccrBegin(loopscope);
-
- // Initialize area
- for(auto y=Height; y-- > 0; )
- for(auto x=Width; x-- > 0; )
- DrawBlock(x,y, (x>0&&x<Width-1&&y<Height-1) ? Empty : Border);
-
- score = lines = combo = incoming = pieces = 0;
- MakeNext();
- MakeNext();
- first=true;
-
- for(escaped = false; !escaped; ) // Main loop
- {
- // Generate new piece
- MakeNext();
- /*if(first) // Use if making 4 pieces
- {
- first=false;
- ccrReturn(0);
- MakeNext();
- }*/
-
- dropping = false;
- atground = false;
- re_collide:
- timer = Timer;
- AI_Signal(0); // signal changed board configuration
-
- // Gameover if cannot spawn piece
- if(CollidePiece(cur))
- {
- break;
- }
-
- ccrReturn(0);
-
- while(!escaped)
- {
- atground = CollidePiece(cur * [](Piece&p){++p.y;});
- if(atground) dropping = false;
- // If we're about to hit the floor, give the AI a chance for sliding.
- AI_Signal(atground ? 2 : 1);
-
- DrawPiece(cur, cur.color);
-
- // Wait for input
- for(ticked=false; ; )
- {
- AI_Run();
- HUD_Run();
- ccrReturn(0);
-
- if(incoming)
- {
- // Receive some lines of garbage from opponent
- DrawPiece(cur, Empty);
- for(int threshold=Height-1-incoming, y=0; y<Height-1; ++y)
- {
- unsigned mask = 0x1EF7BDEF >> (rand()%10);
- DrawRow(y, [&](unsigned x) { return
- y < threshold
- ? Area[y+incoming][x]
- : (mask & (1<<x)) ? Garbage : Empty; });
- }
- // The new rows may push the piece up a bit. Allow that.
- for(; incoming-- > 0 && CollidePiece(cur); --cur.y) {}
- incoming = 0;
- goto re_collide;
- }
-
- ticked = Timer >= timer + std::max(atground?40:10, int( ((17-Level())*8)) );
- if(ticked || MyKbHit() || dropping) break;
- }
-
- Piece n = cur;
- if(MyKbHit()) dropping = false;
-
- switch(ticked ? 's' : (MyKbHit() ? MyGetCh() : (dropping ? 's' : 0)))
- {
- case 'H'<<8: case 'w': ++n.r; /*Sound(120, 1);*/ break;
- case 'P'<<8: case 's': ++n.y; break;
- case 'K'<<8: case 'a': --n.x; /*Sound(120, 1);*/ break;
- case 'M'<<8: case 'd': ++n.x; /*Sound(120, 1);*/ break;
- case 'q': case '\033': /*escaped = true;*/ break;
- case ' ': dropping = true; /*fallthrough*/
- default: continue;
- }
- if(n.x != cur.x) kicked = false;
-
- if(CollidePiece(n))
- {
- if(n.y == cur.y+1) break; // fix piece if collide against ground
- // If tried rotating, and was unsuccessful, try wall kicks
- if(n.r != cur.r && !CollidePiece(n*[](Piece&p){++p.x;})) { kicked = true; ++n.x; } else
- if(n.r != cur.r && !CollidePiece(n*[](Piece&p){--p.x;})) { kicked = true; --n.x; } else
- continue; // no move
- }
- DrawPiece(cur, Empty);
- if(n.y > cur.y) timer = Timer; // Reset autodrop timer
- cur = n;
- }
-
- // If the piece cannot be moved sideways or up from its final position,
- // determine that it must have been spin-fixed into its place.
- // It is a bonus-worthy accomplishment if it ends up clearing lines.
- spinned = CollidePiece(cur*[](Piece&p){--p.y;})
- && CollidePiece(cur*[](Piece&p){--p.x;})
- && CollidePiece(cur*[](Piece&p){++p.x;});
- DrawPiece(cur, cur.color|Occ);
- Sound(50, 30);
-
- while(CascadeEmpty(cur.y)) ccrReturn(0);
- if(n_full > 1) ccrReturn(n_full-1); // Send these rows to opponent
-
- pieces += 1;
- lines += n_full;
- static const unsigned clr[] = {0,1,3,5,8, 13,21,34,45};
- int multiplier = Level(), clears = clr[n_full];
- int bonus = (clears * 100 + (cur.y*50/Height));
- int extra = 0;
- if(spinned) extra = ((clears+1) * ((kicked ? 3 : 4)/2) - clears) * 100;
- combo = n_full ? combo + n_full : 0;
- int comboscore = combo > n_full ? combo*50*multiplier : 0;
- bonus *= multiplier;
- extra *= multiplier;
- score += bonus + extra + comboscore;
- HUD_Add(bonus, extra, comboscore);
- //if(n_full) std::fprintf(stdout, "Game %p += %u lines -> score=%u,lines=%u\n", this, n_full, score,lines);
- }
- //std::fprintf(stdout, "Game %p over with score=%u,lines=%u\n", this, score,lines);
- //over_lines += lines;
-
- if(score > hiscore) hiscore = score;
- HudPrint(7, 4, "", "%-7u", hiscore);
-
- ccrFinish(-1);
- }
-
- protected:
- int Level() const { return 1 + lines/10; }
-
- void MakeNext()
- {
- const int which = 2; // Index within seq[] to populate
- static const Piece b[] =
- {
- { { { 0x04040404,0x00000F00,0x04040404,0x00000F00 } }, 0,0, 0xBDB,0 }, // I
- { { { 0x0000080E,0x000C0808,0x00000E02,0x00020206 } }, 0,0, 0x3DB,0 }, // J
- { { { 0x0000020E,0x0008080C,0x00000E08,0x00060202 } }, 0,0, 0x6DB,0 }, // L
- { { { 0x00000606,0x00000606,0x00000606,0x00000606 } }, 0,0, 0xEDB,0 }, // O
- { { { 0x00080C04,0x0000060C,0x00080C04,0x0000060C } }, 0,0, 0xADB,0 }, // S
- { { { 0x00000E04,0x00040C04,0x00040E00,0x00040604 } }, 0,0, 0x5DB,0 }, // T
- { { { 0x00020604,0x00000C06,0x00020604,0x00000C06 } }, 0,0, 0x4DB,0 }, // Z
- // Add some pentaminos to create a challenge worth the AI:
- { { { 0x00020702,0x00020702,0x00020702,0x00020702 } }, 0,0, 0x2DB,0 }, // +
- { { { 0x000E0404,0x00020E02,0x0004040E,0x00080E08 } }, 0,0, 0x9DB,0 }, // T5
- { { { 0x00000A0E,0x000C080C,0x00000E0A,0x00060206 } }, 0,0, 0x3DB,0 }, // C
- { { { 0x00060604,0x000E0600,0x02060600,0x00060700 } }, 0,0, 0x7DB,0 }, // P
- { { { 0x00060602,0x00070600,0x04060600,0x00060E00 } }, 0,0, 0xFDB,0 }, // Q
- { { { 0x04040404,0x00000F00,0x04040404,0x00000F00 } }, 0,0, 0xBDB,0 }, // I
- { { { 0x00040702,0x00030602,0x00020701,0x00020306 } }, 0,0, 0xDDB,0 }, // R
- { { { 0x00010702,0x00020603,0x00020704,0x00060302 } }, 0,0, 0x8DB,0 }, // F
- // I is included twice, otherwise it's just a bit too unlikely.
- };
- int c = Empty;
- auto fx = [this]() { seq[0].x=1; seq[0].y=-1;
- seq[1].x=Width+1; seq[1].y=SHeight-8;
- seq[2].x=Width+5; seq[2].y=SHeight-8;
- /*seq[3].x=Width+9; seq[3].y=SHeight-8;
- seq[4].x=Width+1; seq[4].y=SHeight-4;
- seq[5].x=Width+5; seq[5].y=SHeight-4;
- seq[6].x=Width+9; seq[6].y=SHeight-4;*/
- };
- auto db = [&](int x,int y)
- {
- PutCell(x+RenderX, y, c);
- return false;
- };
- fx();
- seq[1]>db; seq[0] = seq[1];
- seq[2]>db; seq[1] = seq[2];
- /*seq[3]>db; seq[2] = seq[3];
- seq[4]>db; seq[3] = seq[4];
- seq[5]>db; seq[4] = seq[5];
- seq[6]>db; seq[5] = seq[6];*/
- fx();
- const unsigned npieces = sizeof(b) / sizeof(*b);
- unsigned rnd = (std::rand()/double(RAND_MAX)) * (4*npieces);
- #ifndef EASY
- /*if(pieces > 3)
- {
- int heap_room = 0;
- while(TestFully(heap_room,false)) ++heap_room;
- bool cheat_good = heap_room <= (7 + lines/20);
- bool cheat_evil = heap_room >= 18;
- if(heap_room >= 16 && (pieces % 5) == 0) cheat_good = false;
- if( (pieces % 11) == 0) cheat_good = true;
- if(cheat_good) cheat_evil = false;
- if(cheat_good || cheat_evil)
- {
- // Don't tell anyone, but in desperate situations,
- // we let AI judge what's best for upcoming pieces,
- // in order to prolong the game!
- // So, the AI cheats, but it is an equal benefactor.
- // EXCEPTION: if there is an abundance of space,
- // bring out the _worst_ possible pieces!
- TetrisAIengine<>::scoring best_score;
- unsigned best_choice = ~0u;
- for(unsigned test=0; test<npieces; ++test)
- {
- unsigned choice = (test + rnd) % npieces;
- if(choice == 0) continue; // Ignore the duplicate I (saves time)
- if(cheat_evil && choice == 7) continue; // Don't give +, it's too evil
-
- seq[which] = b[ choice ];
- seq[which].r = 0;
-
- TetrisAIengine<false> chooser;
- chooser.AI_Signal(0);
- chooser.AI_Run(Area, seq);
- auto& s = chooser.data[0].best_score;
- if(best_choice == ~0u
- || (cheat_evil ? s < best_score : s > best_score)
- )
- { best_score = s; best_choice = choice; }
- }
- rnd = best_choice * 4 + (rnd % 4);
- }
- }*/
- #endif
- seq[which] = b[rnd / 4];
- seq[which].r = rnd % 4;
- fx();
- c=seq[1].color; seq[1]>db;
- c=(seq[2].color&0xF00) + 176; seq[2]>db;
- /*c=(seq[3].color&0xF00) + 176; seq[3]>db;
- c=(seq[4].color&0xF00) + 176; seq[4]>db;
- c=(seq[5].color&0xF00) + 176; seq[5]>db;
- c=(seq[6].color&0xF00) + 176; seq[6]>db;*/
- HudPrint(0, SHeight-9, "NEXT:","",0);
- HudPrint(12, 0, "SCORE:", "%-7u", score);
- HudPrint(12, 2, "LINES:", "%-5u", lines);
- HudPrint(12, 4, "LEVEL:", "%-3u", Level());
- }
-
- void HudPrint(int c, int y,const char*a,const char*b,int v=0) const
- {
- char Buf[64];
- snprintf(Buf, sizeof Buf, b, v);
- ScreenPutString(a, 15, RenderX+Width+2, y);
- ScreenPutString(Buf, c, RenderX+Width+2, y+1);
- }
-
- void HUD_Run()
- {
- if(!hudtimer || Timer < hudtimer) return;
- HUD_Add(0,0,0);
- hudtimer = 0;
- }
- void HUD_Add(int bonus, int extra, int combo)
- {
- hudtimer = Timer + 180;
- static const char blank[] = " ";
- HudPrint(10, 6,bonus?blank :blank,bonus?"%+-6d":blank, bonus);
- HudPrint(10, 8,combo?"Combo":blank,combo?"%+-6d":blank, combo);
- HudPrint(13, 10,extra?"Skill":blank,extra?"%+-6d":blank, extra);
- }
-
- virtual void AI_Signal(int) { }
- virtual int AI_Run() { return 0; }
- virtual int MyKbHit() = 0;
- virtual int MyGetCh() = 0;
- public:
- // Return -1 = don't want sleep, +1 = want sleep, 0 = don't mind
- virtual char DelayOpinion() const { return 0; }//dropping ? -1 : 0; }
- };
-
- class TetrisHuman: public Tetris
- {
- public:
- TetrisHuman(unsigned rx) : Tetris(rx) { }
- protected:
- virtual int MyKbHit() { return kbhit(); }
- virtual int MyGetCh() { int c; return (c = getch()) ? c : (getch() << 8); }
- };
-
- class TetrisAI: public Tetris, TetrisAIengine<true>
- {
- protected:
- virtual void AI_Signal(int s) { TetrisAIengine::AI_Signal(s); }
- virtual int AI_Run()
- {
- #ifdef __DJGPP__
- char buf1[16]/*, buf2[16], buf3[16]*/;
- sprintf(buf1, "COM%u%c%c%c%c", ply_limit,
- resting ? 'r' : '_',
- confident ? 'C' : '_',
- doubting ? 'D' : '_',
- atground ? 'G' : '_'
- );
- ScreenPutString(buf1, 0x70, Tetris::RenderX+Width, 0);
- /*
- sprintf(buf2, "%-8d", data[0].best_score.first);
- sprintf(buf3, "%2d,%d", data[0].best_pos.x,
- data[0].best_pos.rot);
- ScreenPutString(buf2, 0x08, Tetris::RenderX+Width, 1);
- ScreenPutString(buf3, 0x08, Tetris::RenderX+Width, 4);
- */
- #endif
- return TetrisAIengine::AI_Run(Tetris::Area, seq);
- }
- virtual int MyKbHit()
- {
- return PendingAIinput ? 1 : (PendingAIinput = GenerateAIinput()) != 0;
- }
- virtual int MyGetCh()
- {
- int r = PendingAIinput;
- return r ? (PendingAIinput=0), r : GenerateAIinput();
- }
- char d(char c, int maxdelay)
- {
- if(Timer >= intimer+maxdelay) { intimer=Timer; return c; }
- return 0;
- }
- int GenerateAIinput()
- {
- /*if(TetrisAIengine::atground)
- {
- if(seq->r != data[0].best_pos.rot2) return d('w',1);
- if(data[0].best_pos.x2 < 0) return d('a', 1);
- if(data[0].best_pos.x2 > 0) return d('d', 1);
- }
- else*/
- {
- if(seq->r != data[0].best_pos.rot) return d('w',1);
- if(seq->y >= 0 && seq->x > data[0].best_pos.x) return d('a', 2);
- if(seq->y >= 0 && seq->x < data[0].best_pos.x) return d('d', 2);
- }
- if(doubting || !confident) return 0;
- return d('s',3);
- }
-
- int PendingAIinput, delay;
- unsigned long intimer;
- public:
- virtual char DelayOpinion() const
- { if(doubting || restart || !confident) return -1;
- return Tetris::DelayOpinion(); }
-
- TetrisAI(unsigned rx) : Tetris(rx), PendingAIinput(0), delay(0), intimer(0) {}
- };
- #undef Timer
-}
+ return (unsigned long)(519 * std::chrono::duration<double>( std::chrono::system_clock::now() - begin ).count()); + } + #define Timer TimerRead() + static void Sound(unsigned/*freq*/, unsigned/*duration*/) + { + } + static void PutCell(int x, int y, unsigned cell); + static void ScreenPutString(const char* str, unsigned attr, unsigned column, unsigned row) + { + for(; *str; ++column, ++str) + { + PutCell(column, row, ((unsigned char)(*str & 0xFF)) | (attr << 8)); + } + } + static char peeked_input = 0; + static bool kbhit() + { + if(peeked_input) return true; + peeked_input = Input.PeekInput(); + return peeked_input != 0; + } + static char getch() + { + char r = peeked_input; + peeked_input = 0; + return r; + } + + // Game engine + using uint64_t = std::uint_fast64_t; + struct Piece + { + struct { uint64_t s[4]; } shape; + int x:8, y:8, color:14; + unsigned r:2; + + template<typename T> // walkthrough operator + inline bool operator>(T it) const + { + uint64_t p = 1ull, q = shape.s[r]; + for(int by=0; by<8; ++by) + for(int bx=0; bx<8; ++bx) + { + if((q & p) && it(x+bx, y+by)) return true; + //p >>= 1ull; + p <<= 1ull; + } + return false; + } + template<typename T> // transmogrify operator + inline Piece operator*(T it) const { Piece res(*this); it(res); return res; } + }; + + template<bool DoDraw> + struct TetrisArea + { + int Area[Height][Width]; + unsigned RenderX; + unsigned n_full, list_full, animx; + unsigned long timer; + struct { ccrVars; } cascadescope; + public: + TetrisArea(unsigned x=0) : RenderX(x) { } + + bool Occupied(int x,int y) const + { return x<1 || (x>Width-2) || (y>=0 && (Area[y][x] & Occ)); } + + template<typename T> + inline void DrawRow(unsigned y, T get) + { + for(int x=1; x<Width-1; ++x) DrawBlock(x,y, get(x)); + } + + inline bool TestFully(unsigned y, bool state) const + { + for(int x=1; x<Width-1; ++x) if(state != !!(Area[y][x]&Occ)) return false; + return true; + } + + void DrawBlock(unsigned x,unsigned y, int color) + { + if(x < (unsigned)Width && y < (unsigned)Height) Area[y][x] = color; + if(DoDraw) PutCell(x+RenderX, y, color); + } + + void DrawPiece(const Piece& piece, int color) + { + piece>[&](int x,int y)->bool { this->DrawBlock(x,y,color); return false; }; + } + + bool CollidePiece(const Piece& piece) const + { + return piece>[&](int x,int y) { return this->Occupied(x,y); }; + } + bool CascadeEmpty(int FirstY) + { + if(DoDraw) + { + ccrBegin(cascadescope); + + // Count full lines + n_full = list_full = 0; + for(int y = std::max(0,FirstY); y < Height-1; ++y) + if(TestFully(y,true)) + { + ++n_full; + list_full |= 1u << y; + } + if(n_full) + { + // Clear all full lines in Tengen Tetris style. + for(animx = 1; animx < Width-1; ++animx) + { + for(timer=Timer; Timer<timer+6; ) ccrReturn(true); + auto label = + " SINGLE " + " DOUBLE " + " TRIPLE " + " TETRIS " + "QUADRUPLE " + "QUINTUPLE " + " SEXTUPLE " + " SEPTUPLE " + " OCTUPLE "+(n_full-1)*10; + for(int y = FirstY; y < Height-1; ++y) + if(list_full & (1u << y)) + DrawBlock(animx,y, label[(animx%10)] + 0x100); + if(DoDraw) Sound(10 + animx*n_full*40, 2); + } + if(DoDraw) Sound(50, 15); + // Cascade non-empty lines + int target = Height-2, y = Height-2; + for(; y >= 0; --y) + if(!(list_full & (1u << y))) + DrawRow(target--, [&](unsigned x) { return this->Area[y][x]; }); + // Clear the top lines + for(auto n=n_full; n-- > 0; ) + DrawRow(target--, [](unsigned) { return Empty; }); + } + ccrFinish(false); + } + else + { + // Cascade non-empty lines + int target = Height-2, y = Height-2; + n_full = 0; + for(int miny = std::max(0,FirstY); y >= miny; --y) + if(TestFully(y, true)) + { + ++n_full; + miny = 0; + } + else + { + if(target != y) + memcpy(&Area[target], &Area[y], sizeof(Area[0][0])*Width); + --target; + } + // Clear the top lines + for(auto n=n_full; n-- > 0; ) + DrawRow(target--, [](unsigned) { return Empty; }); + return false; + } + } + }; + + template<bool DoReturns = true> + class TetrisAIengine: TetrisArea<false> + { + public://protected: + typedef std::pair<int/*score*/, int/*prio*/> scoring; + struct position + { + // 1. Rotate to this position + int rot; + // 2. Move to this column + int x; + // 3. Drop to ground + // 4. Rotate to this position + int rot2; + // 5. Move maximally to this direction + int x2; + // 6. Drop to ground again + }; + + std::vector<position> positions1, positions2; + + struct Recursion + { + // Copy of the field before this recursion level + decltype(Area) bkup; + // Currently testing position + unsigned pos_no; + // Best outcome so far from this recursion level + scoring best_score, base_score; + position best_pos; + Recursion() : best_pos( {1,5, 1,0} ) { } + } data[8]; + unsigned ply, ply_limit; + + bool restart; // Begin a new set of calculations + bool confident; // false = Reset best-score + bool resting; // true = No calculations to do + bool doubting; + struct { ccrVars; } aiscope; + + public: + void AI_Signal(int signal) + { + // any = piece moved; 0 = new piece, 2 = at ground + switch(signal) + { + case 0: // new piece + // do full scan and reset score + confident = false; + restart = true; + resting = false; + doubting = false; + break; + case 1: // piece moved + // keep scanning (low prio), no resets + resting = false; + break; + case 2: // now at ground + // do full scan without resetting score + resting = false; + restart = true; + doubting = true; + break; + } + } + int AI_Run(const decltype(Area)& in_area, const Piece* seq) + { + std::memcpy(Area, in_area, sizeof(Area)); + + // For AI, we use Pierre Dellacherie's algorithm, + // but extended for arbitrary ply lookahead. + enum { + landingHeightPenalty = -1, erodedPieceCellMetricFactor = 2, + rowTransitionPenalty = -2, columnTransitionPenalty = -2, + buriedHolePenalty = -8, wellPenalty = -2/*, + occlusionPenalty = 0*/ }; + + ccrBegin(aiscope); + + positions1.clear(); + positions2.clear(); + for(int x=-1; x<Width; ++x) + for(unsigned rot=0; rot<4; ++rot) + for(unsigned rot2=0; rot2<4; ++rot2) + for(int x2=-1; x2<=1; ++x2) + { + positions1.push_back( std::move<position> ( {int(rot),x,int(rot2),x2} ) ); + if(rot2 == rot && x2 == 0) + positions2.push_back( std::move<position> ( {int(rot),x,int(rot2),x2} ) ); + } + + confident = false; + doubting = false; + Restart: + restart = false; + resting = false; + + /*std::random_shuffle(positions1.begin(), positions1.end());*/ + std::random_shuffle(positions2.begin(), positions2.end()); + + ply = 0; + + Recursion: + // Take current board as testing platform + std::memcpy(data[ply].bkup, Area, sizeof(Area)); + if(!confident || ply > 0) + { + data[ply].best_score = {-999999,0}; + if(ply == 0) + { + //int heap_room = 0; + //while(TestFully(heap_room,false)) ++heap_room; + ply_limit = 2; + } + } + for(;;) + { + data[ply].pos_no = 0; + do { + if(DoReturns) + { + ccrReturn(0); + if(restart) goto Restart; + } + if(ply > 0) + { + // Game might have changed the the board contents. + std::memcpy(data[0].bkup, in_area, sizeof(Area)); + + // Now go on and test with the current testing platform + std::memcpy(Area, data[ply].bkup, sizeof(Area)); + } + + // Fix the piece in place, cascade rows, and analyze the result. + { const position& goal = (/*ply==0&&!doubting ? positions1 :*/ positions2) + [ data[ply].pos_no ]; + Piece n = seq[ply]; + n.x = goal.x; + n.r = goal.rot; + if(ply) n.y = 0; + + // If we are analyzing a mid-fall maneuver, verify whether + // the piece can be actually maneuvered into this position. + //if(ply==0 && n.y >= 0) + for(Piece q,t=*seq; t.x!=n.x && t.r!=n.r; ) + if( (t.r == n.r || (q=t, ++t.r, CollidePiece(t)&&(t=q,true))) + && (t.x <= n.x || (q=t, --t.x, CollidePiece(t)&&(t=q,true))) + && (t.x >= n.x || (q=t, ++t.x, CollidePiece(t)&&(t=q,true)))) + goto next_move; // no method of maneuvering. + + // Land the piece if it's not already landed + do ++n.y; while(!CollidePiece(n)); --n.y; + if(n.y < 0 || CollidePiece(n)) goto next_move; // cannot place piece? + + /* + // Rotate to ground-rotation + if(n.r != goal.rot2 || goal.x2 != 0) + { + while(n.r != goal.rot2) + { + ++n.r; + if(CollidePiece(n)) goto next_move; + } + if(goal.x2 != 0) + { + do n.x += goal.x2; while(!CollidePiece(n)); + n.x -= goal.x2; + } + + do ++n.y; while(!CollidePiece(n)); --n.y; + if(n.y < 0 || CollidePiece(n)) goto next_move; // cannot place piece? + } + */ + + DrawPiece(n, Occ); // place piece + + // Find out the extents of this piece, and how many + // cells of the piece contribute into full (completed) rows. + char full[4]={-1,-1,-1,-1}; + int miny=n.y+9, maxy=n.y-9, minx=n.x+9, maxx=n.x-9, num_eroded=0; + n>[&](int x,int y) -> bool + { if(x < minx) {minx = x;} if(x > maxx) {maxx = x;} + if(y < miny) {miny = y;} if(y > maxy) {maxy = y;} + if(full[y - n.y] < 0) full[y - n.y] = this->TestFully(y,true); + num_eroded += full[y - n.y]; + return false; }; + + CascadeEmpty(n.y); + + // Analyze the board and assign penalties + int penalties = 0; + for(int y=0; y<Height-1; ++y) + for(int q=1,r, x=1; x<Width; ++x, q=r) + if(q != (r = Occupied(x,y))) + penalties += rowTransitionPenalty; + for(int x=1; x<Width-1; ++x) + for(int ceil=0/*,heap=0*/,q=0,r, y=0; y<Height; ++y,q=r) + { + if(q != (r = Occupied(x,y))) + { + penalties += columnTransitionPenalty; + /*if(!r) { penalties += heap * occlusionPenalty; heap = 0; }*/ + } + if(r) { ceil=1; /*++heap;*/ continue; } + if(ceil) penalties += buriedHolePenalty; + if(Occupied(x-1,y) && Occupied(x+1,y)) + for(int y2=y; y2<Height-1 && !Occupied(x,y2); ++y2) + penalties += wellPenalty; + } + + data[ply].base_score = { + // score + (erodedPieceCellMetricFactor * int(n_full) * num_eroded + + penalties + + landingHeightPenalty * ((Height-1) * 2 - (miny+maxy))) * 16, + // tie-breaker + 50 * std::abs(Width-2-minx-maxx) + + (minx+maxx < Width-2 ? 10 : 0) - n.r + - 400*(goal.rot != goal.rot2) + - 800*(goal.x2 != 0) + }; + } + if(ply+1 < ply_limit) + { ++ply; goto Recursion; + Unrecursion: --ply; } + + /*fprintf(stdout, "ply %u: [%u]%u,%u gets %d,%d\n", + ply, + data[ply].pos_no, + positions[data[ply].pos_no].x, + positions[data[ply].pos_no].rot, + data[ply].base_score.first, + data[ply].base_score.second);*/ + + if(data[ply].best_score < data[ply].base_score) + { + data[ply].best_score = data[ply].base_score; + data[ply].best_pos = (/*ply==0&&!doubting ? positions1 :*/ positions2) [ data[ply].pos_no ]; + } + next_move:; + } while(++data[ply].pos_no < (/*ply==0&&!doubting ? positions1 :*/ positions2).size()); + + if(ply > 0) + { + int v = data[ply].best_score.first; + v /= 2; + //if(ply_limit == 4) v /= 2; else v *= 2; + data[ply-1].base_score.first += v;// >> (2-ply); + goto Unrecursion; + /* + parent += child / 2 : + Game 0x7ffff0d94ce0 over with score=91384,lines=92 + Game 0x7ffff0d96a40 over with score=153256,lines=114 + parent += child : + Game 0x7fff4a4eb8a0 over with score=83250,lines=86 + Game 0x7fff4a4ed600 over with score=295362,lines=166 + parent += child * 2 : + Game 0x7fff000a2e00 over with score=182306,lines=131 + Game 0x7fff000a10a0 over with score=383968,lines=193 + parent += child * 4 : + Game 0x7fff267867b0 over with score=62536,lines=75 + Game 0x7fff26788510 over with score=156352,lines=114 + */ + } + // all scanned; unless piece placement changes we're as good as we can be. + confident = true; + resting = true; + doubting = false; + while(resting) ccrReturn(0); + if(restart) goto Restart; + } // infinite refining loop + ccrFinish(0); + } + }; + + class Tetris: protected TetrisArea<true> + { + public: + Tetris(unsigned rx) : TetrisArea(rx), seq(),hiscore(0),hudtimer(0) {} + virtual ~Tetris() { } + + protected: + // These variables should be local to GameLoop(), + // but because of coroutines, they must be stored + // in a persistent wrapper instead. Such persistent + // wrapper is provided by the game object itself. + Piece seq[4]; + unsigned hiscore, score, lines, combo, pieces; + unsigned long hudtimer; + bool escaped, dropping, ticked, kicked, spinned, atground, first; + + struct { ccrVars; } loopscope; + public: + unsigned incoming; + + int GameLoop() + { + Piece &cur = *seq; + ccrBegin(loopscope); + + // Initialize area + for(auto y=Height; y-- > 0; ) + for(auto x=Width; x-- > 0; ) + DrawBlock(x,y, (x>0&&x<Width-1&&y<Height-1) ? Empty : Border); + + score = lines = combo = incoming = pieces = 0; + MakeNext(); + MakeNext(); + first=true; + + for(escaped = false; !escaped; ) // Main loop + { + // Generate new piece + MakeNext(); + /*if(first) // Use if making 4 pieces + { + first=false; + ccrReturn(0); + MakeNext(); + }*/ + + dropping = false; + atground = false; + re_collide: + timer = Timer; + AI_Signal(0); // signal changed board configuration + + // Gameover if cannot spawn piece + if(CollidePiece(cur)) + { + break; + } + + ccrReturn(0); + + while(!escaped) + { + atground = CollidePiece(cur * [](Piece&p){++p.y;}); + if(atground) dropping = false; + // If we're about to hit the floor, give the AI a chance for sliding. + AI_Signal(atground ? 2 : 1); + + DrawPiece(cur, cur.color); + + // Wait for input + for(ticked=false; ; ) + { + AI_Run(); + HUD_Run(); + ccrReturn(0); + + if(incoming) + { + // Receive some lines of garbage from opponent + DrawPiece(cur, Empty); + for(int threshold=Height-1-incoming, y=0; y<Height-1; ++y) + { + unsigned mask = 0x1EF7BDEF >> (rand()%10); + DrawRow(y, [&](unsigned x) { return + y < threshold + ? Area[y+incoming][x] + : (mask & (1<<x)) ? Garbage : Empty; }); + } + // The new rows may push the piece up a bit. Allow that. + for(; incoming-- > 0 && CollidePiece(cur); --cur.y) {} + incoming = 0; + goto re_collide; + } + + ticked = Timer >= timer + std::max(atground?40:10, int( ((17-Level())*8)) ); + if(ticked || MyKbHit() || dropping) break; + } + + Piece n = cur; + if(MyKbHit()) dropping = false; + + switch(ticked ? 's' : (MyKbHit() ? MyGetCh() : (dropping ? 's' : 0))) + { + case 'H'<<8: case 'w': ++n.r; /*Sound(120, 1);*/ break; + case 'P'<<8: case 's': ++n.y; break; + case 'K'<<8: case 'a': --n.x; /*Sound(120, 1);*/ break; + case 'M'<<8: case 'd': ++n.x; /*Sound(120, 1);*/ break; + case 'q': case '\033': /*escaped = true;*/ break; + case ' ': dropping = true; /*fallthrough*/ + default: continue; + } + if(n.x != cur.x) kicked = false; + + if(CollidePiece(n)) + { + if(n.y == cur.y+1) break; // fix piece if collide against ground + // If tried rotating, and was unsuccessful, try wall kicks + if(n.r != cur.r && !CollidePiece(n*[](Piece&p){++p.x;})) { kicked = true; ++n.x; } else + if(n.r != cur.r && !CollidePiece(n*[](Piece&p){--p.x;})) { kicked = true; --n.x; } else + continue; // no move + } + DrawPiece(cur, Empty); + if(n.y > cur.y) timer = Timer; // Reset autodrop timer + cur = n; + } + + // If the piece cannot be moved sideways or up from its final position, + // determine that it must have been spin-fixed into its place. + // It is a bonus-worthy accomplishment if it ends up clearing lines. + spinned = CollidePiece(cur*[](Piece&p){--p.y;}) + && CollidePiece(cur*[](Piece&p){--p.x;}) + && CollidePiece(cur*[](Piece&p){++p.x;}); + DrawPiece(cur, cur.color|Occ); + Sound(50, 30); + + while(CascadeEmpty(cur.y)) ccrReturn(0); + if(n_full > 1) ccrReturn(n_full-1); // Send these rows to opponent + + pieces += 1; + lines += n_full; + static const unsigned clr[] = {0,1,3,5,8, 13,21,34,45}; + int multiplier = Level(), clears = clr[n_full]; + int bonus = (clears * 100 + (cur.y*50/Height)); + int extra = 0; + if(spinned) extra = ((clears+1) * ((kicked ? 3 : 4)/2) - clears) * 100; + combo = n_full ? combo + n_full : 0; + int comboscore = combo > n_full ? combo*50*multiplier : 0; + bonus *= multiplier; + extra *= multiplier; + score += bonus + extra + comboscore; + HUD_Add(bonus, extra, comboscore); + //if(n_full) std::fprintf(stdout, "Game %p += %u lines -> score=%u,lines=%u\n", this, n_full, score,lines); + } + //std::fprintf(stdout, "Game %p over with score=%u,lines=%u\n", this, score,lines); + //over_lines += lines; + + if(score > hiscore) hiscore = score; + HudPrint(7, 4, "", "%-7u", hiscore); + + ccrFinish(-1); + } + + protected: + int Level() const { return 1 + lines/10; } + + void MakeNext() + { + const int which = 2; // Index within seq[] to populate + static const Piece b[] = + { + { { { 0x04040404,0x00000F00,0x04040404,0x00000F00 } }, 0,0, 0xBDB,0 }, // I + { { { 0x0000080E,0x000C0808,0x00000E02,0x00020206 } }, 0,0, 0x3DB,0 }, // J + { { { 0x0000020E,0x0008080C,0x00000E08,0x00060202 } }, 0,0, 0x6DB,0 }, // L + { { { 0x00000606,0x00000606,0x00000606,0x00000606 } }, 0,0, 0xEDB,0 }, // O + { { { 0x00080C04,0x0000060C,0x00080C04,0x0000060C } }, 0,0, 0xADB,0 }, // S + { { { 0x00000E04,0x00040C04,0x00040E00,0x00040604 } }, 0,0, 0x5DB,0 }, // T + { { { 0x00020604,0x00000C06,0x00020604,0x00000C06 } }, 0,0, 0x4DB,0 }, // Z + // Add some pentaminos to create a challenge worth the AI: + { { { 0x00020702,0x00020702,0x00020702,0x00020702 } }, 0,0, 0x2DB,0 }, // + + { { { 0x000E0404,0x00020E02,0x0004040E,0x00080E08 } }, 0,0, 0x9DB,0 }, // T5 + { { { 0x00000A0E,0x000C080C,0x00000E0A,0x00060206 } }, 0,0, 0x3DB,0 }, // C + { { { 0x00060604,0x000E0600,0x02060600,0x00060700 } }, 0,0, 0x7DB,0 }, // P + { { { 0x00060602,0x00070600,0x04060600,0x00060E00 } }, 0,0, 0xFDB,0 }, // Q + { { { 0x04040404,0x00000F00,0x04040404,0x00000F00 } }, 0,0, 0xBDB,0 }, // I + { { { 0x00040702,0x00030602,0x00020701,0x00020306 } }, 0,0, 0xDDB,0 }, // R + { { { 0x00010702,0x00020603,0x00020704,0x00060302 } }, 0,0, 0x8DB,0 }, // F + // I is included twice, otherwise it's just a bit too unlikely. + }; + int c = Empty; + auto fx = [this]() { seq[0].x=1; seq[0].y=-1; + seq[1].x=Width+1; seq[1].y=SHeight-8; + seq[2].x=Width+5; seq[2].y=SHeight-8; + /*seq[3].x=Width+9; seq[3].y=SHeight-8; + seq[4].x=Width+1; seq[4].y=SHeight-4; + seq[5].x=Width+5; seq[5].y=SHeight-4; + seq[6].x=Width+9; seq[6].y=SHeight-4;*/ + }; + auto db = [&](int x,int y) + { + PutCell(x+RenderX, y, c); + return false; + }; + fx(); + seq[1]>db; seq[0] = seq[1]; + seq[2]>db; seq[1] = seq[2]; + /*seq[3]>db; seq[2] = seq[3]; + seq[4]>db; seq[3] = seq[4]; + seq[5]>db; seq[4] = seq[5]; + seq[6]>db; seq[5] = seq[6];*/ + fx(); + const unsigned npieces = sizeof(b) / sizeof(*b); + unsigned rnd = (unsigned)((std::rand()/double(RAND_MAX)) * (4 * npieces)); + #ifndef EASY + /*if(pieces > 3) + { + int heap_room = 0; + while(TestFully(heap_room,false)) ++heap_room; + bool cheat_good = heap_room <= (7 + lines/20); + bool cheat_evil = heap_room >= 18; + if(heap_room >= 16 && (pieces % 5) == 0) cheat_good = false; + if( (pieces % 11) == 0) cheat_good = true; + if(cheat_good) cheat_evil = false; + if(cheat_good || cheat_evil) + { + // Don't tell anyone, but in desperate situations, + // we let AI judge what's best for upcoming pieces, + // in order to prolong the game! + // So, the AI cheats, but it is an equal benefactor. + // EXCEPTION: if there is an abundance of space, + // bring out the _worst_ possible pieces! + TetrisAIengine<>::scoring best_score; + unsigned best_choice = ~0u; + for(unsigned test=0; test<npieces; ++test) + { + unsigned choice = (test + rnd) % npieces; + if(choice == 0) continue; // Ignore the duplicate I (saves time) + if(cheat_evil && choice == 7) continue; // Don't give +, it's too evil + + seq[which] = b[ choice ]; + seq[which].r = 0; + + TetrisAIengine<false> chooser; + chooser.AI_Signal(0); + chooser.AI_Run(Area, seq); + auto& s = chooser.data[0].best_score; + if(best_choice == ~0u + || (cheat_evil ? s < best_score : s > best_score) + ) + { best_score = s; best_choice = choice; } + } + rnd = best_choice * 4 + (rnd % 4); + } + }*/ + #endif + seq[which] = b[rnd / 4]; + seq[which].r = rnd % 4; + fx(); + c=seq[1].color; seq[1]>db; + c=(seq[2].color&0xF00) + 176; seq[2]>db; + /*c=(seq[3].color&0xF00) + 176; seq[3]>db; + c=(seq[4].color&0xF00) + 176; seq[4]>db; + c=(seq[5].color&0xF00) + 176; seq[5]>db; + c=(seq[6].color&0xF00) + 176; seq[6]>db;*/ + HudPrint(0, SHeight-9, "NEXT:","",0); + HudPrint(12, 0, "SCORE:", "%-7u", score); + HudPrint(12, 2, "LINES:", "%-5u", lines); + HudPrint(12, 4, "LEVEL:", "%-3u", Level()); + } + + void HudPrint(int c, int y,const char*a,const char*b,int v=0) const + { + char Buf[64]; + snprintf(Buf, sizeof Buf, b, v); + ScreenPutString(a, 15, RenderX+Width+2, y); + ScreenPutString(Buf, c, RenderX+Width+2, y+1); + } + + void HUD_Run() + { + if(!hudtimer || Timer < hudtimer) return; + HUD_Add(0,0,0); + hudtimer = 0; + } + void HUD_Add(int bonus, int extra, int combo) + { + hudtimer = Timer + 180; + static const char blank[] = " "; + HudPrint(10, 6,bonus?blank :blank,bonus?"%+-6d":blank, bonus); + HudPrint(10, 8,combo?"Combo":blank,combo?"%+-6d":blank, combo); + HudPrint(13, 10,extra?"Skill":blank,extra?"%+-6d":blank, extra); + } + + virtual void AI_Signal(int) { } + virtual int AI_Run() { return 0; } + virtual int MyKbHit() = 0; + virtual int MyGetCh() = 0; + public: + // Return -1 = don't want sleep, +1 = want sleep, 0 = don't mind + virtual char DelayOpinion() const { return 0; }//dropping ? -1 : 0; } + }; + + class TetrisHuman: public Tetris + { + public: + TetrisHuman(unsigned rx) : Tetris(rx) { } + protected: + virtual int MyKbHit() { return kbhit(); } + virtual int MyGetCh() { int c; return (c = getch()) ? c : (getch() << 8); } + }; + + class TetrisAI: public Tetris, TetrisAIengine<true> + { + protected: + virtual void AI_Signal(int s) { TetrisAIengine::AI_Signal(s); } + virtual int AI_Run() + { + #ifdef __DJGPP__ + char buf1[16]/*, buf2[16], buf3[16]*/; + sprintf(buf1, "COM%u%c%c%c%c", ply_limit, + resting ? 'r' : '_', + confident ? 'C' : '_', + doubting ? 'D' : '_', + atground ? 'G' : '_' + ); + ScreenPutString(buf1, 0x70, Tetris::RenderX+Width, 0); + /* + sprintf(buf2, "%-8d", data[0].best_score.first); + sprintf(buf3, "%2d,%d", data[0].best_pos.x, + data[0].best_pos.rot); + ScreenPutString(buf2, 0x08, Tetris::RenderX+Width, 1); + ScreenPutString(buf3, 0x08, Tetris::RenderX+Width, 4); + */ + #endif + return TetrisAIengine::AI_Run(Tetris::Area, seq); + } + virtual int MyKbHit() + { + return PendingAIinput ? 1 : (PendingAIinput = GenerateAIinput()) != 0; + } + virtual int MyGetCh() + { + int r = PendingAIinput; + return r ? (PendingAIinput=0), r : GenerateAIinput(); + } + char d(char c, int maxdelay) + { + if(Timer >= intimer+maxdelay) { intimer=Timer; return c; } + return 0; + } + int GenerateAIinput() + { + /*if(TetrisAIengine::atground) + { + if(seq->r != data[0].best_pos.rot2) return d('w',1); + if(data[0].best_pos.x2 < 0) return d('a', 1); + if(data[0].best_pos.x2 > 0) return d('d', 1); + } + else*/ + { + if(seq->r != data[0].best_pos.rot) return d('w',1); + if(seq->y >= 0 && seq->x > data[0].best_pos.x) return d('a', 2); + if(seq->y >= 0 && seq->x < data[0].best_pos.x) return d('d', 2); + } + if(doubting || !confident) return 0; + return d('s',3); + } + + int PendingAIinput, delay; + unsigned long intimer; + public: + virtual char DelayOpinion() const + { if(doubting || restart || !confident) return -1; + return Tetris::DelayOpinion(); } + + TetrisAI(unsigned rx) : Tetris(rx), PendingAIinput(0), delay(0), intimer(0) {} + }; + #undef Timer +} diff --git a/utils/gen_adldata/file_formats/load_jv.h b/utils/gen_adldata/file_formats/load_jv.h index 125356a..b79832f 100644 --- a/utils/gen_adldata/file_formats/load_jv.h +++ b/utils/gen_adldata/file_formats/load_jv.h @@ -66,7 +66,7 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix) tmp[1].data[9] = data[offset + 9 + 11]; tmp[1].data[10] = data[offset + 7 + 11] & 0x0F;//~0x30; tmp[1].finetune = 0; - tmp[1].diff = data[offset]; + tmp[1].diff = (data[offset] != 0); struct ins tmp2; tmp2.notenum = data[offset + 1]; diff --git a/utils/gen_adldata/ini/ini_processing.cpp b/utils/gen_adldata/ini/ini_processing.cpp index 4ef43fc..6e53ba5 100644 --- a/utils/gen_adldata/ini/ini_processing.cpp +++ b/utils/gen_adldata/ini/ini_processing.cpp @@ -416,9 +416,9 @@ bool IniProcessing::parseFile(const char *filename) int newSize = MultiByteToWideChar(CP_UTF8, 0, filename, - dest.size(), + (int)dest.size(), (wchar_t *)dest.c_str(), - dest.size()); + (int)dest.size()); dest.resize(newSize); FILE *cFile = _wfopen(dest.c_str(), L"rb"); #else diff --git a/utils/gen_adldata/measurer.cpp b/utils/gen_adldata/measurer.cpp index 3116045..4789b43 100644 --- a/utils/gen_adldata/measurer.cpp +++ b/utils/gen_adldata/measurer.cpp @@ -220,8 +220,8 @@ DurationInfo MeasureDurations(const ins &in) result.peak_amplitude_time = peak_amplitude_time; result.peak_amplitude_value = peak_amplitude_value; result.begin_amplitude = begin_amplitude; - result.quarter_amplitude_time = quarter_amplitude_time; - result.keyoff_out_time = keyoff_out_time; + result.quarter_amplitude_time = (double)quarter_amplitude_time; + result.keyoff_out_time = (double)keyoff_out_time; result.ms_sound_kon = (long)(quarter_amplitude_time * 1000.0 / interval); result.ms_sound_koff = (long)(keyoff_out_time * 1000.0 / interval); diff --git a/utils/gen_adldata/progs_cache.h b/utils/gen_adldata/progs_cache.h index aa29c8a..7b4cd39 100644 --- a/utils/gen_adldata/progs_cache.h +++ b/utils/gen_adldata/progs_cache.h @@ -6,6 +6,7 @@ #include <utility> #include <memory> #include <cstring> +#include <algorithm> #include <cstdint> #include <string> #include <vector> |