import { findIndex , reduce , remove , update } from '@typed/list' ; import { equals } from '@typed/logic' ; import { fromJust , isNothing } from '@typed/maybe' ; import { Bounds , Direction , Position , Tile , Tiles } from '../../model' ; import { checkCanMergeTile } from './checkCanMergeTiles' ; import { movePositionInDirection } from './movePositionInDirection' ; import { sortTilesForDirection } from './sortTiles' ; const isAtPosition = ( position ) => ( tile ) => equals ( position , tile . position ) ; export function moveTilesInDirection ( bounds , direction , tiles ) { let current = moveTiles ( bounds , direction , tiles ) ; let next = moveTiles ( bounds , direction , current ) ; while ( ! equals ( current , next ) ) { current = next ; next = moveTiles ( bounds , direction , current ) ; } return next ; } export function moveTiles ( bounds , direction , tiles ) { const sortedTiles = sortTilesForDirection ( direction , tiles ) ; return reduce ( moveTile ( bounds , direction ) , sortedTiles , sortedTiles ) ; } export function moveTile ( bounds , direction ) { let merged = 0 ; const move = ( tiles , tile , originalTilesIndex ) : Tiles => { const tileIndex = originalTilesIndex - merged ; const proposedPosition = movePositionInDirection ( bounds , direction , tile . position ) ; const tileAtPositionIndexMaybe = findIndex ( isAtPosition ( proposedPosition ) , tiles ) ; const proposedTile = { ... tile , position : proposedPosition } ; if ( equals ( tile . position , proposedPosition ) ) { return tiles ; } if ( isNothing ( tileAtPositionIndexMaybe ) ) { return move ( update ( tileIndex , proposedTile , tiles ) , proposedTile , originalTilesIndex ) ; } const tileAtPositionIndex = fromJust ( tileAtPositionIndexMaybe ) ; const tileAtPosition = tiles [ tileAtPositionIndex ] ; if ( ! checkCanMergeTile ( tileAtPosition , tile ) ) { return tiles ; } merged ++ ; const mergedTile = { id : proposedTile . id , value : tileAtPosition . value + tile . value , position : proposedPosition , } ; return update ( tileAtPositionIndex , mergedTile , remove ( tileIndex , 1 , tiles ) ) ; } ; return move ; }