생성일: 2019년 12월 20일
수정일: 2023년 08월 15일

4clojure - Analyze a Tic-Tac-Toe Board (73)

  1. 문제
  2. 풀이
    1. 풀이 과정

문제

(= nil (__ [[:e :e :e]
            [:e :e :e]
            [:e :e :e]]))

(= :x (__ [[:x :e :o]
           [:x :e :e]
           [:x :e :o]]))

(= :o (__ [[:e :x :e]
           [:o :o :o]
           [:x :e :x]]))

(= nil (__ [[:x :e :o]
            [:x :x :e]
            [:o :x :o]]))

(= :x (__ [[:x :e :e]
           [:o :x :e]
           [:o :e :x]]))

(= :o (__ [[:x :e :o]
           [:x :o :e]
           [:o :e :x]]))

(= nil (__ [[:x :o :x]
            [:x :o :x]
            [:o :x :o]]))

풀이

(fn [coll]
	(let [a (flatten (partition 1 4 (flatten coll)))
		  r (flatten (partition 1 4 (flatten (map #(reverse %) coll))))
		  b (into (into (into coll (apply map vector coll)) [a]) [r])]
	 (cond (some true? (map #(every? (fn [x] (= x :x)) %) b)) :x
		   (some true? (map #(every? (fn [x] (= x :o)) %) b)) :o
		 	:else nil)))

풀이 과정

sort 해서 하면 되겠거니 했었는데 일직선이 되지 않는 값들에 대해서가 문제가 된다. 그래서 좀 더 생각해야 할 것 같다.

틱택토 게임은 기본적으로 빙고와 같다고 생각 한다.

일직선에 3개는 일단 해결이 될 것 같은데 밑으로는 어떻게 검증을 해야 하나 생각을 했을 때 밑으로 collection을 만들어 주면 될 것 같다는 생각이 들었다.

(apply map vector [[:x :e :o] [:x :e :e] [:x :e :o]])
;; ([:x :x :x] [:e :e :e] [:o :e :o])

대각선도 위와 같은 형태로 만들어서 검증을 할 수 있는 로직을 짜면 해결이 될 것 같다.

group-by로 검증 로직을 할 수 있을 것 같은데 좀 더 고민이 필요하다.

이 문제를 풀기 위한 데이터 구조가 어떻게 되는지 생각을 해봐야겠다.

내 생각에는 수직, 수평, 대각선 각각의 값들을 가진 3개의 백터 쌍으로 있는 collection을 먼저 만들어 놓고 검증을 하는 것이 낫겠다고 생각한다.

수평, 수직은 어떻게든 될 것 같은데 대각선을 어떻게 추출을 해야할지 좀 고민이 된다. 전통적인 방식으로만 하려고 생각하다보니 그것에는 적합하지 않다는 것을 느끼고 있다. 그래서 더 힘든 것 같다. 생각의 전환이라는 것이 한번 생각이 들면 바꿔서 생각을 한다는 것이 쉬운 일은 아니다.

검증은 every?로 하면 한 collection내의 값이 모두 동일해야 참이라는 것을 알 수 있다.

(every? #(= % :x) [:x :x :x])
;; true

(every? #(= % :x) [:x :x :o])
;; false

우선 수평, 수직에 대한 자료형을 만들어 봤다

(into [[:x :e :o] [:x :e :e] [:x :e :o]] (apply map vector [[:x :e :o] [:x :e :e] [:x :e :o]]))
;; [[:x :e :o] [:x :e :e] [:x :e :o] [:x :x :x] [:e :e :e] [:o :e :o]]

그리고 검사식은 아래와 같다. :x에 대한 every?가 true이고 그 결과를 가지고 true가 1개라도 있으면 true인 결과를 반환한다.

(some true? (map #(every? (fn [x] (= x :x)) %) [[:x :e :o] [:x :e :e] [:x :e :o] [:x :x :x] [:e :e :e] [:o :e :o]]))
;; true		 

대각선을 제외하고 4개 통과하는 프로그램이다.

(fn [coll]
	(let [b (into coll (apply map vector coll))]
	 (cond (some true? (map #(every? (fn [x] (= x :x)) %) b)) :x
		   (some true? (map #(every? (fn [x] (= x :o)) %) b)) :o
		 	:else nil)))
			

대각선을 가지고 오는 방법은 first, second, last인데.. 일단 여기까지만 생각이 난다. 반대 대각선은 last, second, first… 이 조합으로 구성을 어떻게 해야할지 생각하면 될 것 같다.

first,second, last 방법 말고, 값을 풀어서 다시 나누는 방법을 실행 해봤다.

(flatten (partition 1 4 (flatten [[:x :e :e] [:o :x :e] [:o :e :x]])))
;; (:x :x :x)

반대 대각선은 이렇게 하면 될 것 같다.

(flatten (partition 1 4 (flatten (map #(reverse %) [[:x :e :o] [:x :o :e] [:o :e :x]]))))
;; (:o :o :o)
(fn [coll]
	(let [a (flatten (partition 1 4 (flatten coll)))
		  r (flatten (partition 1 4 (flatten (map #(reverse %) coll))))
		  b (into (into (into coll (apply map vector coll)) [a]) [r])]
	 (cond (some true? (map #(every? (fn [x] (= x :x)) %) b)) :x
		   (some true? (map #(every? (fn [x] (= x :o)) %) b)) :o
		 	:else nil)))
			

이번 문제를 풀어보면서 중요한 사실을 알게 된 것이 있는데 어떤 데이터 형식만을 고집하기 보다는 그 형식을 풀어서 문제는 다른 각도로 생각해보는 것도 필요하다는 것을 알게 되었다

아래와 같은 형식으로도 some을 변경이 가능하다.

(fn [coll]
	(let [a (flatten (partition 1 4 (flatten coll)))
		  r (flatten (partition 1 4 (flatten (map #(reverse %) coll))))
		  b (into (into (into coll (apply map vector coll)) [a]) [r])]
	 (some {[:x :x :x] :x [:o :o :o] :o} b)))
Tags: 4clojure Today I Learn