diff --git a/xwords4/common/model.c b/xwords4/common/model.c index 2fb803b46..ef5c17c4b 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -1,6 +1,6 @@ /* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* - * Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights + * Copyright 2000-2015 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -342,6 +342,56 @@ model_hashMatches( const ModelCtxt* model, const XP_U32 hash ) return matches; } +XP_Bool +model_revertToHash( ModelCtxt* model, const XP_U32 hash, PoolContext* pool ) +{ + XP_U16 nPopped = 0; + StackCtxt* stack = model->vol.stack; + const XP_U16 nEntries = stack_getNEntries( stack ); + StackEntry entries[nEntries]; +#ifdef DEBUG + XP_U32 hashes[nEntries]; +#endif + XP_S16 foundAt = -1; + + for ( XP_U16 ii = 0; ii < nEntries; ++ii ) { + XP_U32 thisHash = +#ifdef DEBUG + hashes[ii] = +#endif + stack_getHash( stack ); + if ( hash == thisHash ) { + foundAt = ii; + break; + } + if ( ! stack_popEntry( stack, &entries[ii] ) ) { + break; + } + ++nPopped; + } + + for ( XP_S16 ii = nPopped - 1; ii >= 0; --ii ) { + stack_redo( stack, &entries[ii] ); + /* Assert not needed for long */ + XP_ASSERT( hashes[ii] = stack_getHash( stack ) ); + } + + XP_Bool found = -1 != foundAt; + if ( found ) { + XP_LOGF( "%s: undoing %d turns to match hash %X", __func__, + foundAt, hash ); +#ifdef DEBUG + XP_Bool success = +#endif + model_undoLatestMoves( model, pool, foundAt, NULL, NULL ); + XP_ASSERT( success ); + /* Assert not needed for long */ + XP_ASSERT( hash == stack_getHash( model->vol.stack ) ); + } + + return found; +} + #ifdef STREAM_VERS_BIGBOARD void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses ) diff --git a/xwords4/common/model.h b/xwords4/common/model.h index c58f95ded..f9e688494 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -124,6 +124,9 @@ void model_setSize( ModelCtxt* model, XP_U16 boardSize ); void model_destroy( ModelCtxt* model ); XP_U32 model_getHash( const ModelCtxt* model, XP_U16 version ); XP_Bool model_hashMatches( const ModelCtxt* model, XP_U32 hash ); +XP_Bool model_revertToHash( ModelCtxt* model, const XP_U32 hash, + PoolContext* pool ); + void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers ); XP_U16 model_getNPlayers( const ModelCtxt* model ); diff --git a/xwords4/common/server.c b/xwords4/common/server.c index 7422e2e88..e9f6bea8d 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -2086,11 +2086,17 @@ readMoveInfo( ServerCtxt* server, XWStreamCtxt* stream, #ifdef STREAM_VERS_BIGBOARD if ( STREAM_VERS_BIGBOARD <= stream_getVersion( stream ) ) { XP_U32 hashReceived = stream_getU32( stream ); - success = model_hashMatches( server->vol.model, hashReceived ); + success = model_hashMatches( server->vol.model, hashReceived ) + || model_revertToHash( server->vol.model, hashReceived, + server->pool ); // XP_ASSERT( success ); /* I need to understand when this can fail */ - if ( !success ) { - XP_LOGF( "%s: hash mismatch",__func__); +#ifdef DEBUG_HASHING + if ( success ) { + XP_LOGF( "%s: hash match: %X",__func__, hashReceived ); + } else { + XP_LOGF( "%s: hash mismatch: %X not found",__func__, hashReceived ); } +#endif } #endif if ( success ) {