;; ===========
;; EXPLANATION
;; ===========

;; The coordinate model defines, how indices to the bits of a bit board are mapped to coordinates
;; and vice versa. It maps the lowest index to the lowest coordinates, which are the coordinates
;; with lowerst row and column ids. How those row and column ids are interpreted and translated into
;; game coordinates will depend on the game specific implementation.

;; For example: A chess board as typically displayed, will have the square A1 in the lower left
;; corner. However, this might not be mapped to the lowest index of the bits of the bit
;; board. Instead a possible mapping could map A8 to the lowest index and H1 to the highest index,
;; which could make sense from the perspective of screen display, where usually the top left corner
;; is assigned the coordinates (0,0).

;; It would then be a good idea to write a translation function, which takes care of that mapping.

(define-module (coords-model)
  #:export
  (get-row-part
   get-col-part
   make-coords
   index->coords
   coords->index))


(define (get-row-part coords)
  (car coords))

(define (get-col-part coords)
  (cdr coords))

(define (make-coords row-idx col-idx)
  (cons row-idx col-idx))

(define (index->coords index row-count col-count)
  (cond
   [(>= index (* row-count col-count))
    (throw 'index-error
           (simple-format #f "expected index < ~a" (* row-count col-count))
           index row-count col-count)]
   [(not (exact-integer? index))
    (throw 'index-error "expected index to be exact integer" index)]
   [(not (>= index 0))
    (throw 'index-error "expected index to be greater than 0 or equal to 0" index)]
   [(let* ([row-coord (floor (/ index col-count))]
           [col-coord (- index (* row-coord col-count))])
      (make-coords row-coord col-coord))]))

(define (coords->index coords row-count col-count)
  (let ([row-coord (get-row-part coords)]
        [col-coord (get-col-part coords)])
    (cond
     [(or (< row-coord 0)
          (< col-coord 0)
          (>= row-coord row-count)
          (>= col-coord col-count))
      (throw 'index-error "index out of bounds" row-coord col-coord row-count col-count)]
     [else (+ (* row-coord col-count) col-coord)])))
